Skip to content

特征工程实战:从时序窗口到防泄漏 ​

这是《监督学习实战:回归建模与模型选型》的下一本。 上一本最后得出一个否定性的结论:换模型收益 0.0145、加数据收益 0.011,都到顶了。 这本书就是去回答那个结论留下的问题:那剩下的空间在哪?

三个反转 ​

这本书的全部内容,可以压缩成三行实测结果(同一份数据、同一套划分):

text
基础 7 列                     测试 R² = 0.95900
+ 10 列窗口/差分特征             测试 R² = 0.95906   ← 加了 10 列,几乎没动
+ 4 列历史 SOH 轨迹             测试 R² = 0.99904   ← 再加 4 列,跳了 0.04
+ 1 列 soh − 0.80(泄漏)       测试 R² = 1.000000  ← 完 美,而且是假的

三个反转,三种认知:

反转数字你该学到的
加 10 列没涨+0.00006"加特征"不等于"加信息"
加 4 列跳了 0.04+0.03998对的特征能改变问题的信息结构
加 1 列到 1.000000+0.04098分数不是判据 —— 那是事故,不是成果

这本书不教"多凑特征",教"怎么判断一个特征值不值得做"。

最锋利的一个论证 ​

书里有一组数字,比任何"倍数"都有说服力:

text
换模型(线性 → 300 棵提升树)在 7 列上的极差  = 0.01587
换模型在 21 列上的极差                        = 0.00007
                                                    ↑
                                            缩小了 221 倍

含义:

特征没到位时,"选哪个模型"很重要(差 0.0159)。 特征到位之后,"选哪个模型"这个问题直接消失了(差 0.00007)。

这就是"卡点在特征"的最强证据 —— 不是"加特征比换模型收益大",而是特征到位后,换模型这件事变得无关紧要。

适合谁读 ​

适合你,如果:

  • 已完成上一本(《监督学习实战》),会 X/y 切分、按实体划分、四个回归指标、交叉验证
  • 你会用 sklearn 的 Pipeline,但特征基本是"原样丢进去"
  • 你的模型分数卡在某个水平,不知道该往哪改进
  • 或者:你已经在做特征,但说不清哪些特征真的有用

不太适合,如果:

上一本讲了什么,这本不重复 ​

上一本已经讲过、本书只引用不再展开的:

主题在哪本讲
按实体划分(分组划分)、避免划分泄漏上一本第 09~12 章
四个回归指标(MAE / RMSE / R²)上一本第 08 章
交叉验证、报"均值 ± 标准差"上一本第 11~12 章
决策树 / 随机森林 / 梯度提升上一本第 16~19 章
学习曲线、正则化上一本第 21~22 章
模型选型的四个维度上一本第 26 章

本书新增的,是上一本没有的:窗口 / 差分 / 滚动统计、特征选择与消融、 三种泄漏的完整专题、特征账本、以及"怎么判断一个特征值不值得做"。

一个提醒:本书第 19 章(预处理泄漏)会用到上一本第 15 章(缩放与 Pipeline) 的结论。如果你对 Pipeline 还不熟,建议先回去看一眼那一章。

你会学到什么 ​

按四个能力组织:

能力具体表现
把"过去"变成特征会用 shift(1).rolling(w) 构造只含历史的统计量,并知道漏写 shift 的后果
判断一个特征值不值得做会做消融实验、看 Δ 与方差,能识别"加了 10 列等于没加"
守住不泄漏认得出划分/预处理/特征三种泄漏,并会写检查清单
知道该停手明白"信息上限由特征决定,不由超参决定",不再无效调参

主线项目 ​

全书围绕三层数据展开 —— 而这三层正好是一条完整的特征工程路径:

第 1 层  逐循环时序      69,591 行 × 9 列   一行 = 一圈
              ↓  按窗口汇总(100 圈 → 1 行,压缩 3.28 倍)
第 2 层  窗口表          21,239 行 × 9 列   一行 = 一段(上一本用的表)
              ↓  补上"带历史看"的列(行数不变,列数 9 → 27)
第 3 层  时序特征表      21,239 行 × 27 列  一行 = 一段 + 它的过去  ★ 本书主表

你会亲手走完这三层 —— 包括中途那些不该加的特征(因为"加错"比"不加"更常见)。

不懂电池完全不影响阅读 —— 所有结论都是关于"特征工程方法"的。

学习路径 ​

组章主题你会拿走什么
A 视角转变01–04环境与数据、课程地图、为什么横截面特征到顶了、信息结构知道该往哪改进
B 造时序特征05–10滑动窗口、分组与排序、冷启动 NaN、差分与斜率、滚动统计、构造纪律会安全地造特征
C 让特征能用11–16缩放、编码、ColumnTransformer、特征选择、消融实验、特征账本会判断特征价值
D ★ 泄漏专题17–22三种泄漏总览、划分泄漏、预处理泄漏、特征泄漏、亲手做出 R²=1.000000、防泄漏清单★ 一套防泄漏纪律
E 别过拟合23–27过拟合的形状、早停、正则化、超参搜索、调参的收益上限知道该停手
F 集成与收口28–32多窗口平均、模型融合、❖ 阶段目标、从清单到流程、下一本能交付一份报告

★ 标记的是最值得花时间的部分。 第 17–22 章是全书重心。

四条读法 ​

① 按顺序读(推荐):后面的章节依赖前面的口径(尤其是"只含历史"这个纪律)。

② 时间有限,只读两组:第 05–10 章(怎么造特征)+ 第 17–22 章(怎么不泄漏)。 这两组就是特征工程的 80%。

③ 当参考手册:每章的「常见坑」是速查表;第 16 章的特征账本和第 22 章的 防泄漏清单是可以直接拿走用的交付物。

