Skip to content

第 02 章 · 学习路线与知识地图 ​

这一章要解决什么:在动手写代码之前,先看清楚"我接下来要学的 37 章之间是什么关系"。 这一章没有代码,但值得花 20 分钟读完 —— 它能帮你判断"现在卡住了,应该回头看哪一章"。

2.1 一句话说清这本书在教什么 ​

把一堆 CSV 变成"我敢下判断的证据"。

这句话拆开,就是全书的五个部分:

一堆 CSV  ──[读进来]──>  一张表  ──[清洗]──>  可信的数据  ──[统计/画图]──>  证据  ──[组织]──>  报告
   │                      │                      │                        │                  │
   │                  第 12 章                第 30 章                第 32~38 章         第 39 章
   │                  第 23 章                第 32~34 章
   │
   └─ 你在真实工作中拿到的东西(可能是 Excel 导出的、传感器记的、数据库导的)

每一章都在推进这条链路的一小段。所以你随时可以问自己:我现在在链路的哪一步?

2.2 知识地图 ​

点开看完整地图(38 章的分组与依赖关系)
┌─────────────────────────────────────────────────────────────────────┐
│  起步(第 01–02 章)                                                 │
│  01 环境安装   ← 必须最先完成                                        │
│  02 知识地图   ← 你正在读                                            │
└─────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────┐
│  A · Python 基础(第 03–16 章)—— 学"怎么指挥计算机"                 │
│                                                                     │
│  数据从哪来          怎么处理它              怎么组织代码            │
│  ────────────       ──────────────         ──────────────          │
│  03 变量与类型       06 列表                 10 函数                 │
│  04 数值与算术       07 循环与切片           11 推导式与解包         │
│  05 字符串           08 条件判断             13 异常处理             │
│                      09 字典与集合           14 模块与导入           │
│                                              15 类与对象  ★补充      │
│                                              16 类型注解  ★补充      │
│                                                                     │
│  12 文件读写与 csv  ← A 组的收尾,也是转向数据处理的桥梁             │
└─────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────┐
│  B · NumPy(第 17–22 章)—— 学"怎么让计算机一次算一整列"             │
│                                                                     │
│  17 第一个数组        20 向量化运算(告别 for)                      │
│  18 创建与形状        21 广播机制  ★ 标准化就是它                    │
│  19 索引与切片        22 聚合与布尔索引                              │
│      ★ 视图 vs 拷贝                                                  │
└─────────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────┐
│  C · Pandas(第 23–31 章)—— 学"怎么处理真实的表"                    │
│                                                                     │
│  23 第一个 DataFrame   27 派生列                                     │
│  24 数据速览三件套     28 分组聚合        ★ 切-算-合                 │
│  25 选行选列 loc/iloc  29 时间序列与重采样                           │
│  26 筛选与排序         30 缺失值处理      ★★ 全书最重要的坑          │
│                        31 保存结果                                   │
└─────────────────────────────────────────────────────────────────────┘
                              ↓
        ┌─────────────────────┴─────────────────────┐
        ↓                                           ↓
┌───────────────────────────┐         ┌───────────────────────────┐
│  D · 数据清洗(32–34)    │         │  E · 可视化(35–38)      │
│                           │         │                           │
│  32 Z 分数                │         │  35 折线图(趋势)        │
│  33 IQR  ★ 比 Z 稳健      │         │  36 散点图(关系)        │
│  34 异常处置策略          │         │  37 热力图(冗余/泄漏)   │
│      ★ 删/截/标/单        │         │  38 箱线图(分布对比)    │
└───────────────────────────┘         └───────────────────────────┘
        └─────────────────────┬─────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────────┐
│  F · 阶段目标(第 39 章)                                            │
│  把上面全部拼起来 → 一条命令产出《电池数据体检报告》+ 4 张图          │
└─────────────────────────────────────────────────────────────────────┘

图里带 ★ 的是这一章最关键的知识点,★★ 表示"坑"的严重程度 —— 自测时优先看它。第 15、16 章(类与对象、类型注解)是整章补充内容,别跳过。

2.3 五个部分分别在解决什么问题 ​

理解"每一部分为什么存在",比记住语法更有用 —— 因为它决定了你什么时候该用它。

