将函数应用于 Pandas Groupby
Applying function to Pandas Groupby
我目前正在处理 Python 中的面板数据,我正在尝试计算给定组 (ID) 中每个时间序列观察值的滚动平均值。
考虑到我的数据集的大小(具有多个时间段的数千个组),.groupby 和 .apply() 函数计算时间太长(已 运行 超过一个小时并且仍然没有——整个数据集只包含大约 300k 个观察值)。
我最终想遍历多个列,执行以下操作:
- 按组 ID 计算给定列中每个时间步长的滚动平均值
- 创建一个新列,其中包含原始值与移动平均值之间的差异 [x_t - (x_t-1 + x_t)/2]
- 将列存储在新的 DataFrame 中,这将与原始数据集相同,只是它具有 #2 的残差而不是原始值。
重复并将新残差附加到 df_resid(如下所示)
df_resid
date id rev_resid exp_resid
2005-09-01 1 NaN NaN
2005-12-01 1 -10000 -5500
2006-03-01 1 -352584 -262058.5
2006-06-01 1 240000 190049.5
2006-09-01 1 82648.75 37724.25
2005-09-01 2 NaN NaN
2005-12-01 2 4206.5 24353
2006-03-01 2 -302574 -331951
2006-06-01 2 103179 117405.5
2006-09-01 2 -52650 -72296.5
这是原始数据的小样本。
df
date id rev exp
2005-09-01 1 745168.0 545168.0
2005-12-01 1 725168.0 534168.0
2006-03-01 1 20000.0 10051.0
2006-06-01 1 500000.0 390150.0
2006-09-01 1 665297.5 465598.5
2005-09-01 2 956884.0 736987.0
2005-12-01 2 965297.0 785693.0
2006-03-01 2 360149.0 121791.0
2006-06-01 2 566507.0 356602.0
2006-09-01 2 461207.0 212009.0
和(非常慢的)代码:
df['rev_resid'] = df.groupby('id')['rev'].apply(lambda x:x.rolling(center=False,window=2).mean())
我希望有一种计算效率更高的方法来执行此操作(主要是关于 #1),并且可以扩展到多列。
任何帮助将不胜感激。
为了加快计算速度,如果数据框已经在 'id'
上排序,那么您不必在 groupby
中执行 rolling
(如果它未排序。 .. 这样做)。然后因为你的 window 只有长度 2
那么我们通过检查 id == id.shift
的位置来屏蔽结果。这是有效的,因为它是排序的。
d1 = df[['rev', 'exp']]
df.join(
d1.rolling(2).mean().rsub(d1).add_suffix('_resid')[df.id.eq(df.id.shift())]
)
date id rev exp rev_resid exp_resid
0 2005-09-01 1 745168.0 545168.0 NaN NaN
1 2005-12-01 1 725168.0 534168.0 -10000.00 -5500.00
2 2006-03-01 1 20000.0 10051.0 -352584.00 -262058.50
3 2006-06-01 1 500000.0 390150.0 240000.00 190049.50
4 2006-09-01 1 665297.5 465598.5 82648.75 37724.25
5 2005-09-01 2 956884.0 736987.0 NaN NaN
6 2005-12-01 2 965297.0 785693.0 4206.50 24353.00
7 2006-03-01 2 360149.0 121791.0 -302574.00 -331951.00
8 2006-06-01 2 566507.0 356602.0 103179.00 117405.50
9 2006-09-01 2 461207.0 212009.0 -52650.00 -72296.50
我目前正在处理 Python 中的面板数据,我正在尝试计算给定组 (ID) 中每个时间序列观察值的滚动平均值。
考虑到我的数据集的大小(具有多个时间段的数千个组),.groupby 和 .apply() 函数计算时间太长(已 运行 超过一个小时并且仍然没有——整个数据集只包含大约 300k 个观察值)。
我最终想遍历多个列,执行以下操作:
- 按组 ID 计算给定列中每个时间步长的滚动平均值
- 创建一个新列,其中包含原始值与移动平均值之间的差异 [x_t - (x_t-1 + x_t)/2]
- 将列存储在新的 DataFrame 中,这将与原始数据集相同,只是它具有 #2 的残差而不是原始值。
重复并将新残差附加到 df_resid(如下所示)
df_resid date id rev_resid exp_resid 2005-09-01 1 NaN NaN 2005-12-01 1 -10000 -5500 2006-03-01 1 -352584 -262058.5 2006-06-01 1 240000 190049.5 2006-09-01 1 82648.75 37724.25 2005-09-01 2 NaN NaN 2005-12-01 2 4206.5 24353 2006-03-01 2 -302574 -331951 2006-06-01 2 103179 117405.5 2006-09-01 2 -52650 -72296.5
这是原始数据的小样本。
df
date id rev exp
2005-09-01 1 745168.0 545168.0
2005-12-01 1 725168.0 534168.0
2006-03-01 1 20000.0 10051.0
2006-06-01 1 500000.0 390150.0
2006-09-01 1 665297.5 465598.5
2005-09-01 2 956884.0 736987.0
2005-12-01 2 965297.0 785693.0
2006-03-01 2 360149.0 121791.0
2006-06-01 2 566507.0 356602.0
2006-09-01 2 461207.0 212009.0
和(非常慢的)代码:
df['rev_resid'] = df.groupby('id')['rev'].apply(lambda x:x.rolling(center=False,window=2).mean())
我希望有一种计算效率更高的方法来执行此操作(主要是关于 #1),并且可以扩展到多列。
任何帮助将不胜感激。
为了加快计算速度,如果数据框已经在 'id'
上排序,那么您不必在 groupby
中执行 rolling
(如果它未排序。 .. 这样做)。然后因为你的 window 只有长度 2
那么我们通过检查 id == id.shift
的位置来屏蔽结果。这是有效的,因为它是排序的。
d1 = df[['rev', 'exp']]
df.join(
d1.rolling(2).mean().rsub(d1).add_suffix('_resid')[df.id.eq(df.id.shift())]
)
date id rev exp rev_resid exp_resid
0 2005-09-01 1 745168.0 545168.0 NaN NaN
1 2005-12-01 1 725168.0 534168.0 -10000.00 -5500.00
2 2006-03-01 1 20000.0 10051.0 -352584.00 -262058.50
3 2006-06-01 1 500000.0 390150.0 240000.00 190049.50
4 2006-09-01 1 665297.5 465598.5 82648.75 37724.25
5 2005-09-01 2 956884.0 736987.0 NaN NaN
6 2005-12-01 2 965297.0 785693.0 4206.50 24353.00
7 2006-03-01 2 360149.0 121791.0 -302574.00 -331951.00
8 2006-06-01 2 566507.0 356602.0 103179.00 117405.50
9 2006-09-01 2 461207.0 212009.0 -52650.00 -72296.50