用代码固定定义并重新计算指标
目标
根据“Moanoteu”16 周的产品记录,编写按照定义计算 DAU、WAU、MAU、粘性、每周共享用户和 7 天激活率的函数,并测量定义变化时数字会晃动多少。
为什么重要
指标只有在写下了定义时才是数字。内部账户、时区、去重、活跃标准,只要其中一项不同,同一份记录就会得出完全不同的趋势。创业早期要用这些数字决定投资和招聘,所以把定义固定在代码里、重新计算并得出相同的值,这种习惯就是产品判断的底线。
材料与定义
/opt/fixtures/founder/product/users.csv—user_id,signup_at,is_internal(时间为 UTC,末尾带 Z)/opt/fixtures/founder/product/events.csv—user_id,ts,event(event:session_start、create_doc、share_doc、invite_sent、upgrade)- 业务时区是 Asia/Seoul(UTC+9)。日期是首尔日期,一周从首尔时间星期一 00:00 开始,第 0 周是 2026-03-02(第 0–15 周)。
- 所有指标都排除内部账户(is_internal=1)。活跃 = 在该时间段内
session_start至少 1 次。按人数统计。 - 所有函数的第一个参数都是材料目录路径(评分器也会用其他材料来调用)。日期参数是像
"2026-06-14"这样的字符串。
步骤
- 在
/root/founder/metrics/summary.json中写入材料概况:users(全部用户数)、internal_users、events(全部事件行数)、event_counts(按事件种类统计行数的对象)。 - 在
/root/founder/metrics/metrics.py中创建dau(fix, day)——在首尔日期day有 session_start 的外部用户数(整数)。 - 在
/root/founder/metrics/internal.json中写入 2026-06-14 的dau_all(含内部账户)、dau_external(排除)、inflation_pct(= (dau_all − dau_external) / dau_external × 100,在小数点后第二位四舍五入)。 - 在
metrics.py中加入wau(fix, day)、mau(fix, day)——包含day在内向前回溯 7 天、28 天内的活跃外部用户数。 - 在
metrics.py中加入stickiness(fix, day)——截至day的 28 天内 DAU 的平均值 ÷mau(fix, day),在小数点后第四位四舍五入。 - 在
/root/founder/metrics/definitions.json中,以三种定义写入以 2026-06-14 为基准的 WAU:session(session_start)、any_event(不论事件种类)、core(share_doc)。均为外部用户,按人数。 - 在
metrics.py中加入weekly_sharers(fix)——把第 0–15 周各自“该周做过 share_doc 的外部用户数”,以像{"0": n, "1": n, ...}这样的字符串周次键的字典返回。 - 在
metrics.py中加入activation(fix)(注册周为 0–11 的外部用户中,从注册时刻起 7×24 小时内做过 create_doc 的比率 →{"signups": n, "activated": m, "rate": 0.0000}),并在/root/founder/metrics/report.json中汇总写入 2026-06-14 的dau、wau、mau、stickiness、activation_rate、north_star_peak_week(每周共享用户最多的周次,整数)、north_star_week15(第 15 周的值)。
参考
- 首尔日期:
datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc).astimezone(ZoneInfo("Asia/Seoul")).date() - 周次:
(서울시각 - datetime(2026, 3, 2, tzinfo=서울)).days // 7 - 常见错误:按 UTC 日期归组,把事件数写成人数,不排除内部账户,用 30 天或日历月来统计 MAU,用一天的 DAU 去除粘性。
- 只用标准库(csv、datetime、zoneinfo、collections)就够了。也可以用 sqlite3 CLI 来确认。
先清点材料
在 /root/founder/metrics/summary.json 中写入 users、internal_users、events、event_counts。
用 csv.DictReader 读取两个文件,再用 collections.Counter 统计事件种类即可。is_internal 是字符串 "1"。
DAU——首尔日期,外部用户,按人数
在 /root/founder/metrics/metrics.py 中创建 dau(fix, day)。在首尔日期 day 有 session_start 的外部用户数。
把 UTC 时间转换成 Asia/Seoul 后,用 .date() 归组,把用户 id 收集到 set 中,统计其大小。内部账户通过 users.csv 的 is_internal 过滤。
内部账户把指标虚增了多少
在 /root/founder/metrics/internal.json 中写入 2026-06-14 的 dau_all、dau_external、inflation_pct。
在同一天、同一个定义(session_start)下,只改变是否包含内部账户,统计两次。比率的分母是外部用户的 DAU。
WAU、MAU——包含基准日的 7 天、28 天
在 metrics.py 中加入 wau(fix, day)、mau(fix, day)。包含 day 在内向前回溯 7 天、28 天内的活跃外部用户数。
先建好每天的活跃集合,再统计 day、day-1、……、day-6(或 -27)的并集大小。不是日历月,也不是 30 天。
粘性——28 天平均 DAU ÷ MAU
在 metrics.py 中加入 stickiness(fix, day)。把截至 day 的 28 天内 DAU 的平均值除以 mau(fix, day),并在小数点后第四位四舍五入。
如果除以当天一天的 DAU,会因星期几而上下起伏。把 28 天各自的 DAU 相加再除以 28,用这个平均值。
只改变活跃的定义,统计同一个窗口
在 /root/founder/metrics/definitions.json 中,以 session、any_event、core(share_doc)三种定义,写入以 2026-06-14 为基准的 7 天窗口的外部用户数。
窗口和用户过滤保持不变,只改变统计的事件种类。any_event 不区分事件种类。
North Star 候选——每周共享用户
在 metrics.py 中加入 weekly_sharers(fix)。以字符串周次键的字典,返回第 0–15 周各自的 share_doc 外部用户数。
周次是 (首尔时间 − 2026-03-02 00:00 首尔).days // 7。没有事件的周也用 0 填满全部 16 个键。
激活率和一页报告
在 metrics.py 中加入 activation(fix),并在 /root/founder/metrics/report.json 中汇总 dau、wau、mau、stickiness、activation_rate、north_star_peak_week、north_star_week15。
激活不是按日历日期,而是从注册时刻起 7×24 小时(timedelta(days=7))内的第一次 create_doc。对象是注册周为 0–11 的外部用户。如果最多的周有多个,就取靠前的周次。