五年注册人数从 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 秒实验
- 把 pct_change 换成 diff,看得到的是不是「净增人数」而不是百分比。
- 删掉 2025 年,只用四年重跑,看定比的基数变没变。
- 想一想:如果 2026 年只有 95 人,同比是多少?还能说「增长」吗?
常见误区
- 只看人数不看增速:人数年年涨,增速已经掉了一半。
- 把定比当涨幅:定比 306.67 是「涨到 3 倍」,涨幅是 206.67%。
- 同比定比混着比:同比是逐年,定比是固定基期,两者的数不能放一张表直接比。
- 两边表格口径不同还硬对:SQL 查洗过的表、pandas 用原始表,差 5 条很正常。
自测三问(点开对答案)
1. 五年涨了 3.07 倍,是怎么算的? —— 最后一年除以第一年:92 除以 30 等于 3.07。 2. 人数在涨、增速在降,这矛盾吗? —— 不矛盾。基数变大以后,同样的增长速度要增加的人数更多,增速自然会钝化。 3. 同比和定比各看什么? —— 同比看每年的增长节奏,定比看相对基期累计走了多远。年度看完了,下一篇换到更细的粒度:按月、按渠道、按城市。
- ☐ (本篇完,下一篇 9.5 新注册用户分析与小结)