A 组 · Python 基础(03–16):把想法写成指令 ​

它解决的问题:计算机不会读心术。你要用它能懂的方式,把你的处理逻辑一步步说清楚。

核心转折点:第 06~10 章。学完这几章,你就能写出"能跑"的程序了:

python
caps = [2.50, 2.46, 2.42, 2.38]        # 列表:存一串数据
for c in caps:                          # 循环:对每一个做点什么
    soh = c / 2.5                       # 算术
    if soh < 0.85:                      # 条件:分情况处理
        print(f"SOH {soh:.4f} → 预警")  # 输出

这一段最常见的卡点:下标从 0 开始、切片不含右端、缩进就是语法。 这三个想通了,A 组就通了。

为什么要有第 12 章(读文件):到这一步你终于能处理"真实存在的数据",而不是自己手写的小列表。 这也是你第一次遇到"路径""编码""读进来全是字符串"这三个真实世界的麻烦。

B 组 · NumPy(17–22):从"能算"到"算得快" ​

它解决的问题:Python 的 for 循环在处理上百万个数字时太慢了。

python
# Python 列表:每个元素都要单独跑一次解释器
result = []
for c in caps:                 # 100 万个元素 → 几秒钟
    result.append(c / 2.5)

# NumPy 数组:一行,底层是 C 循环,快几十倍
result = caps / 2.5            # 100 万个元素 → 几毫秒

三个最关键的知识点:

概念在哪一章为什么重要
视图 vs 拷贝19改一个切片会连带改原数组 —— 这是 NumPy 最难查的 bug
向量化20"整列一次算完"的思维,是后面所有数据处理的基础
广播21它同时就是 Z-score 标准化(StandardScaler)的数学本体

为什么 AI 开发必须先学 NumPy:PyTorch 的 Tensor、TensorFlow 的 EagerTensor、 JAX 的 Array —— 它们的 API 都是照着 NumPy 设计的。 学会 NumPy 的"整体运算"思维,再学这些框架会轻松得多。

C 组 · Pandas(23–31):处理"真实的表" ​

它解决的问题:真实数据不是干净的数值矩阵,而是混合类型、有缺失、有索引、有日期的表格。

python
df = pd.read_csv("battery.csv")           # 一行读入,类型自动推断
df[df["soh"] < 0.85]                       # 按条件筛行
df.groupby("cell_id")["soh"].mean()        # 按电芯分组算均值
df["soh"].resample("100D").mean()          # 按时间重采样
df["x"].fillna(df["x"].median())           # 填缺失

这一段的信息量最大,也最容易"看懂了但写不出来"。建议:

  • 第 25、26 章(选取与筛选)反复练,因为它们出现在后面每一段代码里;
  • 第 28 章(groupby)是分水岭,理解"切-算-合"这个心智模型;
  • 第 30 章(缺失值)里有全书最重要的一个坑:先排序、再按组插值。请务必亲手跑一遍那个例子。

D 组 · 数据清洗(32–34):判断"哪些数字不可信" ​

它解决的问题:数据里总是有错的。但"发现异常"和"处理异常"是两件独立的事。

阶段方法关键认知
发现物理规则(值为负、超上限)不需要统计,最可靠
发现Z 分数(32)均值和标准差会被异常值自己带偏
发现IQR(33)比 Z 分数稳健得多
处理四种策略(34)没有"正确"策略,只有"和目的匹配"的策略

最重要的两个结论:

  1. 物理规则先于统计规则 —— 容量为负这种事,不该等统计方法来抓;
  2. 工业项目的默认答案是"标记 + 单独分析",而不是直接删 —— 因为删数据不可逆。

E 组 · 可视化(35–38):把数字变成"别人能看懂的东西" ​

它解决的问题:0.9071 这个数字没人有感觉;一条曲线配上一条 0.80 的参考线,所有人都懂了。

四种图各自回答什么问题(这个对应关系比语法重要):

图回答的问题章节
折线图"随时间/循环怎么变化?"35
散点图"这两个量有关系吗?"36
热力图"这十几个字段里,哪些是重复的?"37
箱线图"几组的分布有什么差别?"38

最容易犯的错:把相关系数当因果。第 36 章会用一个真实例子拆穿"共同趋势造成的假相关"。

