parallelize/speed up pandas groupby 变换的高效方法
Efficient way to parallelize/speed up pandas groupby transform
我正在尝试加速一些用于计算 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 秒才能执行。你知道有什么有效的方法可以加快速度吗?
谢谢
最好的问候
您可以通过 .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.6 秒与 0.715 秒:提高 51 倍
我正在尝试加速一些用于计算 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 秒才能执行。你知道有什么有效的方法可以加快速度吗?
谢谢 最好的问候
您可以通过 .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.6 秒与 0.715 秒:提高 51 倍