同期群是按用户首次行为时间分组后观察其后续各周期留存表现的分析方法;必须先计算每个用户的first_active_date作为cohort_date,再算相对天数,而非直接groupby user_id 或 date。

什么是同期群(Cohort)以及为什么不能直接用 groupby
同期群分析本质是按用户首次行为时间分组,再观察他们在后续各周期的留存表现。直接对 df.groupby('user_id') 或 df.groupby('date') 无法建模“首日”和“第N日”的关系——关键在于先锚定每个用户的 first_active_date,再计算相对天数。
常见错误是把登录日期当同期群标签,结果混入了老用户;或者用 resample 按自然月聚合,丢失了用户粒度的时序路径。
- 必须为每个
user_id计算其最早出现的日期:df.groupby('user_id')['event_date'].min() - 将该日期广播回原表(用
map或merge),生成cohort_date列 - 用
(event_date - cohort_date).dt.days // 7得到“第几周”,避免手动算月份带来的不等长问题
pandas 中构建留存矩阵的三步核心操作
留存矩阵是同期群分析的输出形态:行是各 cohort(如“2024-01-01 cohort”),列是相对周期(如“第0周”“第1周”),值为该 cohort 在对应周期的活跃用户占比。
关键不是 pivot,而是先构造可 pivot 的三元组:cohort_date、cohort_period、user_id(去重后计数)。
- 添加
cohort_period列:df['cohort_period'] = ((df['event_date'] - df['cohort_date']) / np.timedelta64(1, 'D')).astype(int) - 用
df.groupby(['cohort_date', 'cohort_period'])['user_id'].nunique()得到原始频次 - 用
unstack(level=1, fill_value=0)转成宽表,再用首列(cohort_period == 0)做分母做广播除法:cohort_df.div(cohort_df.iloc[:, 0], axis=0)
如何处理非等长周期(比如按月但每月天数不同)
按自然月划分 cohort_period 容易导致“第1月”实际跨度从28到31天不等,影响跨 cohort 可比性。更稳健的做法是统一按“第N个日历月的第一天”对齐。
推荐用 pd.offsets.MonthBegin() 而非 strftime('%Y-%m'):
-
df['cohort_month'] = (df['first_active_date'] - pd.offsets.MonthBegin()).normalize()→ 对齐到月初 -
df['cohort_period_month'] = ((df['event_date'] - df['cohort_month']) / np.timedelta64(1, 'M')).astype(int)仍不精确,应改用:df['event_month'] = df['event_date'].dt.to_period('M')和df['cohort_month'] = df['first_active_date'].dt.to_period('M'),再相减得到整数月差 - 注意
to_period('M')相减结果是MonthEnd类型,需转.astype(int)
遇到 NaN 或 inf 留存率时怎么定位
出现 NaN 通常是因为某 cohort 在第0周期无数据(即 cohort_date 没匹配上任何 event_date),而 inf 多因分母为 0 —— 说明该 cohort 在首日没人活跃,但后续周期却有记录,意味着 first_active_date 计算逻辑和事件时间范围不一致。
- 检查
first_active_date是否来自同一事件表(比如用了注册表而非登录表) - 确认
event_date类型是datetime64[ns],否则减法返回timedelta64[ns]但除法可能隐式转为 float 出错 - 用
cohort_sizes = df.groupby('cohort_date')['user_id'].nunique()单独看每 cohort 首日规模,和留存矩阵首列比对是否一致
真正难的不是算出数字,而是确保 cohort_date 的定义和业务口径完全一致——比如“注册当天算第0天”还是“首次付费才算 cohort 起点”,这个逻辑一旦写死在代码里,后续所有分析都会偏移。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











