You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

蒙特卡洛模拟中如何高效为Pandas所有列应用滚动窗口?

高效替代方案:基于Numpy的批量滑动窗口计算

你的核心问题是逐列循环调用rolling.apply的效率极低——这是因为rolling.apply本质上是逐行调用Python函数,加上10000列的循环,双重低效叠加。我们可以通过Numpy的批量数组操作直接完成所有列的滑动窗口计算,完全避免循环。

步骤原理

  1. 先将原数据转换为布尔数组(标记每个元素是否>0)
  2. 对所有列批量计算滑动窗口内True的数量
  3. 判断数量是否>20,再补全前29个位置的NaN(和原rolling行为一致)

实现代码

import pandas as pd
import numpy as np
from scipy.stats import norm

trials = 10000
df1 = pd.DataFrame(norm.rvs(size=(500, trials)))

# 1. 转换为布尔数组:元素>0为True,否则False
bool_arr = df1.values > 0
window_size = 30
n_rows, n_cols = bool_arr.shape

# 2. 批量计算滑动窗口内True的数量(用Numpy as_strided实现高效滑动窗口)
from numpy.lib.stride_tricks import as_strided

# 构造滑动窗口视图:形状为(n_rows - window_size + 1, window_size, n_cols)
strides = (bool_arr.strides[0], bool_arr.strides[0], bool_arr.strides[1])
windowed_arr = as_strided(
    bool_arr,
    shape=(n_rows - window_size + 1, window_size, n_cols),
    strides=strides
)

# 对每个窗口求和(axis=1是窗口维度)
window_sums = windowed_arr.sum(axis=1)

# 3. 生成最终结果:前29个位置补NaN,后面是是否>20的布尔值
result = np.full((n_rows, n_cols), np.nan)
result[window_size-1:] = window_sums > 20

# 转换为DataFrame
df2 = pd.DataFrame(result, columns=df1.columns)

为什么这个方法快?

  • 完全避免了Python层面的循环,所有计算都是Numpy的C级批量操作
  • as_strided只是创建数组视图,不复制数据,内存开销极小
  • 求和与布尔判断都是向量化操作,效率比逐列调用rolling.apply高几个数量级

另一种可选方法:用卷积实现求和

如果担心as_strided的内存视图操作不够直观,可以用卷积来计算窗口和:

from scipy.signal import convolve2d

# 构造卷积核:30行1列的全1数组,对应沿列方向的滑动窗口
kernel = np.ones((window_size, 1), dtype=int)
# 用"valid"模式计算,只保留有完整窗口的结果
window_sums = convolve2d(bool_arr, kernel, mode='valid')
# 同样补NaN
result = np.full((n_rows, n_cols), np.nan)
result[window_size-1:] = window_sums > 20
df2 = pd.DataFrame(result, columns=df1.columns)

这个方法的效率和as_strided接近,代码更直观,适合对内存视图操作不熟悉的场景。

内容的提问来源于stack exchange,提问作者Charles0349

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 16:53:29