首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >数分人必知必会 | 分析方法:同期群分析Cohort Analysis

数分人必知必会 | 分析方法:同期群分析Cohort Analysis

作者头像
做数据的二号姬
发布2025-08-15 11:51:09
发布2025-08-15 11:51:09
6200
举报

原创内容

No.769

数分人必知必会 | 分析方法:同期群分析Cohort Analysis

本周份的分析干货,供大家参考~

图片由夸克AI绘制

同期群分析是一种比较常见的分析方法,在互联网行业、信贷风控、产品优化、市场营销等领域都有着非常普遍的应用,在数分人必知必会的分析方法中,绝对要算一个必知必会的席位。

官方一点的对同期群分析的介绍是这样的:Cohort Analysis是一种数据分析方法,它将具有共同特征(通常指在同一时间段内首次发生某行为)的用户或对象划分为一个群体(即“同期群”),然后追踪并比较这些群体随时间变化的行为表现,从而揭示不同群体间的差异和演化规律。

所谓的同期群,其实就是按共同特征(如注册月份、首次购买时间、出生年份等)划分的用户群体,说得俗一点就是:具有可比性的群体。

绝大多数的分析方法说到底都是最朴素的逻辑,具有可比性。从逻辑学的角度来说,当且仅当两个(或多个)对象处于同一个“比较框架”之下,并且在该框架所规定的比较维度上,它们都确实“落在同一把尺子上”,我们才说它们“具有可比性”,缺了这把尺子,就谈不上比较真假、好坏、大小、优劣。只有同尺度、同维度、同标准的两个比较个体,才叫做具有可比性。

为什么要使用同期群分析呢,主要是处于下面愿意i你的考虑:

  • 避免整体数据误导:整体平均值(如“总用户留存率60%”)可能掩盖新老用户差异
  • 洞察用户生命周期:追踪用户从首次接触到长期留存/流失的全路径
  • 评估策略效果:比较不同时期/策略下的用户群表现(如改版前后的新用户留存)

同期群分析通常以 “时间” + “行为指标” 组合观察,比如:不同月份注册用户的月度留存率、不同渠道用户的首次购买后复购率等。通过细分用户生命周期,我们可以识别到增长机会、验证策略有效性,并避开整体数据的认知陷阱。尤其适用于产品优化、运营活动复盘和用户价值深度挖掘场景。

接下来我们用一个Python案例来介绍cohort分析:

在正式开始之前,我们需要生成一个虚拟的数据集,大概这样:

生成虚拟数据集的代码如下:

代码语言:javascript
复制
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
from operator import attrgetter

rng = np.random.default_rng(42)
n_users = 3000

# 随机注册日期:2023-01-01 到 2023-06-30
reg_dates = pd.to_datetime(rng.choice(pd.date_range('2023-01-01', '2023-06-30'), n_users))

# 每个用户随机在注册后 90 天内购买 1~10 次
records = []
for uid, reg inenumerate(reg_dates, start=1):
    n_orders = rng.integers(1, 11)
    order_dates = reg + pd.to_timedelta(rng.integers(0, 90, n_orders), unit='D')
    for d in order_dates:
        records.append({'user_id': uid,
                        'reg_date': reg.normalize(),
                        'order_date': d.normalize()})

df = pd.DataFrame(records)

然后构造一些需要的辅助列,对于这个虚拟数据集,需要这么几个辅助列:注册月份、下单月份、第N个月后下单:

辅助列构造的代码如下:

代码语言:javascript
复制
df['reg_period']   = df['reg_date'].dt.to_period('M')  # 注册月份
df['order_period'] = df['order_date'].dt.to_period('M') # 下单月份
df['cohort_index'] = (df['order_period'] - df['reg_period']).apply(attrgetter('n'))  # 第 N 个月

基于上面的辅助列,我们可以得到一个cohort表:也就是基于注册月份来看,当月下单、1个月后下单、2个月后下单的订单数:

实现的代码也比较简单:

代码语言:javascript
复制
cohort_table = (df.groupby(['reg_period', 'cohort_index'])
                  .agg(n_customers=('user_id', 'nunique'))
                  .reset_index())

接下来把首月人数合并进来做分母:

