Pandas按ID分组判断1个月窗口内是否存在后续购买并新增left列
问题:Pandas按用户分组判断1个月窗口内是否存在后续复购记录
现有一个DataFrame df,结构如下:
ID purchase_date duration end_date 1_month 1 2021-04-03 4 2021-04-07 2021-05-07 1 2021-05-01 7 2021-05-08 2021-06-08 2 2021-07-01 10 2021-07-11 2021-08-11 1 2021-07-05 5 2021-07-10 2021-08-10
需新增名为left的列:若客户在当前行1_month对应的日期范围内存在后续购买记录,则该字段赋值为0;若无对应购买记录则赋值为1,目标效果如下:
ID purchase_date duration end_date 1_month left 1 2021-04-03 4 2021-04-07 2021-05-07 0 1 2021-05-01 7 2021-05-08 2021-06-08 1 2 2021-07-01 10 2021-07-11 2021-08-11 1 1 2021-07-05 5 2021-07-10 2021-08-10 1
约束规则
- 需基于
1_month列按ID分组,判断当前行之后的1个月窗口内该客户是否存在其他购买记录,逻辑需同时兼容无后续购买、存在多次购买的客户场景。 - 仅存在1条购买记录的客户,
left值统一赋值为1,这类客户不存在窗口内复购行为。 - 数据时间范围为2021-01-01至2022-01-01,需覆盖所有购买记录(含每个客户最后一条购买记录)的校验。
实现方案
使用merge_asof做向量化非等值连接,性能远高于逐行apply,适配百万级数据量场景:
- 首先统一日期列格式,避免类型错误
import pandas as pd # 转换所有日期列为datetime类型 date_columns = ['purchase_date', 'end_date', '1_month'] df[date_columns] = df[date_columns].apply(pd.to_datetime)
- 排序后做非等值匹配,查找当前行之后的最近一次购买记录
# 按用户ID、购买时间排序,保证匹配顺序正确 df = df.sort_values(['ID', 'purchase_date']).reset_index(drop=True) # 构造复购匹配表 repurchase_records = df[['ID', 'purchase_date']].rename(columns={'purchase_date': 'next_purchase'}) # 按用户分组,匹配当前购买时间之后的最近一次购买 df = pd.merge_asof( df, repurchase_records, left_on='purchase_date', right_on='next_purchase', by='ID', direction='forward', # 仅匹配当前行之后的记录 allow_exact_matches=False # 排除当前行自身 )
- 按规则赋值
left列
# 默认所有记录left为1(无复购) df['left'] = 1 # 若找到的后续购买时间落在1_month窗口内,赋值为0 df.loc[df['next_purchase'] <= df['1_month'], 'left'] = 0 # 删除临时匹配列 df = df.drop(columns='next_purchase')
场景覆盖说明
- 单条记录客户:无后续匹配结果,
next_purchase为空,left自动为1,符合要求 - 多次购买客户:自动匹配当前行之后最早的购买记录,只要落在窗口内就标记为0
- 客户最后一条购买记录:无后续购买记录,自动标记为1,符合边界要求
- 多次复购场景:仅判断窗口内是否存在购买,不限制复购次数,逻辑兼容
内容的提问来源于stack exchange,提问作者Databoi
相关产品推荐
相关产品推荐