F 组 · 阶段目标(39):把前面全部拼起来 ​

第 39 章没有新知识,它做的是工程组织:

python
def load_and_clean(path): ...        # 读 + 清洗,返回 (df, 日志)
def fig_fade(df, out_path): ...      # 一张图 = 一个函数
def build_findings(df, log, ...): ...  # 报告要的数字集中算一次
def write_report(f, out_path): ...   # 只负责拼 Markdown,不做计算

def main():                          # 只做编排,没有计算
    ...

三条纪律:main() 里只有调用没有计算;一个图一个函数;报告里每个数字都来自 build_findings()。

为什么这很重要:这样"图、数字、结论"永远不会互相矛盾。数据一换,重跑即可。

2.4 三条学习路线 ​

路线 A:零基础系统学习(约 30 小时)

这是本书设计的默认路线。

阶段章节时间重点
起步01–021 小时环境一定要装通
A 组03–1610 小时每章都跑代码、做练习,不要跳
B 组17–223 小时重点:视图 vs 拷贝、广播
C 组23–317 小时重点:groupby、缺失值那个坑
D 组32–342 小时重点:为什么 IQR 比 Z 分数稳健
E 组35–383 小时重点:四种图各回答什么问题
F 组392 小时亲手跑出报告

节奏建议:每天 2 小时、每周 5 天,三周走完。 卡住了怎么办:先回头看上一章的"常见坑",90% 的问题在那里。

路线 B:有编程基础,快速上手(约 12 小时)
阶段章节说明
起步01环境必须装通(这一步和有没有基础无关)
快扫03–10只看每章的「常见坑」和练习,遇到 Python 特有的写法(切片、enumerate、默认参数陷阱)再细读
必读11–12推导式、with open、路径处理 —— 这几个是 Python 的标志性写法
必读13–16异常、模块、类、类型注解 —— 决定代码能否维护
正常学17–31NumPy + Pandas,这是新东西,按顺序读
正常学32–39清洗、可视化、报告

可以跳的:第 04 章(算术)、第 05 章(字符串基础)如果你已熟悉; 不能跳的:第 19 章(视图 vs 拷贝)、第 21 章(广播)、第 30 章(插值的坑)—— 这几个和语言基础无关,是新知识。

路线 C:只想做数据分析(约 15 小时)
阶段章节说明
起步01环境
最小基础06、09、10、12列表、字典、函数、读文件 —— 够用就行,别陷进去
可选11、15、16想代码写得好一点就读
主体17–31NumPy + Pandas,按顺序
主体32–39清洗、可视化、报告
跳过03–05、07–08、13–14遇到不懂的语法再回来查

注意:即使"只想做数据分析",第 06/09/10/12 章也不能跳 —— 否则你会在第 26 章看到 df[df["a"] > 1] 时完全不知道发生了什么。

2.5 五类常见的"卡住" ​

提前知道这些,就不会在遇到时怀疑自己。

卡点 1:环境装不上,反复报模块找不到

这不是你的问题,是所有人的必经之路。 环境问题占了新手卡壳原因的 80%。

怎么办:

  1. 严格按第 01 章的检查清单逐条确认;
  2. 关键诊断命令:python -c "import sys; print(sys.executable)" —— 看路径里有没有 .venv;
  3. 实在修不好,删掉 .venv 重建(这是虚拟环境最大的好处:随时可以推倒重来)。
卡点 2:A 组后期开始"看得懂但写不出来"

原因:从第 12 章起,代码开始变长(读文件 → 处理 → 输出),而你还在一个个语法点地记。

怎么办:

  • 不要背语法,背结构。任何数据处理脚本都是"读 → 处理 → 写"三段式;
  • 把第 12 章的示例关掉书自己默写一遍,卡在哪就翻哪一章;
  • 抄代码不丢人,但抄完要能说出每一行在干什么。说不出来的行,就是你要回去补的章。
卡点 3:Pandas 链式操作看不懂

长这样的代码:

python
df[df["soh"] < 0.85].groupby("cell_id")["resistance_mohm"].mean().sort_values(ascending=False).head(5)

怎么办:从左往右读,每一步都想"现在手上是什么东西":

