如何对Pandas分组应用带日期条件的函数标记重复活动
问题
我有一个包含name、date、activity、charge number列的Pandas DataFrame,需要新增repeated列,标记成员是否在30天窗口(当前日期前后15天)内重复同一活动。目前已经实现了单个用户的处理函数,但无法通过groupby语法批量处理数千个用户,求解决方法。
示例输入数据
| name | date | activity |
|---|---|---|
| alice | 2022-09-01 | run |
| alice | 2022-09-07 | run |
| bob | 2022-08-01 | run |
| char | 2022-10-02 | swim |
| bob | 2022-08-03 | run |
| char | 2022-10-01 | climb |
期望输出数据(含repeated列)
| name | date | activity | repeated |
|---|---|---|---|
| alice | 2022-09-01 | run | True |
| alice | 2022-09-07 | run | True |
| bob | 2022-08-01 | run | False |
| char | 2022-10-02 | swim | False |
| bob | 2022-10-01 | run | False |
| char | 2022-10-06 | climb | False |
| bob | 2022-10-15 | run | True |
现有单个用户处理代码
import pandas as pd def same_activity(df, x): time_start = x['date'] - pd.Timedelta(days=15) time_end = x['date'] + pd.Timedelta(days=15) events = df.loc[(df['date'] >= time_start) & (df['date'] <= time_end)]['activity'].isin([x['activity']]) return events.sum() > 1 df1['repeated'] = df1.apply(lambda r : same_activity(df1, r), axis=1)
解决方案
1. 预处理日期格式
先确保date列是datetime类型,否则后续时间操作会报错:
df['date'] = pd.to_datetime(df['date'])
2. 高效批量处理的两种方法
方法一:分组+时间滑动窗口
直接按「用户名+活动类型」分组,用Pandas的时间滚动窗口统计30天内的条目数,只要计数大于1就标记为重复:
df['repeated'] = ( df.groupby(['name', 'activity'])['date'] .rolling('30D', on='date', closed='both') .count() .reset_index(level=[0,1], drop=True) > 1 )
closed='both'确保窗口包含当前日期前后15天的所有条目(总跨度30天)- 这种方法自动处理每个用户的每个活动,无需逐行判断
方法二:排序+前后日期差对比
先排序再用shift对比相邻条目,性能比滚动窗口更优,适合大数据量:
# 按用户名、活动、日期排序 df_sorted = df.sort_values(['name', 'activity', 'date']) # 分组计算当前条目与上一个/下一个同活动条目的天数差 df_sorted['prev_day_diff'] = df_sorted.groupby(['name', 'activity'])['date'].diff().dt.days.fillna(999) df_sorted['next_day_diff'] = df_sorted.groupby(['name', 'activity'])['date'].diff(-1).dt.days.abs().fillna(999) # 只要前后15天内有同活动条目,就标记为True df_sorted['repeated'] = (df_sorted['prev_day_diff'] <= 15) | (df_sorted['next_day_diff'] <= 15) # 恢复原数据顺序(如果不需要排序后的结果) df = df_sorted.sort_index()
原方法效率低的原因
你之前的apply逐行处理,每一行都要全表扫描过滤日期,属于O(n²)的低效操作,用户数量增加后会明显卡顿。上面两种方法都是先分组再处理,时间复杂度降到O(n log n),几千个用户也能快速跑完。
内容的提问来源于stack exchange,提问作者kingoftheorchids
相关产品推荐
相关产品推荐

