Pandas 按时间和分组滚动条件求和

3

我有一个类似这样的数据框:
| 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       |

请注意,(datetime, product) 一对可能不唯一,但是我仍然必须根据数据框索引保持顺序。
我尝试过:
1. 滚动函数:但不幸的是,我没有固定的窗口大小,并且我没有独特的一对(datetime, product),因此我不能使用datetime作为索引,然后使用 .rolling('5 minutes')。
2. Groupby(product).cumsum():但我无法将总和限制在最近的几分钟内。
可能需要某些平滑而性能不太差的方法,适用于相当大的df。
你有什么提示吗?
谢谢您的帮助。

你能不能先进行resample(5分钟),然后再进行滚动操作? - undefined
@DanailPetrov 谢谢你,但我需要一个滑动窗口,而不是固定的时间步长。 - undefined
1个回答

3
你可以使用pd.DataFrame.groupbygroupby.applypd.DataFrame.rolling按时间窗口(5分钟 == '5T')和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

我正在添加具体步骤,请查看是否与您的数据框有任何区别:

>>> 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

我注意到在values后面缺少了闭合括号,已经修复。
编辑:
这适用于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)

我猜想在你的原始数据框中,索引已经被设定为 DATETIME,如果是这样的话,你就不需要在最后加上 .values,也不需要使用 .set_index('DATETIME') 这一部分。 - undefined
你试过只运行右边的代码吗?我的意思是不将值赋给数据框,只运行右边的代码。如果是这样,是否也会报错? - undefined
我已经粘贴了我执行的确切步骤以获得结果,请告诉我我漏掉了什么。 - undefined
我明白了,我正在使用 1.2.0 版本。让我检查一下。虽然我以为它可以与任何 pandas 版本 >= 1 兼容。 - undefined
1
最后(对于1.0.5版本)的匹配行不正确,因为右侧是按PRODUCT分组的,并且在重置索引之后仍然保持分组。无论如何,在更新到1.2.0版本后,你提出的第一个方法似乎终于起作用了!谢谢你! - undefined
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接