df                                  一张表
df[df["soh"] < 0.85]                还是表,只是行少了(筛选)
  .groupby("cell_id")               一个"分组对象",还没算
  ["resistance_mohm"]               指定要算哪一列
  .mean()                           现在才真的算 —— 变成 Series(每支电芯一个数)
  .sort_values(ascending=False)     排序
  .head(5)                          取前 5

练习方法:把上面这一行拆成 6 行、每行 print 一次中间结果。 看得见就懂了。第 25 章的练习里就有这个训练。

卡点 4:报错看不懂

记住:Python 的报错信息是从下往上看。

Traceback (most recent call last):              ← 上面是"调用栈",先别看
  File "demo.py", line 12, in <module>          ← 出错位置:文件 + 行号、哪个函数
    df["soh"] / df["cap_rated"]
    ~~~~~~~~~~^~~~~~~~~~~~~~~~~~
TypeError: unsupported operand type(s) for /: 'str' and 'float'   ← ★ 最后一行最重要
        └── 类型错误:字符串和浮点数不能相除

读法三步:

  1. 最后一行:什么错(异常类型 + 消息);
  2. 倒数第二段 File:错在哪(文件 + 行号);
  3. ^ 箭头:指向具体哪个字符。

然后问自己:"我需要的东西,现在是什么类型?" 九成的问题用 print(type(x)) 就能定位。

第 13 章会专门讲这个,并把常见异常类型列成表。

卡点 5:学会语法了,但拿到自己的数据还是不知道从哪下手

这是"没有形成流程"的表现。 解决办法:把下面这套流程用成肌肉记忆。

点开:拿到任何一张表的标准流程
python
# ① 先看清楚它是什么(第 23、24 章)
df = pd.read_csv("your_data.csv")
print(df.shape)          # 多大规模?
print(df.head())         # 长什么样?
df.info()                # 每列什么类型、有没有缺失?
df.describe()            # 数值范围合不合理?

# ② 逐列问"它是什么"(第 24 章)
#    标识列(每行都不同)→ 不进模型,但可以当分组键
#    类别列(取值很少)  → 要编码
#    时间列              → 可以派生成"距开始多少天"
#    标签列              → 是预测目标,绝不能当特征

# ③ 查数据质量(第 30、32、33 章)
df.isna().sum()                        # 缺多少、缺在哪
(df["数值列"] < 0).sum()                # 物理规则
# 再用 IQR 或 Z 分数找统计意义上的异常

# ④ 开始回答你的业务问题(第 26、28、35~38 章)
df.groupby("分组键")[...].mean()        # 分组统计
# 挑一张合适的图(趋势→折线、关系→散点、分布→箱线、多字段→热力图)

这四步走完,再谈建模。 跳过任何一步,后面都会付出更大的代价。

2.6 本章检查清单 ​

已勾选 0 / 0 项

本章练习 ​

本章没有编程练习,但有三个值得花 10 分钟想清楚的问题:

思考题 1:为什么先学 NumPy,再学 Pandas?

提示:想一下 Pandas 的 DataFrame 底层是用什么存的。

参考答案

因为 Pandas 的底层就是 NumPy 数组。

python
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3]})
print(type(df["a"].to_numpy()))     # <class 'numpy.ndarray'>

推论(这些都会在后面反复出现):

  1. Pandas 的整列运算就是 NumPy 的向量化:df["soh"] / 2.5 之所以能一行算完,是因为底层走了 NumPy。
  2. NumPy 的坑会原样继承到 Pandas:第 19 章的"视图 vs 拷贝"在 Pandas 里表现为 SettingWithCopyWarning(第 25 章)。
  3. 报错信息会混着出现:你可能看到 ValueError: operands could not be broadcast together, 这是 NumPy 的报错,但触发它的是 Pandas 的代码。
  4. 缺了 NumPy 就学不懂"为什么":知道 axis=0 是什么,才知道 df.mean(axis=0) 在干什么。

反过来说,为什么不能只学 NumPy? 因为:

  • NumPy 数组只能存同一种类型(第 17 章),而真实的表是数值+类别+时间混在一起;
  • NumPy 没有列名、没有索引标签、没有缺失值标记(NaN 处理很难用)、没有日期类型。

