如何计算Pandas DataFrame中每行对应过去n行的标准差?
优化Pandas中计算滚动标准差的效率问题
你现在用iterrows()循环逐行计算过去n行的标准差,这种方法在数据量稍大的时候会变得非常慢——毕竟iterrows()是逐行迭代,每次还要做切片计算,时间复杂度是O(m*n)(m是DataFrame的行数),而且直接用df['std'][i]赋值还可能触发SettingWithCopyWarning,甚至导致意外的修改行为。
最优解决方案:用Pandas内置的rolling()方法
Pandas专门提供了rolling()API来处理这类滚动窗口统计计算,完全不需要手动循环,底层是向量化的C实现,效率比循环高几个数量级,代码也更简洁。
场景1:计算包含当前行在内的过去n行的标准差
比如你提到的「行索引为100、n=25时,计算索引76到100区间(共25行)的标准差」,直接用下面的代码:
n = 25 df['std'] = df['Close'].rolling(window=n).std()
window=n:指定滚动窗口的大小为n行- 默认情况下,前n-1行因为数据不足n个,会返回
NaN;如果希望前n-1行用已有数据计算标准差(比如第5行用前5行的数据),可以加上min_periods=1参数:df['std'] = df['Close'].rolling(window=n, min_periods=1).std()
场景2:计算当前行之前的n行(不包含当前行)的标准差
如果你需要的是「行索引为100时,计算索引75到99区间(共25行)的标准差」,只需要在rolling()后加shift(1),把结果下移一行即可:
df['std'] = df['Close'].rolling(window=n).std().shift(1)
为什么你的原代码效率低?
iterrows()的性能问题:逐行迭代本质上是Python层面的循环,远不如Pandas底层的向量化操作高效,当DataFrame有上万行甚至更多时,差距会非常明显。- 链式索引的风险:
df['std'][i]属于链式索引,Pandas无法确定你是在修改原DataFrame还是一个副本,容易触发SettingWithCopyWarning,正确的赋值方式应该是df.loc[i, 'std'],但即使修正了这一点,循环的效率依然很低。 - 切片逻辑易出错:你原代码中的切片写法,在索引不是连续整数的时候会出现逻辑错误,而
rolling()会自动处理各种索引类型,无需手动计算切片范围。
完整测试示例
import pandas as pd import numpy as np # 生成1000行测试数据 np.random.seed(42) df = pd.DataFrame({'Close': np.random.randn(1000)}) n = 25 # 计算包含当前行的滚动标准差 df['std_rolling'] = df['Close'].rolling(window=n).std() # 计算当前行之前n行的标准差(不包含当前行) df['std_rolling_past'] = df['Close'].rolling(window=n).std().shift(1)
内容的提问来源于stack exchange,提问作者Don Coder
相关产品推荐
相关产品推荐

