TT Lab
开始
学习 学习路径 课程

开发者创业 — 先验证再动手

搭建留存三角表,用数字看清三个陷阱

在 TT Lab 中继续学习

目标

用“Moanoteu”的每周注册同期群构建留存三角形,用数字确认分母、空格、幸存者这三个陷阱,然后依据正确的加权留存率和按注册渠道的留存率来作判断。

为什么重要

总的活跃数把新进来的人和离开的人混在同一个数字里。要把同一周注册的人分开追踪,才能看出产品是否留住了人。而且这个计算,只要改变分母,或者把空格填成 0,就很容易变好或变差——它牵系着广告费和路线图,所以必须按定义重新计算。

材料与定义

步骤

  1. 在 /root/founder/cohort/sizes.json 中,以 {"0": n, ..., "11": n} 的形式写入各同期群的注册人数。
  2. 在 /root/founder/cohort/cohort.py 中创建 retention(fix, max_n)——{"0": [r0, r1, ..., r_max_n], ...},尚未观测的格子为 None。
  3. 在 /root/founder/cohort/denominator.json 中,以两种分母写入同期群 4 的第 4 周留存率:rate_cohort_size(正确的分母)、rate_week0_active(以第 0 周活动者为分母——故意犯的错误)。
  4. 在 /root/founder/cohort/censor.json 中,以两种方法写入第 6 周留存率:pooled_rate(只含观测完毕的同期群,按人数加权)、naive_rate_with_zeros(所有同期群,尚未观测的格子按 0 处理),以及 eligible_cohorts(观测完毕的同期群数)。
  5. 在 /root/founder/cohort/survivor.json 中,以两份名单写入第 4 周留存率:all_users_rate(同期群 0–11 的全体,只含观测完毕的同期群)、survivors_only_rate(只挑出在第 15 周有活动的人,做同样的计算)、survivors(这些人的人数)。
  6. 在 cohort.py 中加入 pooled(fix, n, unbounded=False)——只收集观测完毕的同期群、按人数加权的留存率 {"cohorts": k, "users": u, "retained": r, "rate": 0.0000}。unbounded 为真时,按“在 c+N 周之后的任何一周(含 c+N)有活动”来统计。
  7. 在 /root/founder/cohort/channel.json 中,以 {"organic_search": r, ...} 的形式,写入按注册渠道(最后接触点)的第 4 周加权留存率,共五个渠道。
  8. 在 /root/founder/cohort/report.json 中写入 curve(n=0..8 的 bounded 加权留存率 9 个)、week4、week4_unbounded、flatten_week(与上一周相比下降小于 0.02 的第一个 n,1 以上)、best_channel、worst_channel。

参考

各同期群的注册人数

在 /root/founder/cohort/sizes.json 中,以字符串键写入按注册周次(0–11)统计的外部注册用户数。

把 signup_at 转换为首尔时间,计算距 2026-03-02 有多少天,再除以 7 所得的商就是同期群。排除内部账户。

留存三角形——尚未观测的格子为 None

在 /root/founder/cohort/cohort.py 中创建 retention(fix, max_n)。同期群字符串键 → n=0..max_n 的留存率列表,c+n>15 的格子为 None。

先为每个人建立有 session_start 的周次集合。分母是同期群的注册人数,尚未观测完毕的格子不是 0,而是 None。

改变分母,留存率就显得更好

在 /root/founder/cohort/denominator.json 中,以 rate_cohort_size 和 rate_week0_active 两种分母,写入同期群 4 的第 4 周留存率。

分子相同(周次 8 有活动的同期群 4 的人)。只把分母换成注册人数和第 0 周(周次 4)的活动者数,试一试。

把尚未观测的格子填成 0,曲线就会虚假地折下去

在 /root/founder/cohort/censor.json 中写入第 6 周留存率的 pooled_rate、naive_rate_with_zeros、eligible_cohorts。

正确的一边,只收集 c+6 ≤ 15 的同期群,用全部留存人数 ÷ 全部注册人数。错误的一边,把所有同期群的注册人数都放进分母(尚未观测的人被算作留存 0)。

只看现在剩下的人,过去就显得更好

在 /root/founder/cohort/survivor.json 中,以 all_users_rate(全体)和 survivors_only_rate(只含第 15 周有活动的人)写入第 4 周加权留存率,并写入 survivors(这些人的人数)。

两种计算的同期群和周次规则相同,只是人的名单不同。名单原则上要在注册时点就固定,所以第二个数字是故意犯的错误。

加权留存率函数——bounded 与 unbounded

在 cohort.py 中加入 pooled(fix, n, unbounded=False)。只含观测完毕的同期群,按人数加权,返回 {cohorts, users, retained, rate}。

不是同期群比率的简单平均,而是留存人数之和 ÷ 注册人数之和。unbounded 看的是在 c+n 周及其之后的任何一周是否有过活动。

按注册渠道的第 4 周留存率

在 /root/founder/cohort/channel.json 中,写入最后接触点的五个渠道各自的第 4 周加权留存率。

在 touches.csv 中,每个人 ts 最晚的那一行的 channel 就是注册渠道。只把名单缩小到该渠道的人,做与 pooled 相同的计算。

把曲线和判断放在一页上

在 /root/founder/cohort/report.json 中写入 curve(n=0..8)、week4、week4_unbounded、flatten_week、best_channel、worst_channel。

flatten_week 是从 n=1 开始看,curve[n-1] − curve[n] < 0.02 的第一个 n。渠道取第 7 步结果中最高的和最低的。