Python并行化相关性比单个进程相关性慢

时间:2017-02-16 09:30:27

标签: python pandas parallel-processing multiprocessing correlation

我想在Python中使用df.corr()模块并行化multiprocessing。我正在使用一列并计算相关值,其中一个进程和第二列中的所有列都处于休息状态,其他进程中的其他列则处于休息状态。我继续以这种方式通过堆叠来自所有过程的结果行来填充相关矩阵的上层。

我获取了形状(678461, 210)的示例数据并尝试了我的并行化方法和df.corr(),并分别获得214.40s42.64s的运行时间。所以,我的并行化方法需要更多时间。

有没有办法改善这个?

import multiprocessing as mp
import pandas as pd
import numpy as np
from time import *

def _correlation(args):

    i, mat, mask = args
    ac = mat[i]

    arr = []

    for j in range(len(mat)):  
        if i > j:
            continue

        bc = mat[j]
        valid = mask[i] & mask[j]
        if valid.sum() < 1:
            c = NA    
        elif i == j:
            c = 1.
        elif not valid.all():
            c = np.corrcoef(ac[valid], bc[valid])[0, 1]
        else:
            c = np.corrcoef(ac, bc)[0, 1]

        arr.append((j, c))

    return arr

def correlation_multi(df):

    numeric_df = df._get_numeric_data()
    cols = numeric_df.columns
    mat = numeric_df.values

    mat = pd.core.common._ensure_float64(mat).T
    K = len(cols)
    correl = np.empty((K, K), dtype=float)
    mask = np.isfinite(mat)

    pool = mp.Pool(processes=4)

    ret_list = pool.map(_correlation, [(i, mat, mask) for i in range(len(mat))])

    for i, arr in enumerate(ret_list):
        for l in arr:
            j = l[0]
            c = l[1]

            correl[i, j] = c
            correl[j, i] = c

    return pd.DataFrame(correl, index = cols, columns = cols)

if __name__ == '__main__':
    noise  = pd.DataFrame(np.random.randint(0,100,size=(100000, 50)))
    noise2  = pd.DataFrame(np.random.randint(100,200,size=(100000, 50)))
    df = pd.concat([noise, noise2], axis=1)

    #Single process correlation    
    start = time()
    s = df.corr()
    print('Time taken: ',time()-start)

    #Multi process correlation
    start = time()
    s1 = correlation_multi(df)
    print('Time taken: ',time()-start)

1 个答案:

答案 0 :(得分:0)

_correlation的结果必须通过进程间通信从工作进程移动到运行Pool的进程。

这意味着返回数据被pickle,发送到其他进程,unpickled并添加到结果列表中。 这需要时间,本质上是一个连续的过程。

map按照发送顺序处理退货,IIRC。因此,如果一次迭代需要相对较长的时间,其他结果可能会停滞等待。您可以尝试使用imap_unordered,一旦到达就会产生结果。