我在运行蒙特卡洛模拟.计算的一部分需要对每个模拟的滚动窗口应用函数.然而,我不知道如何有效地做到这一点.我担心这可能是一个重复的帖子,但我找不到另一个这样的帖子.

我举的最小可重现的例子是:

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

# Number of simulations
trials = 10000

# Generate random variables
df1 = pd.DataFrame(norm.rvs(size = (500, trials)))

f = lambda x: np.sum(x > 0) > 20

# Make a deep copy of df1
df2 = df1.copy(deep = True)

for col in df2.columns:
    
    df2[col] = df2[col].rolling(window = 30).apply(f)

有没有一种方法可以在不理解for循环或列表的情况下编写这段代码?因为模拟是列,所以df2理想情况下至少有10,000列.拥有一个转置的数据帧也是很好的.在我的代码中,这一部分所用的时间大约是我模拟中第二长进程的100倍.

推荐答案

你并不是一个最小的例子.所以我们首先试着看看最小的例子会发生什么,然后我们在完整的例子上测试性能.

Data

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

# Number of simulations
trials = 10000

# Generate random variables
df1 = pd.DataFrame(norm.rvs(size = (500, trials)))

Min example

在这里,我既减少了数据量,又更改了您的函数以使用更少的数据

df_min = df1[range(3)][:10]
# backup
df_min_bk = df_min.copy()
f_min = lambda x: np.sum(x > 0) > 2

其中df_min

          0         1         2
0  0.407418  1.741455 -0.270929
1 -0.530294  1.248405  1.201781
2 -1.193793 -0.088235  0.991222
3 -0.941380  0.499053 -0.913778
4  0.951970 -2.073895 -1.179818
5 -1.666666  1.143326  1.266971
6  0.688032 -0.188798 -0.130474
7  0.618970 -0.595450  1.420563
8  1.370329 -0.904624  1.167164
9 -0.571588  0.547064 -1.169145

Run minimal example

使用应用

%%time
for col in df_min.columns:
    
    df_min[col] = df_min[col].rolling(window=3).apply(f_min)
CPU times: user 10.6 ms, sys: 693 µs, total: 11.3 ms
Wall time: 11 ms

输出结果是

     0    1    2
0  NaN  NaN  NaN
1  NaN  NaN  NaN
2  0.0  0.0  0.0
3  0.0  0.0  0.0
4  0.0  0.0  0.0
5  0.0  0.0  0.0
6  0.0  0.0  0.0
7  0.0  0.0  0.0
8  1.0  0.0  0.0
9  0.0  0.0  0.0

避免应用

设置df_min = df_min_bk.copy(),并使用内置函数将相同的函数重写为

for col in df_min.columns:
    
    df_min[col] = df_min[col].gt(0).rolling(window=3).sum().gt(2).astype(int)
CPU times: user 1.02 ms, sys: 3.21 ms, total: 4.24 ms
Wall time: 3.9 ms

Which is almost 3x the previous case 输出结果是 still

   0  1  2
0  0  0  0
1  0  0  0
2  0  0  0
3  0  0  0
4  0  0  0
5  0  0  0
6  0  0  0
7  0  0  0
8  1  0  0
9  0  0  0

如果我们记住滚动窗口的前n-1列应该是NaN,这是可以接受的.

避免循环列

再次设置为df_min = df_min_bk.copy(),我们可以使用不循环列的PRIME函数

%%time
df_min = df_min.gt(0).rolling(window=3).sum().gt(2).astype(int)
CPU times: user 2.21 ms, sys: 0 ns, total: 2.21 ms
Wall time: 2.22 ms

这几乎是珍贵表壳的2倍,应用表壳的6倍.输出与上一个示例相同.

Full Example

%%time
df2 = df2.gt(0).rolling(window=30).sum().gt(20).astype(int)
CPU times: user 607 ms, sys: 27 ms, total: 634 ms
Wall time: 633 ms

这只需要不到一秒钟的时间.虽然应用和循环遍历列需要几分钟

计时应用

CPU times: user 8min 40s, sys: 150 ms, total: 8min 40s
Wall time: 8min 40s

与以前的方法相比,speedup820x.

Conclusion

首先播放您可以可视化的少量数据,然后最终播放几个完整的列,然后播放所有数据.

Python相关问答推荐

CustomTKinter-向表单添加额外的输入字段

每个组每第n行就有Pandas

使用GEKKO在简单DTE系统中进行一致初始化

将HTML输出转换为表格中的问题

try 与gemini-pro进行多轮聊天时出错

如何使用matplotlib在Python中使用规范化数据和原始t测试值创建组合热图?

Python 约束无法解决n皇后之谜

标题:如何在Python中使用嵌套饼图可视化分层数据?

pandas滚动和窗口中有效观察的最大数量

如何使用根据其他值相似的列从列表中获取的中间值填充空NaN数据

无法使用DBFS File API路径附加到CSV In Datricks(OSError Errno 95操作不支持)

将tdqm与cx.Oracle查询集成

删除marplotlib条形图上的底边

Python列表不会在条件while循环中正确随机化'

如何更改groupby作用域以找到满足掩码条件的第一个值?

在Python中调用变量(特别是Tkinter)

处理具有多个独立头的CSV文件

通过追加列表以极向聚合

polars:有效的方法来应用函数过滤列的字符串

Pandas 数据帧中的枚举,不能在枚举列上执行GROUP BY吗?