滚动统计性能:pandas vs. numpy strides

Posted

技术标签:

【中文标题】滚动统计性能:pandas vs. numpy strides【英文标题】:Rolling statistics performance: pandas vs. numpy strides 【发布时间】:2022-01-18 22:26:28 【问题描述】:

我有兴趣在大型一维 numpy 数组上计算滚动窗口中的统计信息。对于小窗口大小,使用 numpy strides (a la numpy.lib.stride_tricks.sliding_window_view) 比 pandas 滚动窗口实现更快,但对于大窗口大小则相反。

考虑以下几点:

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

data = np.random.randn(10**6)
data_pandas = pd.Series(data)

window = 2
%timeit np.mean(sliding_window_view(data, window), axis=1)
# 19.3 ms ± 255 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit data_pandas.rolling(window).mean()
# 34.3 ms ± 688 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

window = 1000
%timeit np.mean(sliding_window_view(data, window), axis=1)
# 302 ms ± 8.01 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit data_pandas.rolling(window).mean()
# 31.7 ms ± 958 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

result_numpy = np.mean(sliding_window_view(data, window), axis=1)
result_pandas = data_pandas.rolling(window).mean()[window-1:]
np.allclose(result_numpy, result_pandas)
# True

对于较大的窗口大小,pandas 实现实际上更快,而 numpy 实现慢得多

在 pandas 的底层发生了什么,我们如何使用 numpy 获得类似的性能?

与 pandas 相比,我如何在 numpy 的大窗口上获得类似的性能?

【问题讨论】:

这个问题是开放式的,不适用于已发布的答案。您可能会考虑将问题中的最后一条语句改写为“与 Pandas 相比,我如何在 NumPy 的大窗口上获得类似的性能?”,假设有答案。讨论内部实现细节通常超出了 *** 问题的范围。 sliding_window的创建时间基本相同,但最大的时间差异在于取(999999, 2)(999001, 1000)的平均值。这是合理的。查看pd.rolling(...).mean 的文档,我看到一个engine 参数,它可能是cythonnumba。所以pandas 正在做它自己专门的compiled.calculation。 已修复 @scootermefecit 感谢您的建议。 【参考方案1】:

TL;DR:这两个版本使用非常不同的算法

sliding_window_view 技巧可以很好地解决小窗口的滚动平均问题,但这不是一种干净的方法,也不是一种有效的方法,尤其是对于大窗口。实际上,Numpy 计算平均值并记录滚动平均值,因此没有明确的信息表明用户正在大步作弊以计算其他内容。 提供的 Numpy 实现在 O(n * w) 中运行,其中 n 是数组大小,w 是窗口大小。 Pandas 确实具有需要计算滚动平均值的信息,因此它使用了更有效的算法。 Pandas 算法在 O(n) 时间运行。有关它的更多信息,请阅读this post。

这是一个更快的 Numpy 实现:

cumsum = np.cumsum(data)
invSize = 1. / window
(cumsum[window-1:] - np.concatenate([[0], cumsum[:-window]])) * invSize

这是我机器上的性能结果:

Naive Numpy version:  193.2 ms
Pandas version:        33.1 ms
Fast Numpy version:     8.5 ms

【讨论】:

感谢您提供更快的 numpy rolling mean 实现。我也对滚动方差(或标准偏差)感兴趣,正如预期的那样,使用 numpy 步幅甚至更慢,但使用 pandas 仍然非常快。您是否知道滚动方差的类似 numpy 实现? 对于数值稳定的方差并不容易,因为在计算过程中均值会发生变化。这篇文章可能对您有所帮助:***.com/questions/5147378/rolling-variance-algorithm

以上是关于滚动统计性能:pandas vs. numpy strides的主要内容,如果未能解决你的问题,请参考以下文章

VS2008中的性能调查s-s-rS

pandas.series.rolling.apply 方法似乎将 Series 隐式转换为 numpy 数组

对于循环 pandas 和 numpy:性能

numpy模块

numpy pandas1

numpy 模块和 pandas 模块