从numpy数组创建熊猫数据帧,或者通过多重处理创建熊猫数据帧

时间:2019-06-05 08:48:48

标签: python pandas dataframe multiprocessing

我写了一个代码,其中有很长的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数据帧,需要将它们追加以创建更大的堆叠数据帧。

提前谢谢!

0 个答案:

没有答案