第13章封面

学了 12 章的招式,是时候打真仗了。第 13 章用五个真实数据集(都公开可下载)演示完整的分析流程——每个案例都是「读入 → 清洗 → 变形 → 聚合 → 可视化」的一次实战演练。强烈建议全部亲手复现。

🌍 战役一:Bitly / USA.gov 点击流

数据:2011 年短链接服务 Bitly 的 US.gov 点击流,每行一个 JSON。

剧情:展示「没有 pandas 也能干活」→ 再展示「有 pandas 快十倍」:

# 纯 Python 统计时区(Counter 出场)
from collections import Counter
time_zones = [rec["tz"] for rec in records if "tz" in rec]
Counter(time_zones).most_common(10)

# pandas 版:三行搞定同样的事
frame = pd.DataFrame(records)
tz_counts = frame["tz"].value_counts()
tz_counts[:10].plot.barh()         # 横向条形一目了然

学到value_counts() + 条形图是分类变量分析的最小闭环;fillna("Missing") + str.contains 处理缺失/异常标签的标准流程。

🎥 战役二:MovieLens 电影评分

数据:6040 个用户对 3700 部电影的 100 万条评分(users/movies/ratings 三张表)。

剧情:三表 merge 大联欢 + 透视表:

data = pd.merge(pd.merge(ratings, users), movies)   # 三表连成一张
mean_ratings = data.pivot_table("rating", index="title",
                                columns="gender", aggfunc="mean")

名场面是「男女观众评价分歧最大的电影」:先过滤评分数 ≥250 的电影(groupby(title).size()),再用男女均分之差排序——书中展示的《异形2》等榜单至今有趣。

学到:merge 链式连接多表;「按组计数再过滤」的可靠性思维(样本太少的评分没有意义);std() 看评分分歧。

👶 战役三:美国新生儿名字 1880–2010

数据:130 年每年一个 yobYYYY.txt(名字、性别、数量)。

剧情pd.concat 把 131 个文件拼成大表,加 year 列,然后玩出花:

pieces = []
for year in range(1880, 2011):
    frame = pd.read_csv(f"yob{year}.txt", names=["name","sex","births"])
    frame["year"] = year
    pieces.append(frame)
names = pd.concat(pieces, ignore_index=True)   # 169 万行名字

# 全名占比( popularity = 出生数 / 当年总数 )
names["prop"] = names.groupby(["year", "sex"])["births"].transform(
    lambda g: g / g.sum())

# 画「各年 Top1000 名字的总占比」曲线 → 最后 25% 的孩子叫什么无人知晓

名场面:「名字末字母的流行度变迁」——1990 年后 L 开头名字暴增,末字母 a/na 女名席卷("Boy named Sue" 现象);还有「字母 L 的性别反转」。学到:concat 批量拼文件、transform 组内归一、pivot_table + plot 的长时序分析套路。

🥗 战役四:USDA 食品数据库

数据:6640 种食物的深嵌套 JSON(每种食物含 3 层 nutrients 信息)。

剧情:处理真实世界最恶心的部分——深嵌套 JSON

nutrients = pd.DataFrame(db[0]["nutrients"])      # 第一层展平
nutrients = pd.concat([pd.DataFrame(f["nutrients"])
                       for f in db], ignore_index=True)
# 每种食物重复展开 nutrient 列表 → 长表 → 去重

然后按食物类别分箱画「锌、铁、蛋白质」的分布直方图(log=True 处理长尾),找最咸/最肥的食物。

学到:嵌套 JSON 展平三板斧(列表推导逐个展开 → concat → drop_duplicates);类别变量 astype("category");分布对比用堆叠直方图。

💰 战役五:FEC 联邦竞选捐款

数据:2012 年美国总统大选捐款记录(职业、雇主、州、候选人、金额)。

剧情:最接近商业分析报告的一场仗:

# 按职业和雇主聚合捐款总额
by_occupation = fec_conts.pivot_table("contb_receipt_amt",
                                      index="contbr_occupation",
                                      columns="cand_nm", aggfunc="sum")
# 捐款金额分桶(cut 的实战)
buckets = pd.cut(fec["contb_receipt_amt"], bins=[0,10,100,1000,10000,100000])
grouped = fec.groupby(["cand_nm", buckets]).size().unstack(0)

# 按州统计 → 候选人 × 州 的热力图式透视
grouped = fec.groupby(["cand_nm", "contbr_st"])["contb_receipt_amt"].sum()

学到cut 分桶 + groupby 的组合拳;类别型数据(occupation/employer)用 astype("category") 提速;长尾金额怎么用对数刻度看。

🧭 五场仗的共同套路

把五个案例的骨架提出来,就是数据分析的通用作战图:

五场实战案例

  1. 读入:read_csv / read_json / 循环 concat;
  2. 清洗:fillna("Missing")、去重、类型转换、value_counts 查异常标签;
  3. 变形:merge 连表 / pivot 长转宽 / transform 组内归一;
  4. 聚合:groupby + agg,永远先看样本量再下结论;
  5. 展示:barh 看类别、line 看时序、hist 看分布。

📌 本章小结:五个数据集各练一招——Bitly 练 value_counts、MovieLens 练 merge 链、Baby Names 练 concat+transform、USDA 练嵌套 JSON、FEC 练 cut+透视。复现它们 = 把全书 12 章串成肌肉记忆,然后拿你自己的数据开始第一场自己的仗。