【问题标题】:Improve parallelization in pandas提高 pandas 的并行化
【发布时间】:2022-01-28 01:36:51
【问题描述】:

我正在尝试在 pandas DataFrame 上并行化一个函数,我想知道为什么并行化比单核解决方案慢得多。我知道并行化有其成本......但我很好奇是否有办法改进代码以便并行化更快。

在我的情况下,我有一个用户 ID 列表(300 000(所有字符串)),需要检查用户 ID 是否也存在于另一个仅包含 10 000 个条目的列表中。

由于我无法重现原始代码,所以我给出了一个导致相同性能问题的整数示例:

import pandas as pd
import numpy as np
from joblib import Parallel, delayed
import time

df = pd.DataFrame({'All': np.random.randint(50000, size=300000)})
selection = pd.Series({'selection': np.random.randint(10000, size=10000)}).to_list()

t1=time.perf_counter()

df['Is_in_selection_single']=np.where(np.isin(df['All'], selection),1,0).astype('int8')
t2=time.perf_counter()
print(t2-t1)

def add_column(x):
    return(np.where(np.isin(x, selection),1,0))

df['Is_in_selection_parallel'] = Parallel(n_jobs=4)(delayed(add_column)(x) for x in df['All'].to_list())
t3=time.perf_counter()
print(t3-t2)

时间打印结果如下:

0.0307

53.07

这意味着并行化比单核慢 1766 倍。

在我的真实例子中,使用User-Id,单核需要1分钟,但15分钟后并行化还没有完成......

我需要并行化,因为我需要多次执行此操作,因此最终脚本需要几分钟才能运行。 感谢您的任何建议!

【问题讨论】:

  • 我认为 np.where 是不必要的,因为 astype('int8') 会将 bool 转换为 int。

标签: python pandas numpy joblib


【解决方案1】:

您将作业拆分为过多的子作业(每行 1 个)。这将产生非常大的间接成本。你应该把它切成更少的块:

parallel_result = Parallel(n_jobs=4)(delayed(add_column)(x) for x in np.split(df['All'].values, 4))
df['Is_in_selection_parallel'] = np.concatenate(parallel_result)

4 个块将比我平台上的非并行版本快 50%。

【讨论】:

  • 完美!带有用户 ID 的我的脚本现在可以在 20 秒内运行,而不是 1 分钟!我可以依赖 Parallel 以与输入相同的顺序返回块吗?
【解决方案2】:

使用一组成员资格测试使我的系统提高了 2.5 倍。这可以用于并行计算。

df = pd.DataFrame({'All': np.random.randint(50000, size=300000)})
selection = np.random.randint(10000, size=10000)

s1 = pd.Series(selection)
s2 = set(selection)

def orig(df, s):
    df['Is_in_selection_single'] = np.where(
        np.isin(df['All'], s), 1, 0).astype('int8')
    return sum(df['Is_in_selection_single'])

def modified(df, s):
    df['Is_in_selection_single'] = df['All'].isin(selection)
    return sum(df['Is_in_selection_single'])

计时结果:

%timeit orig(df, s1)
47.1 ms ± 212 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit modified(df, s2)
19 ms ± 194 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

【讨论】:

    猜你喜欢
    • 2017-04-13
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 2013-01-02
    • 2015-03-11
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多