如何使用Pandas计算用户n日内留存标识?
Pandas实现用户n天留存标识的最优方法
问题背景
现有如下结构的DataFrame(注意原数据中2020-15-01是日期格式错误,应为2020-01-15;另外示例中2020-10-01到2020-11-01间隔31天,不符合3天留存逻辑,推测是笔误):
date | user_id | purchase 2020-01-01 | 1 | 10 2020-10-01 | 1 | 12 2020-01-15 | 1 | 5 2020-11-01 | 2 | 500
需要为每个user_id的每条记录添加n天留存标识,判断该记录日期之后的n天内,用户是否有其他购买行为,输出1(有)或0(无)。
最优实现方案
推荐使用merge_asof方法,它基于排序后的高效合并,适合处理大数据量,步骤如下:
1. 预处理:修正日期格式并排序
首先将date列转换为datetime类型,修正错误日期,再按user_id和date排序(merge_asof要求必须排序):
import pandas as pd # 构造修正后的示例数据 data = { 'date': ['2020-01-01', '2020-10-30', '2020-01-15', '2020-11-01'], 'user_id': [1, 1, 1, 2], 'purchase': [10, 12, 5, 500] } df = pd.DataFrame(data) # 转换日期为datetime类型 df['date'] = pd.to_datetime(df['date']) # 按用户ID和日期排序 df = df.sort_values(['user_id', 'date']).reset_index(drop=True)
2. 使用merge_asof匹配后续购买记录
复制一份数据作为后续购买的匹配源,通过merge_asof找到每条记录之后的第一条购买记录,再判断是否在n天窗口内:
n_days = 3 # 复制数据用于匹配后续购买 df_next = df[['user_id', 'date']].rename(columns={'date': 'next_purchase_date'}) df_next = df_next.sort_values(['user_id', 'next_purchase_date']) # 合并:找到每条记录之后的第一条购买记录(排除自身) merged_df = pd.merge_asof( df, df_next, on='date', by='user_id', direction='forward', # 匹配当前日期之后的记录 allow_exact_matches=False # 不匹配同一日期的自身记录 ) # 计算n天留存标识:判断后续购买日期是否在当前日期+n天内 merged_df[f'{n_days}D_retention'] = ( merged_df['next_purchase_date'] <= merged_df['date'] + pd.Timedelta(days=n_days) ).astype(int) # 清理多余列并还原顺序 result = merged_df.drop('next_purchase_date', axis=1)[['date', 'user_id', 'purchase', f'{n_days}D_retention']]
3. 结果示例
运行后得到的结果:
date user_id purchase 3D_retention 0 2020-01-01 1 10 0 1 2020-01-15 1 5 0 2 2020-10-30 1 12 1 3 2020-11-01 2 500 0
方案优势
- 高效性:
merge_asof是基于排序的线性时间复杂度合并,比逐行遍历或apply的方法快得多,适合处理百万级以上数据。 - 准确性:通过
allow_exact_matches=False排除自身记录,避免误判同一日期的购买行为。 - 扩展性:只需修改
n_days参数即可实现任意天数的留存计算。
内容的提问来源于stack exchange,提问作者titutubs
相关产品推荐
相关产品推荐

