Pandas DataFrame 中的动态聚合
Dynamic aggregation in Pandas DataFrame
我在以下形式的数据框中添加了时间戳数据:
+----+-------+-------+
| ID | DATE | VALUE |
+----+-------+-------+
| 1 | 01-01 | 10 |
| 1 | 01-01 | 20 |
| 1 | 02-01 | 20 |
| 1 | 02-01 | 25 |
| 1 | 03-01 | 30 |
| 2 | 01-01 | 10 |
| 2 | 02-01 | 20 |
| 2 | 02-01 | 30 |
| 2 | 03-01 | 30 |
+----+-------+-------+
在 ID
的分组中,我现在想计算每一行的值与具有相同或更小日期的所有行的平均值的差值,这样:
+----+-------+-------+--------------------------------+
| ID | DATE | VALUE | OUTPUT |
+----+-------+-------+--------------------------------+
| 1 | 01-01 | 10 | 10-AVERAGE(10, 20) |
| 1 | 01-01 | 20 | 20-AVERAGE(10, 20) |
| 1 | 02-01 | 20 | 20-AVERAGE(10, 20, 20, 25) |
| 1 | 02-01 | 25 | 25-AVERAGE(10, 20, 20, 25) |
| 1 | 03-01 | 30 | 30-AVERAGE(10, 20, 20, 25, 30) |
| 2 | 01-01 | 10 | 10-AVERAGE(10) |
| 2 | 02-01 | 20 | 20-AVERAGE(10, 20, 30) |
| 2 | 02-01 | 30 | 30-AVERAGE(10, 20, 30) |
| 2 | 03-01 | 30 | 30-AVERAGE(10, 20, 30, 30) |
+----+-------+-------+--------------------------------+
如何在不创建大量临时列的情况下使用 Pandas/NumPy 实现此目的?
我尝试创建布尔掩码列并为每个仅部分填充的 DATE
创建临时列,但这相当麻烦。
您可以编写一个自定义函数来计算平均值,然后用 groupby.apply
:
调用它
def expanding_average(frame):
average = frame.groupby("DATE")["VALUE"].sum().expanding(1).sum().div(frame.groupby("DATE")["VALUE"].count().expanding(1).sum())
return frame["DATE"].map(average)
df["Average"] = df["VALUE"].sub(df.groupby("ID").apply(expanding_average).droplevel(0))
>>> df
ID DATE VALUE Average
0 1 01-01 10 -5.00
1 1 01-01 20 5.00
2 1 02-01 20 1.25
3 1 02-01 25 6.25
4 1 03-01 30 9.00
5 2 01-01 10 0.00
6 2 02-01 20 0.00
7 2 02-01 30 10.00
8 2 03-01 30 7.50
我在以下形式的数据框中添加了时间戳数据:
+----+-------+-------+
| ID | DATE | VALUE |
+----+-------+-------+
| 1 | 01-01 | 10 |
| 1 | 01-01 | 20 |
| 1 | 02-01 | 20 |
| 1 | 02-01 | 25 |
| 1 | 03-01 | 30 |
| 2 | 01-01 | 10 |
| 2 | 02-01 | 20 |
| 2 | 02-01 | 30 |
| 2 | 03-01 | 30 |
+----+-------+-------+
在 ID
的分组中,我现在想计算每一行的值与具有相同或更小日期的所有行的平均值的差值,这样:
+----+-------+-------+--------------------------------+
| ID | DATE | VALUE | OUTPUT |
+----+-------+-------+--------------------------------+
| 1 | 01-01 | 10 | 10-AVERAGE(10, 20) |
| 1 | 01-01 | 20 | 20-AVERAGE(10, 20) |
| 1 | 02-01 | 20 | 20-AVERAGE(10, 20, 20, 25) |
| 1 | 02-01 | 25 | 25-AVERAGE(10, 20, 20, 25) |
| 1 | 03-01 | 30 | 30-AVERAGE(10, 20, 20, 25, 30) |
| 2 | 01-01 | 10 | 10-AVERAGE(10) |
| 2 | 02-01 | 20 | 20-AVERAGE(10, 20, 30) |
| 2 | 02-01 | 30 | 30-AVERAGE(10, 20, 30) |
| 2 | 03-01 | 30 | 30-AVERAGE(10, 20, 30, 30) |
+----+-------+-------+--------------------------------+
如何在不创建大量临时列的情况下使用 Pandas/NumPy 实现此目的?
我尝试创建布尔掩码列并为每个仅部分填充的 DATE
创建临时列,但这相当麻烦。
您可以编写一个自定义函数来计算平均值,然后用 groupby.apply
:
def expanding_average(frame):
average = frame.groupby("DATE")["VALUE"].sum().expanding(1).sum().div(frame.groupby("DATE")["VALUE"].count().expanding(1).sum())
return frame["DATE"].map(average)
df["Average"] = df["VALUE"].sub(df.groupby("ID").apply(expanding_average).droplevel(0))
>>> df
ID DATE VALUE Average
0 1 01-01 10 -5.00
1 1 01-01 20 5.00
2 1 02-01 20 1.25
3 1 02-01 25 6.25
4 1 03-01 30 9.00
5 2 01-01 10 0.00
6 2 02-01 20 0.00
7 2 02-01 30 10.00
8 2 03-01 30 7.50