【问题标题】:Efficient way to parallelize/speed up pandas groupby transform并行化/加速 pandas groupby 变换的有效方法
【发布时间】:2021-10-08 20:23:44
【问题描述】:

我正在尝试加快一些用于计算 pandas 时间索引数据帧滞后的代码。 数据框包含由 ID 列标识的约 200k 时间序列。 我尝试了 dask 但没有任何改进(比单独使用 pandas 需要更长的时间)。

这是一个生成具有可比大小的虚拟数据框的工作示例:

import itertools as it
import numpy as np
import pandas as pd
np.random.seed(1)

#Series for ID
ID_data = pd.Series(np.arange(0,200000), name='ID')

#Array of data - create pandas dataframe with datetime index
value_data = np.random.rand(52,1)
tidx = pd.date_range('2019-01-01', periods=len(value_data), freq='D')
#Cross join with ID to create test dataframe
df = pd.DataFrame(value_data, columns=['value'], index=tidx).reset_index().merge(ID_data,how="cross").set_index('index')

现在,我想为每个时间序列(由 ID 列标识)计算值列的滞后(在本例中为 1 天滞后):

%%time
df["value_lag1"] = df.groupby(['ID'])["value"].transform(lambda x: x.shift(1))

此代码需要 30 秒才能执行。你知道任何有效的加速方法吗?

谢谢 最好的问候

【问题讨论】:

  • 示例脚本给了我:pandas.errors.MergeError: No common columns to perform merge on。
  • 嗨,我有以下 pandas/numpy 版本:print(pd.__version__) -> 1.3.1 print(np.__version__) -> 1.19.5
  • 我在笔记本上的空白笔记本上做了一个测试,没问题(使用相同的 pandas 版本)
  • 看起来我的有点旧(1.0.5 和 1.18.4)。我会更新并再试一次。
  • 已更新,测试脚本有效。

标签: python pandas dataframe parallel-processing time-series


【解决方案1】:

您可以在不使用 .transform 的 lambda 函数的情况下改进执行时间。直接对GroupBy对象使用DataFrameGroupBy.shift()函数即可,如下:

df["value_lag1"] = df.groupby(['ID'])["value"].shift(1)

在我的机器上原版和这个版本的执行时间分别是36.6s vs 0.715s。提高了 51 倍的速度

使用.transform 中的 lambda 函数,您不会使用内置的矢量化 Pandas 操作,而是使用慢速非优化代码。通过直接使用DataFrameGroupBy.shift() 函数,您的代码变得矢量化并运行得更快。

结果比较

原码和新码生成的2个列名:

df["value_lag1"] = df.groupby(['ID'])["value"].transform(lambda x: x.shift(1))

df["value_lag2"] = df.groupby(['ID'])["value"].shift(1)

df["value_lag1"].compare(df["value_lag2"])

# No difference shown by the compare function:

        self    other
index       

性能比较

%%timeit
df["value_lag1"] = df.groupby(['ID'])["value"].transform(lambda x: x.shift(1))

36.6 s ± 768 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
df["value_lag1"] = df.groupby(['ID'])["value"].shift(1)

715 ms ± 64.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

36.6s vs 0.715s:提高了 51 倍的速度

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-23
    • 2021-09-19
    • 1970-01-01
    • 2020-11-28
    • 1970-01-01
    • 2021-10-15
    • 2016-08-21
    相关资源
    最近更新 更多