代码语言:javascript
复制
cohort_size = cohort_table[cohort_table['cohort_index'] == 0][['reg_period', 'n_customers']]
cohort_table = cohort_table.merge(cohort_size.rename(columns={'n_customers': 'cohort_size'}),
                                  on='reg_period')

cohort_table['retention_rate'] = cohort_table['n_customers'] / cohort_table['cohort_size']

然后把表格在做一次透视,形成一个比较方便作图的形式:

代码语言:javascript
复制
retention_pivot = cohort_table.pivot(index='reg_period',
                                     columns='cohort_index',
                                     values='retention_rate')

至此,数据处理的部分就完成了,接下来是数据可视化的部分工作了:

代码语言:javascript
复制
plt.rcParams['font.sans-serif'] = ['SimHei']        # 黑体
plt.rcParams['axes.unicode_minus'] = False          # 解决负号显示问题
plt.figure(figsize=(10, 6))
sns.heatmap(retention_pivot,
            annot=True,
            fmt='.1%',
            cmap='Reds',
            cbar_kws={'label': '留存率'})
plt.title('Cohort Analysis:按月注册用户的月度留存率')
plt.xlabel('生命周期月份')
plt.ylabel('注册月份')
plt.tight_layout()
plt.show()

最终的图大概是这样:

同样的,我们也可以用SQL写这个案例。

首先是创建一个表,写入一些随机数据作为案例数据集:

代码语言:javascript
复制
-- 生成 2023-01 ~ 2023-06 的 3 000 条模拟订单
INSERTINTO orders(user_id, order_dt)
SELECT
    u,
    d
FROM generate_series(1, 3000)          AS u,
     generate_series(
         '2023-01-01'::date+ (random()*180)::int,
         '2023-01-01'::date+ (random()*180)::int+ (random()*60)::int,
         interval'1 day')            AS d;

其他的处理方案和用Python也是比较类似的:

代码语言:javascript
复制
WITH
-- 计算首单日期(注册日期)
first_orders AS (
    SELECT
        user_id,
        MIN(order_dt) AS reg_date
    FROM orders
    GROUPBY user_id
), 
-- 给每条订单打「注册月份」和「生命周期月份」
order_period AS (
    SELECT
        o.user_id,
        fo.reg_date,
        date_trunc('month', fo.reg_date)            AS reg_month,
        date_trunc('month', o.order_dt)             AS order_month,
        (EXTRACT(year  FROM o.order_dt) -EXTRACT(year  FROM fo.reg_date))*12
        +EXTRACT(monthFROM o.order_dt) -EXTRACT(monthFROM fo.reg_date) AS cohort_index
    FROM orders o
    JOIN first_orders fo ON fo.user_id = o.user_id
), 
-- 统计每个注册月份的「总人数」与「次月留存人数」
cohort_size AS (
    SELECT reg_month, COUNT(DISTINCT user_id) AS users_total
    FROM order_period
    WHERE cohort_index =0
    GROUPBY reg_month
)
, cohort_retained AS (
    SELECT reg_month, COUNT(DISTINCT user_id) AS users_retained
    FROM order_period
    WHERE cohort_index =1      -- 次月
    GROUPBY reg_month
)
-- 计算留存率
SELECT
    cs.reg_month,
    cs.users_total,
    COALESCE(cr.users_retained, 0)                  AS retained_1m,
    ROUND(
        COALESCE(cr.users_retained, 0)::numeric
        / cs.users_total, 4)                        AS retention_rate_1m
FROM cohort_size cs
LEFTJOIN cohort_retained cr
       ON cr.reg_month = cs.reg_month
ORDERBY cs.reg_month;

和Python版本的案例类似,到这里数据本身就处理完了,接下来就是根据这些数据作图,作图本身还是Python作图会容易一些。

总的来说,不管是Python代码实现还是Excel实现,Cohort分析涉及的代码都比较简单。

Cohort分析真正的核心还是在于对于同期群,也就是对于可比群体的定义。Cohort定义必须稳定,不能中途变更,否则会导致数据不可比。

此外,也需要注意避免小样本Cohort的结论偏差(如某Cohort仅100人)。同一用户可能在多个Cohort中出现,需根据业务逻辑去重或合并。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 做数据的二号姬 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档