📊 第9章 网站 App 平台注册用户分析
📄 一句话概括

五年注册人数从 30 涨到 92,涨了 3.07 倍。 同比增长从 40% 一路降到 17.95%——绝对人数在涨,涨得越来越慢。 同比看节奏、定比看累计,两个指标一起看才不会误判。

📝 本章和前面几章的关系

上一篇把数据洗干净了。这一篇开始算:先按年看总量和增长。 用的还是那 300 条正常数据,2021 到 2025。

一、先按年数一数

groupby("year").size() 一句就出五年的数。 2021 年 30 人、2022 年 42、2023 年 58、2024 年 78、2025 年 92。 五年翻了 3.07 倍,占比从一成涨到三成。

光看这一列,结论会是「一年比一年好」。但这只是人数,还不是增长。

二、增长了多少:同比

同比就是今年比去年:(今年减去年) 除以去年。 2022 年 +40.00%,2023 年 +38.10%,2024 年 +34.48%,2025 年 +17.95%。 一路往下掉。2025 年那一栏是 17.95%,比前一年少了十六个点。

绝对人数还在涨,涨得却越来越慢。这叫「基数变大、增速放缓」。 它不是业务变差,是数学必然。一千人涨四成要涨四百,一万人涨四成要涨四千。

三、定比:把五年拉成一条线

以 2021 年为 100,后面每年除以它再乘 100。 2022 年 140.00,2023 年 193.33,2024 年 260.00,2025 年 306.67。 2025 年的定比是 306.67,意思是比 2021 年多了 206.67%。

定比的好处是一眼看累计:五年翻了三倍,比逐年读同比增长快得多。 同比看节奏、定比看累计。第 7 章讲过的那三个指标,项目里就是这么用的。

四、SQL 也能算,但口径要对

同一份活,group by 加 count(*) 也能出,一句 SQL 的事。 但这次 SQL 算出来的 2023 年是 63,pandas 那份是 58,差 5 条。 因为 SQL 查的是洗过的 users_clean,多了 5 条渠道为空的记录;pandas 那份是原始 300 条。

口径不同,数就不能直接对。先确认两边算的是同一张表,再比数。 真实项目里这种「两个数对不上」十有八九是口径问题,不是算错。

五、动手 Demo:年度注册用户分析

按年 groupby 出人数,再算同比和定比,最后用 SQL 复核一遍。 重点是那个「人数涨、增速降」的组合结论。

import numpy as np
import pandas as pd

rng = np.random.default_rng(2026)
plan = [(2021, 30), (2022, 42), (2023, 58), (2024, 78), (2025, 92)]
rows = []
uid = 1
for year, n in plan:
    for _ in range(n):
        rows.append((uid, "用户%03d" % uid, "%d-06-15 10:00:00" % year))
        uid += 1
df = pd.DataFrame(rows, columns=["user_id", "user_name", "reg_time"])
df["year"] = df["reg_time"].str.slice(0, 4).astype(int)

cnt = df.groupby("year").size()
print("合计 %d 人" % cnt.sum())
print("从 %d 涨到 %d,翻了 %.2f 倍"
      % (cnt.iloc[0], cnt.iloc[-1], cnt.iloc[-1] / cnt.iloc[0]))

grow = (cnt.pct_change() * 100).round(2)
base = (cnt / cnt.iloc[0] * 100).round(2)
out = pd.DataFrame({"人数": cnt, "同比%": grow, "定比": base})
print(out.to_string())

print("定比 %.2f,比首年高 %.2f%%"
      % (base.iloc[-1], base.iloc[-1] - 100))

实跑输出:

--------------------------------------------------------------------
年度注册用户分析
--------------------------------------------------------------------

  ① 先按年数一数
  --------------------------------------------------------------------
  五年一共 300 个注册用户。

| 年份 | 注册人数 | 占比 |
|---:|---:|---:|
| 2021 | 30 | 10.00% |
| 2022 | 42 | 14.00% |
| 2023 | 58 | 19.33% |
| 2024 | 78 | 26.00% |
| 2025 | 92 | 30.67% |

  人数一路涨,从 30 涨到 92,五年翻了 3.07 倍。

  ② 增长了多少
  --------------------------------------------------------------------

| 年份 | 人数 | 同比增长 |
|---:|---:|---:|
| 2021 | 30 | — |
| 2022 | 42 | +40.00% |
| 2023 | 58 | +38.10% |
| 2024 | 78 | +34.48% |
| 2025 | 92 | +17.95% |

  增速从 +40.00% 一路降到 +17.95%,绝对人数在涨,涨得却越来越慢。
  这是典型的「基数变大、增速放缓」,不是「业务变差」。
  ! 只看人数会以为一年比一年好,加上增速才看得出趋势在钝化。

  ③ 定比:以第一年为 100
  --------------------------------------------------------------------

| 年份 | 定比(2021 = 100) |
|---:|---:|
| 2021 | 100.00 |
| 2022 | 140.00 |
| 2023 | 193.33 |
| 2024 | 260.00 |
| 2025 | 306.67 |

  2025 年的定比是 306.67,比 2021 年多了 206.67%。
  定比把五年拉成一条线,一眼看出累计涨了多少。比逐年的同比更直观。
  ! 同比看节奏、定比看累计。第 7 章讲过的三个指标,在项目里就是这么用的。

  ④ 用 SQL 直接算
  --------------------------------------------------------------------

| 年份 | 人数 |
|---:|---:|
| 2021 | 30 |
| 2022 | 42 |
| 2023 | 63 |
| 2024 | 78 |
| 2025 | 92 |

  同一份活,SQL 也能干:group by 年份、count 计数。
  注意 2023 年这里是 63,上面 pandas 那份是 58。差了 5 条。
  因为 SQL 查的是洗过的 users_clean,多那 5 条渠道为空的记录;pandas 那份是原始 300 条。
  口径不同,数就不能直接对。先确认两边算的是同一张表,再比数。
  pandas 和 SQL 是两条路,选一条走到底,别混着来。
  ! 这次只有几百条,怎么走都行。真实项目里几百万条,就得先在库里聚合再拿出来。

pct_change() 算的是「比上一行变百分之几」,第一行没上一行,所以是 NaN。 size() 和 count() 不一样:size 数行数,count 只数非空值。这里要行数。 定比不减 100。它是指数,不是涨幅:306.67 是「涨到 3 倍」,不是「涨了 306%」。

30 秒实验

  1. 把 pct_change 换成 diff,看得到的是不是「净增人数」而不是百分比。
  2. 删掉 2025 年,只用四年重跑,看定比的基数变没变。
  3. 想一想:如果 2026 年只有 95 人,同比是多少?还能说「增长」吗?

常见误区

  1. 只看人数不看增速:人数年年涨,增速已经掉了一半。
  2. 把定比当涨幅:定比 306.67 是「涨到 3 倍」,涨幅是 206.67%。
  3. 同比定比混着比:同比是逐年,定比是固定基期,两者的数不能放一张表直接比。
  4. 两边表格口径不同还硬对:SQL 查洗过的表、pandas 用原始表,差 5 条很正常。
自测三问(点开对答案) 1. 五年涨了 3.07 倍,是怎么算的? —— 最后一年除以第一年:92 除以 30 等于 3.07。 2. 人数在涨、增速在降,这矛盾吗? —— 不矛盾。基数变大以后,同样的增长速度要增加的人数更多,增速自然会钝化。 3. 同比和定比各看什么? —— 同比看每年的增长节奏,定比看相对基期累计走了多远。

年度看完了,下一篇换到更细的粒度:按月、按渠道、按城市。

相关笔记