④ 只跑第 30 章:阶段目标一条命令产出完整报告 —— 但先看代码再跑。

每章的固定结构
text
┌─ 开头:这一章要解决什么 + 最容易踩的坑
├─ 概念讲解:是什么、为什么、和什么容易混
├─ 可运行示例:代码 + 真实输出 + 逐段解释
├─ 常见坑:报错信息长什么样、为什么、怎么改
├─ 练习:3 道题,答案默认折叠(先自己做)
└─ 面向工程实践:这一章的知识在真实项目里用在哪

关于练习答案:答案都放在折叠块里,点击展开。 强烈建议:先自己在 demos/ 下敲一遍、跑出结果,再点开对照。

配套数据包怎么用(重要)

本课程刻意不提供示例代码和练习答案的文件包 —— 只提供数据和环境工具。

为什么:特征工程的每一步都很"轻"(shift(1).rolling(20).mean() 一行就完了), 但口径错一个字符,结果就全错,而且不报错。所以只有你自己敲过、错过、查过, 才会真正记住那些口径。

数据包下载:feature-engineering-pipeline-code.zip(约 4 MB)。

包里有三层数据 + 设备级真值(这样你能亲手看到"窗口是怎么来的"):

code/
├── README.md
├── requirements.txt
├── check_env.py
└── data/battery/
    ├── cycle_raw.csv          逐循环时序(69,591 行)★ 自己动手做窗口用它
    ├── soh_features.csv       窗口表(21,239 行,上一本用的)
    ├── soh_features_v2.csv    时序特征表(21,239 × 27)★ 本书主表
    ├── cells.csv              设备级真值(60 行)
    └── README.md              字段 / 分组 / 泄漏标注 / 局限

开始方式:

bash
cd code
python check_env.py

然后从第 03 章开始,自己建 demos/ 目录,把代码敲进去。

纪律一:口径比代码重要

这本书里,"代码写对了但口径错了"是最主要的错误来源。三个例子:

python
# ❌ 含当前行 —— 特征里混进了当前行的标签
df["soh_win_mean5"] = g["soh"].transform(lambda s: s.rolling(5).mean())

# ✅ 只含历史 —— shift(1) 把当前行推出去
df["soh_win_mean5"] = g["soh"].transform(lambda s: s.shift(1).rolling(5).mean())
python
# ❌ 忘了分组 —— 跨设备串线(C002 的第一行混进 C001 的尾巴)
df["soh_win_mean"] = df["soh"].rolling(20).mean()

# ✅ 先分组再滚动
df["soh_win_mean"] = df.groupby("cell_id")["soh"].transform(
    lambda s: s.shift(1).rolling(20).mean())
python
# ❌ 忘了排序 —— 时间倒流,窗口统计量完全无意义
df["soh_win_mean"] = df.groupby("cell_id")["soh"].transform(...)

# ✅ 先按(实体, 时间)排序
df = df.sort_values(["cell_id", "cycle"]).reset_index(drop=True)

★ 这三处错误全都不报错、数值看着正常、分数可能还很高。

所以本书的每一章都会强调"口径",而不只是"代码怎么写"。

纪律二:分数不是判据

这本书里有三次"分数不提醒你"的实测:

① 忘了分组/排序 → 特征值错了(0.8123 vs NaN),分数几乎没变
② 填 0 代替 dropna → 线性模型 0.99910 → 0.94350(树模型却无感)
③ 加一列 soh − 0.80 → R² 恰好 1.000000

第 ② 条特别值得想:

同一个错误(fillna(0)),
  线性模型掉 0.056
  随机森林只掉 0.00001
      ↓
如果你只用树模型,这个错误【会被完全掩盖】

★ 所以纪律是:

不要用"分数没变"来证明"我没写错"。 要用结构检查(值域、NaN 数、量纲、和已知量的恒等关系)来证明。

纪律三:先写预期,再跑代码

这本书每一章几乎都有"看起来对但其实错"的写法。

跑之前先用注释写下预期:

python
# 我预期:加 10 列窗口特征,分数会涨一点(毕竟多了信息)
# 实测:______

先有预期、再看结果,你才会注意到"现实和直觉的差距"。

直接跑代码的人只会看到数字;先写预期的人会看到自己思维的漏洞。

关于数据的重要声明 ​

本书使用的全部是合成数据:

  • 为教学构造的合成数据,不联网、不依赖任何外部数据集;
  • 数据固定不变(校验和见数据包里的 data/battery/README.md);
  • 真实设备的测量数据属于企业机密,本书全程不使用;
  • 数据是理想化的:退化单调、无随机跳变、无工况切换。

三条必须记住的边界:

  1. soh_features_v2.csv 里有两列是"反面教材": soh_margin(= soh − 0.80)和 cycle_frac(= cycle / 最终总寿命)。 它们故意留在数据里,好让你在第 21 章亲手做出 R² = 1.000000。 它们是泄漏列,任何正式建模都不要用。
  2. 时序特征有冷启动 NaN:每支设备最早的窗口没有历史, 14 列时序特征导致 1,260 行有 NaN、19,979 行齐全。处理方式见第 07 章。
  3. 方法可迁移,模型不可直接上线。 真实场景必须重新采集、重新标定。

三条纪律(贴在这里,随时回看) ​

① 口径比代码重要:先排序、再分组、只含历史。
② 分数不是判据:用结构检查证明自己没写错。
③ 信息上限由特征决定,不由超参决定。

准备好了就从第 01 章开始装环境。

如果你时间有限,我建议直接从 第 03 章 · 为什么横截面特征到顶了 读起 —— 它会用三个数字告诉你为什么这本书值得读。

目录 ​

暂无章节