所以顺序是:先学 NumPy 打地基(第 17–22 章),再用 Pandas 盖楼(第 23–31 章)。

思考题 2:为什么第 30 章(缺失值)被称为"全书最重要的坑"?

提示:想一想"这份数据是怎么组织的"。

参考答案

因为数据是"多支电芯竖着摞在一起"的,而插值需要"前后邻居"。

行号    cell_id   cycle   capacity_ah
 861     C001       862      1.9945     ← C001 的最后一圈
 862     C002         1         NaN     ← 这一格缺失了
 863     C002         2      2.5046     ← C002 的第二圈

如果你写 df[["capacity_ah"]].interpolate(),Pandas 会把整列当成一条长序列, 于是用第 861 行的 1.9945(C001 的末圈)和第 863 行的 2.5046(C002 第 2 圈)去插第 862 行:

整表插值 → 2.2496   ❌ 被上一支电芯拖低了
组内插值 → 2.5046   ✅ 与 C002 第 2 圈接近,物理上合理

差异 0.2550 Ah,相当于额定容量的 10.2%。这个错误不会报错、不会报警, 只是让你的数据悄悄偏了 10% —— 后面所有结论都建立在错误的数据上。

正确写法(两个动作缺一不可):

python
df = df.sort_values(["cell_id", "cycle"])            # ① 先排序
df[NUM] = (df.groupby("cell_id")[NUM]                 # ② 再按电芯分组
             .transform(lambda g: g.interpolate(limit_direction="both")))

更重要的那条认知(这才是"最重要的坑"的真正含义):

数据处理的正确写法,不由"这次跑出来一样不一样"决定,而由"物理上什么才是合理的邻居"决定。

在这份数据里,随机撒的缺失碰巧很少落在电芯边界,所以两种做法只差 1 格。 如果你用"结果一不一样"来判断对错,就会得出"两种都行"的错误结论 —— 然后在真实数据上翻车。

思考题 3:为什么报告里的数字不能手写?

提示:想想"数据更新一次会发生什么"。

参考答案

因为手写的数字一定会过时,而过时的数字比没有数字更危险。

场景:你手写了一份报告说"平均 SOH 0.9071,r = -0.94"。 三个月后数据更新了,你重跑脚本,图画出来了(fig.savefig 是代码自动跑的), 但报告里的文字还是旧的 —— 图上显示 0.8912,报告里写着 0.9071。

读者看到的是一份自相矛盾的报告。更糟的是:没人会发现,因为两边看起来都很正常。

第 39 章的解法:把所有要写进报告的数字,集中在一个函数里算一次:

python
def build_findings(df, log, fade, scat, corr, box) -> dict:
    """所有要写进报告的数字,集中算一次。"""
    return {
        "n_rows": len(df),
        "r_soh_r": scat["r_soh_resistance"],
        "worst_cell": per_cell["soh_mean"].idxmin(),
        ...
    }

def write_report(f, out_path):
    """只负责拼 Markdown,不做任何计算。"""
    text = f"...全批平均 SOH 从 {f['fade']['soh_first']:.4f} 降到 ..."
    out_path.write_text(text, encoding="utf-8")

这样图、数字、结论三者永远一致:数据一换,重跑即可,不会出现"图变了但结论没变"。

这条纪律在真实项目里的名字叫"单一数据源(single source of truth)": 任何一个数字,在整个系统里只应该有一个地方产生它。

面向 AI 开发:为什么要"先看图,再建模" ​

这一章讲的知识地图,在真实的 AI 项目里对应一条重要的工程经验:

模型的上限,由数据决定;而数据的上限,由你"看懂它"的程度决定。

一个典型的时间分配对比:

阶段新手的时间有经验的人的时间
看数据、查质量、画图10%50~60%
特征工程10%20~30%
选模型、调参80%10~20%

新手把大部分时间花在调模型上,而有经验的人知道:在脏数据上调参,是在优化一个错误的答案。

本书刻意把 "数据处理 + 可视化" 放在 "模型" 之前,也正是这个原因 —— 第 39 章的"阶段目标"是一份报告,而不是一个模型。


下一章:第 03 章 · 变量、对象与数据类型 —— 正式开始写代码。