只需更改一行代码, pandarallel库 就可以充分利用CPU性能,并行化所有 Pandas 操作,加速你的数据处理。

pandarallel 还提供漂亮的进度条(在笔记本和终端上可用)以 大致了解要完成的剩余计算量。

没有并行化

可以看到,使用并行化后,处理速度快了很多。

一、性能对比

cpu有n个核,大概并行化会提升大概n倍 。以下是使用和不使用 Pandaral·lel 的比较基准。实验环境:

  • 操作系统 :Linux Ubuntu 16.04
  • 硬件 :Intel Core i7 @ 3.40 GHz - 4 核
  • 并行操作的运行速度大约是标准操作的 4 倍(除了标准操作的运行速度仅快 3.2 倍)。

    二、特性

    pandarallel 目前实现以下 API: pandas

    没有并行化 df.groupby(args1).col_name.rolling(args2).apply(func) df.groupby(args1).col_name.rolling(args2).parallel_apply(func) df.groupby(args1).col_name.expanding(args2).apply(func) df.groupby(args1).col_name.expanding(args2).parallel_apply(func) series.map(func) series.parallel_map(func) series.apply(func) series.parallel_apply(func) series.rolling(args).apply(func) series.rolling(args).parallel_apply(func)

    三、语法

    Mac 和 linux,没有什么特殊的用法, 但在 Windows 上, 您掉用的函数必须是 自包含 的,并且不应依赖于外部资源。为了降低大家的记忆压力, 咱们假设所有系统,都要满足自包含且不依赖外部资源。

    3.1 安装

    pip install pandarallel
    

    3.2 错误用法

    import pandas as pd
    from pandarallel import pandarallel
    #初始化,且显示进度条
    pandarallel.initialize(progress_bar=True)
    import math
    def func(x):
        # func不能依赖外部资源, math定义在函数体func之外, 会出问题的!
        return math.sin(x.a**2) + math.sin(x.b**2)
    df = pd.read_csv('实验的csv文件路径')
    df['result'] = df['某个数值字段'].parallel_apply(func)
    

    3.3 正确用法

    定义好计算函数 func, 标准的 pandas 的计算是在 pd.Series 基础上掉用 apply 方法,即 pd.Series.apply(func)

    pandarallel 稍微修改了方法名, pd.Series.parallel_apply(func)

    import pandas as pd
    from pandarallel import pandarallel
    #初始化,且显示进度条
    pandarallel.initialize(progress_bar=True)
    def func(x):
        import math
        # 在函数体func内导入math,掉用math, okay!
        return math.sin(x.a**2) + math.sin(x.b**2)
    df = pd.read_csv('实验的csv文件路径')
    df['result'] = df['某个数值字段'].parallel_apply(func)
    

    四、实验

    对一个 xlsx 文件的 text 字段进行词频统计, 结果保存到新字段 wordCount 中。

    4.1 读取数据

    mda01-22.xlsx数据有55439条记录, 体积573M。

    import pandas as pd
    df = pd.read_excel('mda01-22.xlsx')
    print(len(df))
    df.head()
    
    55439
    

    4.2 没有并行

    %%time
    import pandas as pd
    import jieba
    def word_count(text):
        return len(jieba.lcut(text))
    df = pd.read_excel('mda01-22.xlsx')
    df['wordCount'] = df['text'].apply(word_count)
    df.head()
    
    CPU times: user 11min 56s, sys: 10.5 s, total: 12min 7s
    Wall time: 12min 7s
    

    4.3 并行化

    %%time
    import pandas as pd
    from pandarallel import pandarallel
    #初始化,且显示进度条
    pandarallel.initialize(progress_bar=True)
    def parallel_word_count(text):
        import jieba
        return len(jieba.lcut(text))
    df = pd.read_excel('mda01-22.xlsx')
    df['wordCount'] = df['text'].parallel_apply(word_count)
    df.head()
    
    INFO: Pandarallel will run on 12 workers.
    INFO: Pandarallel will use standard multiprocessing data transfer (pipe) to transfer data between the main process and workers.
    CPU times: user 12.4 s, sys: 1.41 s, total: 13.8 s
    Wall time: 2min 40s
    

    Wow, 运行总时间从 12min 7s 降低 2min 40s 。

    4.4 使用场景

    并行化是有代价的(实例化新进程、通过共享内存发送数据、 …),只有在并行化的计算量大时才有效足够高。对于小规模的数据,使用并行化并不总是值得的。经过测试, 找了一个61kb的xlsx, 结果并行化反而还慢了。

    pandarallel 通过使用计算机cpu所有内核来绕过此限制。 但代价是,需要两倍于标准操作的内存占用。

    广而告之

  • 长期招募小伙伴
  • 付费视频课 | Python实证指标构建与文本分析