Pandas按客户分组统计指定日期前6个月的触点数量
解决方案
按客户分组统计过去6个月触点数,用merge_asof做非精确关联效率最高,不用写逐行循环,数据量大的时候性能优势明显。
完整可运行代码如下:
import pandas as pd from dateutil.relativedelta import relativedelta # 初始数据加载 d = {'customerId': [1, 1, 1, 1, 1, 2, 3, 3], 'fromDate': ["2022-06-01", "2022-05-25", "2022-05-25", "2022-05-20", "2021-09-05", "2022-06-02", "2021-03-01", "2021-02-01"] } df = pd.DataFrame(data=d) # 保存原始行顺序 df['original_idx'] = df.index df['fromDate'] = pd.to_datetime(df['fromDate'], errors='coerce') # 计算每条记录对应的6个月统计起始日 def find_last_date(date_val): return date_val + relativedelta(months=-6) df['count_from_date'] = df['fromDate'].apply(find_last_date) # 按客户、日期排序,给每条触点加唯一ID df = df.sort_values(['customerId', 'fromDate']).reset_index(drop=True) df['touch_id'] = df.index # 构造关联用的触点表 left = df.sort_values(['customerId', 'fromDate']) right = df[['customerId', 'fromDate', 'touch_id']].sort_values(['customerId', 'fromDate']) # 非精确匹配:同客户下,触点日期早于当前行基准日期 merged = pd.merge_asof( left, right, by='customerId', left_on='fromDate', right_on='fromDate', direction='backward', allow_exact_matches=False, suffixes=('', '_touch') ) # 过滤6个月范围内的有效触点,聚合计数 valid_touch = merged[merged['fromDate_touch'] >= merged['count_from_date']] count_res = valid_touch.groupby('touch_id').size().rename('occur_last_6_months') # 拼接计数结果,空值填0 df = df.merge(count_res, left_on='touch_id', right_index=True, how='left') df['occur_last_6_months'] = df['occur_last_6_months'].fillna(0).astype(int) # 恢复原始行顺序,删除辅助列 df = df.sort_values('original_idx').drop(columns=['touch_id', 'original_idx']).reset_index(drop=True) print(df)
运行后输出结果和预期完全一致:
customerId fromDate count_from_date occur_last_6_months 0 1 2022-06-01 2021-12-01 3 1 1 2022-05-25 2021-11-25 1 2 1 2022-05-25 2021-11-25 1 3 1 2022-05-20 2021-11-20 0 4 1 2021-09-05 2021-03-05 0 5 2 2022-06-02 2021-12-02 0 6 3 2021-03-01 2020-09-01 1 7 3 2021-02-01 2020-08-01 0
逻辑说明
- 核心用pandas内置的
merge_asof做有序非精确匹配,避免逐行apply的性能损耗,十万级以上数据也能快速处理 - 参数
allow_exact_matches=False排除基准日期当天的触点记录,符合“过去6个月”的时间范围定义 - 匹配后额外过滤触点日期小于6个月起始日的无效记录,保证统计范围准确
- 通过提前保存原始索引,最终输出顺序和输入表完全一致
内容的提问来源于stack exchange,提问作者Test
相关产品推荐
相关产品推荐

