与 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 数组,它也不适用于 pandasDataFrame
s。
人工问题复制:
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
mm
和 pp
看起来一样:
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.strides
和 pp.strides
。
如何让底层 Pandas 数组表现得像 Numpy?
Numpy 数组 mm
是“C-contiguous”,这就是步幅技巧起作用的原因。如果要在 DataFrame 底层的数组上调用完全相同的代码,可以先使用np.ascontiguousarray
。或者,在考虑数组strides
和itemsize
的同时编写数据窗口可能会更好。
【讨论】:
以上是关于与 Numpy 不同,Pandas 似乎不喜欢内存大步的主要内容,如果未能解决你的问题,请参考以下文章
pandas.DataFrame.describe() 与 numpy.percentile() NaN 处理
pandas.DataFrame.describe() 与 numpy.percentile() NaN 处理