按月看,3 月和 9 月是两个尖峰——但这是造数据时写进去的。 按渠道看,前三名拿走七成七,剩下两个不到四分之一。 「其他」排第一是个坑:它是八个小城市合起来的,不该和单项放一张榜上比。
这一篇把粒度变细:按月看季节、按渠道看结构、按城市看集中度。 最后给整个项目收个尾:这个项目真正教会的是什么。
一、按月:两个尖峰
按月份分组,十二个月的人数一目了然。 3 月 37 人、9 月 39 人最高,2 月只有 10 人。 3 月和 9 月是两个尖峰,和「开学季、年初换工作」的直觉对得上。
但要说清楚:季节性是造数据时写进去的,真数据里有没有,得算完才知道。
二、渠道:前三名拿走七成七
搜索引擎 87 人占 29.00%,社交媒体 85 人占 28.33%,广告投放 59 人占 19.67%。 前三名合起来 77.00%,自然访问和老用户推荐加起来不到四分之一。 这就是第 7 章的贡献度分析:少数几项撑起大头,长尾一堆但分量轻。
结论往哪用?搜索引擎和社交媒体是主战场,广告投放性价比要单独算账。
三、城市:「其他」排第一是个坑
按城市数,「其他」59 人排第一,占 19.67%。 但它不是一座城,是八个小城市合起来的。 名义上的第一名名不副实。这是汇总分组的常见坑:合并项不该和单项比。
去掉「其他」,前三城是杭州 42、北京 39、成都 38,合起来 39.67%。 「其他」不能扔,也不能直接比。要么拆开,要么在结论里单独说明它的构成。
四、小结:这个项目真正教会什么
第一,数据不在手边时,先解决「怎么取」,再谈分析。取数是半个项目。 第二,连数据库只有一行代码,难的是知道库在哪、表怎么设计、字符集对不对。 第三,同一份数据,SQL 和 pandas 都能算,选一条路走到底。
第四,年度看趋势、月度看季节、渠道看结构,三个角度拼起来才是完整结论。 第五,每个数都要能说清口径:哪张表、哪个时间段、算的是行数还是非空值。
五、动手 Demo:新注册用户分析与小结
按月、按渠道、按城市各 groupby 一次,看三种粒度下的结论。 城市那一节会暴露「其他」这个合并项的坑。
import numpy as np
import pandas as pd
chan = ["搜索引擎", "社交媒体", "广告投放", "自然访问", "老用户推荐"]
cw = [0.32, 0.26, 0.18, 0.15, 0.09]
city = ["北京", "上海", "广州", "深圳", "杭州", "成都", "武汉", "其他"]
dw = [0.16, 0.14, 0.11, 0.12, 0.10, 0.09, 0.08, 0.20]
rng = np.random.default_rng(2026)
plan = [(2021, 30), (2022, 42), (2023, 58), (2024, 78), (2025, 92)]
w = np.array([0.5, 0.6, 1.5, 1.0, 0.9, 0.8, 0.9, 1.1, 1.4, 1.0, 0.9, 1.0])
w = w / w.sum()
rows = []
uid = 1
for year, n in plan:
for m in rng.choice(np.arange(1, 13), size=n, p=w):
day = int(rng.integers(1, 29))
hh = int(rng.integers(0, 24))
mm = int(rng.integers(0, 60))
rows.append((uid, "用户%03d" % uid,
"%04d-%02d-%02d %02d:%02d:00" % (year, m, day, hh, mm),
str(rng.choice(chan, p=cw)), str(rng.choice(city, p=dw))))
uid += 1
df = pd.DataFrame(rows, columns=["user_id", "user_name", "reg_time",
"channel", "city"])
df["month"] = df["reg_time"].str.slice(5, 7).astype(int)
mc = df.groupby("month").size()
print("最高 %d 月 %d 人,最低 %d 月 %d 人"
% (mc.idxmax(), mc.max(), mc.idxmin(), mc.min()))
cc = df.groupby("channel").size().sort_values(ascending=False)
print("渠道前三合起来 %.2f%%" % (cc.iloc[:3].sum() / len(df) * 100))
ct = df.groupby("city").size().sort_values(ascending=False)
print("排第一的是 %s,%d 人" % (ct.index[0], ct.iloc[0]))
real = ct.drop("其他")
print("去掉其他,前三城 %s 合起来 %.2f%%"
% ("、".join(real.index[:3]), real.iloc[:3].sum() / len(df) * 100))
实跑输出:
--------------------------------------------------------------------
新注册用户分析与小结
--------------------------------------------------------------------
① 按月看:哪几个月人多
--------------------------------------------------------------------
| 月份 | 注册人数 |
|---:|---:|
| 1 月 | 12 |
| 2 月 | 10 |
| 3 月 | 37 |
| 4 月 | 29 |
| 5 月 | 25 |
| 6 月 | 23 |
| 7 月 | 23 |
| 8 月 | 19 |
| 9 月 | 39 |
| 10 月 | 31 |
| 11 月 | 20 |
| 12 月 | 32 |
最高 9 月 39 人,最低 2 月 10 人。
3 月和 9 月是两个尖峰,和「开学季、年初换工作」的直觉对得上。
! 季节性是造数据时写进去的。真数据里有没有,得算完才知道,不能先认定。
② 渠道:新用户从哪来
--------------------------------------------------------------------
| 渠道 | 人数 | 占比 |
|---|---:|---:|
| 搜索引擎 | 87 | 29.00% |
| 社交媒体 | 85 | 28.33% |
| 广告投放 | 59 | 19.67% |
| 自然访问 | 42 | 14.00% |
| 老用户推荐 | 27 | 9.00% |
第一名 搜索引擎 占 29.00%,前三名合起来 77.00%。
五个渠道,前三名拿走七成七,剩下两个不到四分之一。
这就是第 7 章的贡献度分析:少数几项撑起大头,长尾一堆但分量轻。
③ 城市:集中在哪
--------------------------------------------------------------------
| 城市 | 人数 | 占比 |
|---|---:|---:|
| 其他 | 59 | 19.67% |
| 杭州 | 42 | 14.00% |
| 北京 | 39 | 13.00% |
| 成都 | 38 | 12.67% |
| 上海 | 37 | 12.33% |
| 广州 | 32 | 10.67% |
| 深圳 | 32 | 10.67% |
| 武汉 | 21 | 7.00% |
「其他」排第一,占 19.67%,但它不是一座城,是八个小城市合起来的。
名义上的第一名名不副实。这是汇总分组的常见坑:合并项不该和单项放在一张榜上比。
去掉「其他」,前三城是 杭州、北京、成都,合起来 39.67%。
! 「其他」不能扔,也不能直接比。要么拆开,要么在任何结论里单独说明它的构成。
④ 小结:这个项目教会什么
--------------------------------------------------------------------
第一,数据不在手边时,先解决「怎么取」,再谈分析。取数是半个项目。
第二,连数据库只有一行代码,难的是知道库在哪、表怎么设计、字符集对不对。
第三,同一份数据,SQL 和 pandas 都能算,选一条路走到底。
第四,年度看趋势、月度看季节、渠道看结构,三个角度拼起来才是完整结论。
! 下一章换到电商销售数据,不再连库,改从 Excel 读——那是另一套麻烦。
sort_values(ascending=False) 之后 iloc[:3] 才是前三名,不排序拿的是前三行。
ct.drop("其他") 这一句是本节的重点:把合并项摘掉,排行榜才说得清。
join(real.index[:3]) 把三个城市名用顿号连起来,比逐个 %s 干净。
30 秒实验
- 把「其他」的权重从 0.20 降到 0.05,重跑,看城市榜怎么变。
- 把月份权重改成平均,看还有没有尖峰。
- 想一想:如果老板问「哪个渠道最值得加预算」,光有这五个数够不够?
常见误区
- 把「其他」当成一座城:它是合并项,和单项比没有意义。
- 不排序就取前三:
iloc[:3]取的是前三行,不是前三名。 - 看到季节尖峰就下结论:先确认数据里真有这个机制,再解释原因。
- 只报一个角度:年度、月度、渠道、城市各说一句,才叫完整的项目结论。
自测三问(点开对答案)
1. 为什么「其他」排第一不能当结论? —— 它是八个小城市合并出来的汇总项,和单个城市不在一个量级上比。 2. 渠道分析该往哪用? —— 看主战场在哪、长尾占多少,再加成本数据才能谈「值不值得投」。 3. 一个完整的项目结论至少要有几个角度? —— 这次是四个:年度趋势、月度季节、渠道结构、城市集中度。少一个都片面。第 9 章收尾。第 10 章换到电商销售数据:不再连库,改从 Excel 读,还要做预测。
- ☐ (本篇完,下一篇 10.1 项目概述与分析方法)