我写了一个代码,其中有很长的for循环。 这是一个蒙特卡洛模拟,需要花费很长时间才能执行,因此我决定尝试对其进行并行化。
我的代码原本是这样的:
import numpy as np
import pandas as pd
if __name__ == "__main__":
nsims = 1000
a = pd.DataFrame(np.zeros((100,nsims)))
b = pd.DataFrame(np.zeros((100,nsims)))
c = pd.DataFrame(np.zeros((100,nsims)))
...
first part of the code
...
# monte carlo iteration, very big loop!
for i in range(nsims):
__do a lot of stuff and calculate res1, res2 and res3__
a[i] = res1 # res1 is a numpy array of 100 elements
b[i] = res2 # res2 is a numpy array of 100 elements
c[i] = res3 # res3 is a numpy array of 100 elements
# end of monte carlo iteration
...
rest of the code
...
结果是,我更新了数据帧a,b和c,for循环的每次迭代都用一列。
然后我创建了一个函数,其中所有内容最初都在for循环中,并修改了代码以使用它:
import numpy as np
import pandas as pd
def monte_carlo(arg1, arg2, arg3):
__do a lot of stuff and calculate res1, res2 and res3__
return(res1,res2,res3)
if __name__ == "__main__":
nsims = 1000
a = pd.DataFrame(np.zeros((100,nsims)))
b = pd.DataFrame(np.zeros((100,nsims)))
c = pd.DataFrame(np.zeros((100,nsims)))
...
first part of the code
...
# monte carlo iteration
for i in range(nsims):
a[i],b[i],c[i] = monte_carlo(arg1,arg2,arg3)
# end of monte carlo iteration
...
rest of the code
...
这显然与以前的版本完全相同。
我尝试使用multiprocessing.Pool(这是我的第一次尝试),但是我不确定什么是收集结果并将其组合到三个数据框中的最佳方法。 我能得到的最好的是一个元组列表,然后我将其解压缩并转换为数据帧。
让我做一个例子。
我的代码的简单版本可以正常工作,并且希望并行化:
### original code ###
import numpy as np
import pandas as pd
import time
def monte_carlo(x):
s = np.full(100, x + x)
s1 = np.full(100, 999 - x)
return(s, s1)
if __name__ == "__main__":
result = pd.DataFrame(np.zeros((100,1000)))
result1 = pd.DataFrame(np.zeros((100,1000)))
iter = 1000
t = time.time()
for i in range(iter):
result[i], result1[i] = monte_carlo(i)
print("elapsed time ", time.time()-t)
结果是我得到了两个零填充的数据帧,现在填充了在函数中计算的numpy数组
In [*]: result
Out [*]:
0 1 2 3 4 5 6 ... 993 994 995 996 997 998 999
0 0 2 4 6 8 10 12 ... 1986 1988 1990 1992 1994 1996 1998
1 0 2 4 6 8 10 12 ... 1986 1988 1990 1992 1994 1996 1998
.. ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
98 0 2 4 6 8 10 12 ... 1986 1988 1990 1992 1994 1996 1998
99 0 2 4 6 8 10 12 ... 1986 1988 1990 1992 1994 1996 1998
[100 rows x 1000 columns]
In [*]: result1
Out [*]:
0 1 2 3 4 5 6 ... 993 994 995 996 997 998 999
0 999 998 997 996 995 994 993 ... 6 5 4 3 2 1 0
1 999 998 997 996 995 994 993 ... 6 5 4 3 2 1 0
.. ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
98 999 998 997 996 995 994 993 ... 6 5 4 3 2 1 0
99 999 998 997 996 995 994 993 ... 6 5 4 3 2 1 0
而这正是我想要的。
经过时间为0.4182307720184326秒
这是我最好的并行化代码:
import numpy as np
import pandas as pd
import time
from multiprocessing import Pool
def monte_carlo(x):
s = np.full(100, x + x)
s1 = np.full(100, 999 - x)
return(s, s1)
if __name__ == "__main__":
result = pd.DataFrame(np.zeros((100,1000)))
result1 = pd.DataFrame(np.zeros((100,1000)))
iter = 1000
t = time.time()
p = Pool()
a = p.map(monte_carlo,range(iter))
res,res1 = zip(*a)
result = pd.DataFrame(res).transpose()
result1 = pd.DataFrame(res1).transpose()
print("elapsed time ", time.time()-t)
a是数组(s,s1)的1000个元组的列表,我可以将它们拆成两个元组res和res1,每个元组的大小为1000,然后将每个元组转换为pandas数据帧并将其转置为具有值从列中的过程中获取。
在第二种情况下,经过时间为0.12450671195983887秒。
我得到了改进,我应该能够在更大的代码上进行复制。
似乎我编写的并行代码正在运行,但是我想知道是否有更好的方法可以执行相同的操作。 考虑到在此示例中,我从该函数中仅获得了numpy数组,但在我的真实代码中,对于每个函数调用,我还将获得一些pandas数据帧,需要将它们追加以创建更大的堆叠数据帧。
提前谢谢!