与 Numpy 不同,Pandas 似乎不喜欢内存大步

Posted

技术标签:

【中文标题】与 Numpy 不同,Pandas 似乎不喜欢内存大步【英文标题】:Unlike Numpy, Pandas doesn't seem to like memory strides 【发布时间】:2015-06-22 18:45:27 【问题描述】:

Pandas 似乎缺少 R 风格的矩阵级滚动窗口函数 (rollapply(..., by.column = FALSE)),仅提供基于向量的版本。因此,我尝试关注this question,它与可以复制的示例完美配合,但即使使用(看似相同的)底层 Numpy 数组,它也不适用于 pandasDataFrames。

人工问题复制:

import numpy as np
import pandas as pd
from numpy.lib.stride_tricks import as_strided

test = [[x * y for x in range(1, 10)] for y in [10**z for z in range(5)]]
mm = np.array(test, dtype = np.int64)
pp = pd.DataFrame(test).values

mmpp 看起来一样:

numpy 直接派生的矩阵给了我我想要的完美:

as_strided(mm, (mm.shape[0] - 3 + 1, 3, mm.shape[1]), (mm.shape[1] * 8, mm.shape[1] * 8, 8))

也就是说,它在 3d 矩阵中为我提供了 3 步,每步 3 行,允许我在一次向下移动一行的子矩阵上执行计算。

但熊猫派生版本(与mm 相同的调用被pp 替换):

 as_strided(pp, (pp.shape[0] - 3 + 1, 3, pp.shape[1]), (pp.shape[1] * 8, pp.shape[1] * 8, 8))

很奇怪,就像它以某种方式被转置了一样。这与列/行主要订单有关吗?

我需要在 Pandas 中做矩阵滑动窗口,这似乎是我最好的选择,特别是因为它真的很快。这里发生了什么?如何让底层 Pandas 数组表现得像 Numpy?

【问题讨论】:

【参考方案1】:

.values 似乎以 Fortran 顺序返回基础数据(正如您所推测的那样):

>>> mm.flags # NumPy array
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  ...

>>> pp.flags # array from DataFrame
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  ...

这让 as_strided 感到困惑,它期望数据在内存中按 C 顺序排列。

要解决问题,您可以按 C 顺序复制数据并使用与您的问题相同的步幅:

pp = pp.copy('C') 

或者,如果您想避免复制大量数据,请调整步幅以确认数据的列顺序布局:

as_strided(pp, (pp.shape[0] - 3 + 1, 3, pp.shape[1]), (8, 8, pp.shape[0]*8))

【讨论】:

【参考方案2】:

这与列/行主要订单有关吗?

是的,请参阅 mm.stridespp.strides

如何让底层 Pandas 数组表现得像 Numpy?

Numpy 数组 mm 是“C-contiguous”,这就是步幅技巧起作用的原因。如果要在 DataFrame 底层的数组上调用完全相同的代码,可以先使用np.ascontiguousarray。或者,在考虑数组stridesitemsize 的同时编写数据窗口可能会更好。

【讨论】:

以上是关于与 Numpy 不同,Pandas 似乎不喜欢内存大步的主要内容,如果未能解决你的问题,请参考以下文章

Pandas

pandas1.0.5和numpy1.17.4版本兼容吗?

pandas.DataFrame.describe() 与 numpy.percentile() NaN 处理

pandas.DataFrame.describe() 与 numpy.percentile() NaN 处理

为啥标签与 pandas、itertools 和 numpy 索引不一致?

为啥 Numpy 和 Pandas 数组比源数据消耗更多内存? [关闭]