Pandas 按时间和组滚动条件总和
Pandas rolling conditional sum on time and group
在 Python/Pandas 中,我有一项看似艰巨的任务要做。
我有这样一个数据框:
| DATETIME | PRODUCT | AMOUNT |
我需要为每个产品(我有两个以上的产品)生成最后一列,其中包含过去 5 分钟内(比如说已售出的产品)金额的累计总和。请参阅以下示例:
| DATETIME | PRODUCT | AMOUNT | CUM SUM |
| 2020-01-01 17:10:00 | A | 20 | 20 -> 20 |
| 2020-01-01 17:12:00 | B | 30 | 30 -> 30 |
| 2020-01-01 17:13:00 | A | 10 | 20+10 -> 30 |
| 2020-01-01 17:13:00 | A | 15 | 20+10+15 -> 45 |
| 2020-01-01 17:16:00 | B | 10 | 30+10 -> 40 |
| 2020-01-01 17:17:00 | A | 15 | 10+15+15 -> 40 |
| 2020-01-01 17:20:00 | B | 20 | 10+20 -> 30 |
| 2020-01-01 17:20:00 | B | 10 | 10+20+10 -> 40 |
| 2020-01-01 17:25:00 | A | 10 | 10 -> 10 |
请注意,情侣(日期时间、产品)可能不是唯一的,但我仍然必须根据数据帧索引保留订单。
我试过:
- 滚动功能:但不幸的是我没有固定的 window 大小,而且我没有唯一的一对(日期时间,产品)所以我不能使用日期时间作为索引然后使用
.rolling('5 minutes')
.
Groupby(product).cumsum()
: 但我无法将总和限制在最后几分钟。
可能,我需要一些流畅且性能水平不太差的东西,以应用于相当大的 df 。
你有什么提示吗?
提前致谢。
您可以使用 pd.DataFrame.groupby
, groupby.apply
, pd.DataFrame.rolling
by time window (5 minutes == '5T') and rolling.sum
:
>>> df['CUM SUM'] = (df.set_index('DATETIME')
.groupby('PRODUCT')
.apply(lambda x: x.rolling('5T').sum()
).values)
DATETIME PRODUCT AMOUNT CUM SUM
0 2020-01-01 17:10:00 A 20 20.0
1 2020-01-01 17:12:00 B 30 30.0
2 2020-01-01 17:13:00 A 10 30.0
3 2020-01-01 17:13:00 A 15 45.0
4 2020-01-01 17:16:00 B 10 40.0
5 2020-01-01 17:17:00 A 15 40.0
6 2020-01-01 17:20:00 B 20 30.0
7 2020-01-01 17:20:00 B 10 40.0
8 2020-01-01 17:25:00 A 10 10.0
我正在添加确切的步骤,看看你是否能发现你的 df 有什么不同:
>>> from io import StringIO
>>> df = pd.read_csv(StringIO("""
DATETIME PRODUCT AMOUNT
2020-01-01 17:10:00 A 20
2020-01-01 17:12:00 B 30
2020-01-01 17:13:00 A 10
2020-01-01 17:13:00 A 15
2020-01-01 17:16:00 B 10
2020-01-01 17:17:00 A 15
2020-01-01 17:20:00 B 20
2020-01-01 17:20:00 B 10
2020-01-01 17:25:00 A 10"""), sep=r'\s\s+')
>>> df['DATETIME'] = pd.to_datetime(df['DATETIME'])
>>> df
DATETIME PRODUCT AMOUNT
0 2020-01-01 17:10:00 A 20
1 2020-01-01 17:12:00 B 30
2 2020-01-01 17:13:00 A 10
3 2020-01-01 17:13:00 A 15
4 2020-01-01 17:16:00 B 10
5 2020-01-01 17:17:00 A 15
6 2020-01-01 17:20:00 B 20
7 2020-01-01 17:20:00 B 10
8 2020-01-01 17:25:00 A 10
>>> df['CUM SUM'] = (df.set_index('DATETIME')
.groupby('PRODUCT')
.apply(lambda x: x.rolling('5T').sum()
).values)
>>> df
DATETIME PRODUCT AMOUNT CUM SUM
0 2020-01-01 17:10:00 A 20 20.0
1 2020-01-01 17:12:00 B 30 30.0
2 2020-01-01 17:13:00 A 10 30.0
3 2020-01-01 17:13:00 A 15 45.0
4 2020-01-01 17:16:00 B 10 40.0
5 2020-01-01 17:17:00 A 15 40.0
6 2020-01-01 17:20:00 B 20 30.0
7 2020-01-01 17:20:00 B 10 40.0
8 2020-01-01 17:25:00 A 10 10.0
我注意到我错过了值后的右括号,已修复。
编辑
这适用于 pandas 1.2.0
,适用于`pandas 1.0.5':
>>> df['CUM SUM'] = (df.set_index('DATETIME')
.groupby('AMOUNT')
.apply(lambda x: x.rolling('5T').sum().reset_index(drop=True))
.values)
在 Python/Pandas 中,我有一项看似艰巨的任务要做。
我有这样一个数据框:
| DATETIME | PRODUCT | AMOUNT |
我需要为每个产品(我有两个以上的产品)生成最后一列,其中包含过去 5 分钟内(比如说已售出的产品)金额的累计总和。请参阅以下示例:
| DATETIME | PRODUCT | AMOUNT | CUM SUM |
| 2020-01-01 17:10:00 | A | 20 | 20 -> 20 |
| 2020-01-01 17:12:00 | B | 30 | 30 -> 30 |
| 2020-01-01 17:13:00 | A | 10 | 20+10 -> 30 |
| 2020-01-01 17:13:00 | A | 15 | 20+10+15 -> 45 |
| 2020-01-01 17:16:00 | B | 10 | 30+10 -> 40 |
| 2020-01-01 17:17:00 | A | 15 | 10+15+15 -> 40 |
| 2020-01-01 17:20:00 | B | 20 | 10+20 -> 30 |
| 2020-01-01 17:20:00 | B | 10 | 10+20+10 -> 40 |
| 2020-01-01 17:25:00 | A | 10 | 10 -> 10 |
请注意,情侣(日期时间、产品)可能不是唯一的,但我仍然必须根据数据帧索引保留订单。
我试过:
- 滚动功能:但不幸的是我没有固定的 window 大小,而且我没有唯一的一对(日期时间,产品)所以我不能使用日期时间作为索引然后使用
.rolling('5 minutes')
. Groupby(product).cumsum()
: 但我无法将总和限制在最后几分钟。
可能,我需要一些流畅且性能水平不太差的东西,以应用于相当大的 df 。
你有什么提示吗?
提前致谢。
您可以使用 pd.DataFrame.groupby
, groupby.apply
, pd.DataFrame.rolling
by time window (5 minutes == '5T') and rolling.sum
:
>>> df['CUM SUM'] = (df.set_index('DATETIME')
.groupby('PRODUCT')
.apply(lambda x: x.rolling('5T').sum()
).values)
DATETIME PRODUCT AMOUNT CUM SUM
0 2020-01-01 17:10:00 A 20 20.0
1 2020-01-01 17:12:00 B 30 30.0
2 2020-01-01 17:13:00 A 10 30.0
3 2020-01-01 17:13:00 A 15 45.0
4 2020-01-01 17:16:00 B 10 40.0
5 2020-01-01 17:17:00 A 15 40.0
6 2020-01-01 17:20:00 B 20 30.0
7 2020-01-01 17:20:00 B 10 40.0
8 2020-01-01 17:25:00 A 10 10.0
我正在添加确切的步骤,看看你是否能发现你的 df 有什么不同:
>>> from io import StringIO
>>> df = pd.read_csv(StringIO("""
DATETIME PRODUCT AMOUNT
2020-01-01 17:10:00 A 20
2020-01-01 17:12:00 B 30
2020-01-01 17:13:00 A 10
2020-01-01 17:13:00 A 15
2020-01-01 17:16:00 B 10
2020-01-01 17:17:00 A 15
2020-01-01 17:20:00 B 20
2020-01-01 17:20:00 B 10
2020-01-01 17:25:00 A 10"""), sep=r'\s\s+')
>>> df['DATETIME'] = pd.to_datetime(df['DATETIME'])
>>> df
DATETIME PRODUCT AMOUNT
0 2020-01-01 17:10:00 A 20
1 2020-01-01 17:12:00 B 30
2 2020-01-01 17:13:00 A 10
3 2020-01-01 17:13:00 A 15
4 2020-01-01 17:16:00 B 10
5 2020-01-01 17:17:00 A 15
6 2020-01-01 17:20:00 B 20
7 2020-01-01 17:20:00 B 10
8 2020-01-01 17:25:00 A 10
>>> df['CUM SUM'] = (df.set_index('DATETIME')
.groupby('PRODUCT')
.apply(lambda x: x.rolling('5T').sum()
).values)
>>> df
DATETIME PRODUCT AMOUNT CUM SUM
0 2020-01-01 17:10:00 A 20 20.0
1 2020-01-01 17:12:00 B 30 30.0
2 2020-01-01 17:13:00 A 10 30.0
3 2020-01-01 17:13:00 A 15 45.0
4 2020-01-01 17:16:00 B 10 40.0
5 2020-01-01 17:17:00 A 15 40.0
6 2020-01-01 17:20:00 B 20 30.0
7 2020-01-01 17:20:00 B 10 40.0
8 2020-01-01 17:25:00 A 10 10.0
我注意到我错过了值后的右括号,已修复。
编辑
这适用于 pandas 1.2.0
,适用于`pandas 1.0.5':
>>> df['CUM SUM'] = (df.set_index('DATETIME')
.groupby('AMOUNT')
.apply(lambda x: x.rolling('5T').sum().reset_index(drop=True))
.values)