如何用Pandas DataFrame统计近30天内的记录出现次数
解决Pandas中按ID统计近30天内出现次数的问题
步骤1:确保日期列是datetime类型
首先需要将字符串格式的日期转换为Pandas的datetime类型,否则无法进行时间运算:
import pandas as pd # 构造示例数据(匹配你的需求场景) data = { 'ID': ['001', '001', '001', '002', '002', '002'], 'date': ['2022-01-01', '2022-01-04', '2022-02-05', '2022-01-02', '2022-01-28', '2022-03-01'] } df = pd.DataFrame(data) # 转换日期列 df['date'] = pd.to_datetime(df['date'])
步骤2:按ID分组+时间窗口滚动统计
使用groupby按ID分组,结合rolling的时间窗口功能,指定窗口为30天,同时设置closed='left'排除当前行(因为我们要统计的是当前日期之前30天内的记录):
# 先按ID和日期排序,确保滚动窗口计算逻辑正确 df = df.sort_values(['ID', 'date']) # 计算近30天内的出现次数 df['occurrences_last_month'] = df.groupby('ID')['date'].rolling('30D', closed='left').count().reset_index(level=0, drop=True)
执行后得到的结果完全匹配预期:
| ID | date | occurrences_last_month | |
|---|---|---|---|
| 0 | 001 | 2022-01-01 | 0.0 |
| 1 | 001 | 2022-01-04 | 1.0 |
| 2 | 001 | 2022-02-05 | 1.0 |
| 3 | 002 | 2022-01-02 | 0.0 |
| 4 | 002 | 2022-01-28 | 1.0 |
| 5 | 002 | 2022-03-01 | 0.0 |
为什么你的方法没生效?
- 未按ID分组:直接对整个DataFrame计算会把不同ID的记录混在一起统计,结果自然错误。
- 滚动窗口参数错误:如果没设置
closed='left',默认会包含当前行,导致计数多1;或者误用了行数窗口而非时间窗口('30D')。 - 日期未排序:滚动窗口依赖有序的日期,未排序会导致统计范围混乱。
备选方法(小数据量适用)
如果数据量不大,也可以用apply逐行计算,逻辑更直观,但效率低于滚动窗口:
df['occurrences_last_month'] = df.apply( lambda row: len(df[(df['ID'] == row['ID']) & (df['date'] >= row['date'] - pd.Timedelta(days=30)) & (df['date'] < row['date'])]), axis=1 )
内容的提问来源于stack exchange,提问作者datadatadata
相关产品推荐
相关产品推荐

