特征工程实战:从时序窗口到防泄漏
这是《监督学习实战:回归建模与模型选型》的下一本。 上一本最后得出一个否定性的结论:换模型收益 0.0145、加数据收益 0.011,都到顶了。 这本书就是去回答那个结论留下的问题:那剩下的空间在哪?
三个反转
这本书的全部内容,可以压缩成三行实测结果(同一份数据、同一套划分):
基础 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 | 分数不是判据 —— 那是事故,不是成果 |
这本书不教"多凑特征",教"怎么判断一个特征值不值得做"。
最锋利的一个论证
书里有一组数字,比任何"倍数"都有说服力:
换模型(线性 → 300 棵提升树)在 7 列上的极差 = 0.01587
换模型在 21 列上的极差 = 0.00007
↑
缩小了 221 倍含义:
特征没到位时,"选哪个模型"很重要(差 0.0159)。 特征到位之后,"选哪个模型"这个问题直接消失了(差 0.00007)。
这就是"卡点在特征"的最强证据 —— 不是"加特征比换模型收益大",而是特征到位后,换模型这件事变得无关紧要。
适合谁读
适合你,如果:
- 已完成上一本(《监督学习实战》),会 X/y 切分、按实体划分、四个回归指标、交叉验证
- 你会用
sklearn的Pipeline,但特征基本是"原样丢进去" - 你的模型分数卡在某个水平,不知道该往哪改进
- 或者:你已经在做特征,但说不清哪些特征真的有用
不太适合,如果:
- 你还没学过机器学习基础(建议先看 监督学习实战:回归建模与模型选型)
- 你完全不会 pandas(建议先看 面向 AI 开发的 Python 快速入门)
- 你在找"深度学习特征提取"(这本讲的是表格数据的经典特征工程)
上一本讲了什么,这本不重复
上一本已经讲过、本书只引用不再展开的:
| 主题 | 在哪本讲 |
|---|---|
| 按实体划分(分组划分)、避免划分泄漏 | 上一本第 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 章:阶段目标一条命令产出完整报告 —— 但先看代码再跑。
每章的固定结构
┌─ 开头:这一章要解决什么 + 最容易踩的坑
├─ 概念讲解:是什么、为什么、和什么容易混
├─ 可运行示例:代码 + 真实输出 + 逐段解释
├─ 常见坑:报错信息长什么样、为什么、怎么改
├─ 练习: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 字段 / 分组 / 泄漏标注 / 局限开始方式:
cd code
python check_env.py然后从第 03 章开始,自己建 demos/ 目录,把代码敲进去。
纪律一:口径比代码重要
这本书里,"代码写对了但口径错了"是最主要的错误来源。三个例子:
# ❌ 含当前行 —— 特征里混进了当前行的标签
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())# ❌ 忘了分组 —— 跨设备串线(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())# ❌ 忘了排序 —— 时间倒流,窗口统计量完全无意义
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 数、量纲、和已知量的恒等关系)来证明。
纪律三:先写预期,再跑代码
这本书每一章几乎都有"看起来对但其实错"的写法。
跑之前先用注释写下预期:
# 我预期:加 10 列窗口特征,分数会涨一点(毕竟多了信息)
# 实测:______先有预期、再看结果,你才会注意到"现实和直觉的差距"。
直接跑代码的人只会看到数字;先写预期的人会看到自己思维的漏洞。
关于数据的重要声明
本书使用的全部是合成数据:
- 为教学构造的合成数据,不联网、不依赖任何外部数据集;
- 数据固定不变(校验和见数据包里的
data/battery/README.md); - 真实设备的测量数据属于企业机密,本书全程不使用;
- 数据是理想化的:退化单调、无随机跳变、无工况切换。
三条必须记住的边界:
soh_features_v2.csv里有两列是"反面教材":soh_margin(=soh − 0.80)和cycle_frac(=cycle / 最终总寿命)。 它们故意留在数据里,好让你在第 21 章亲手做出R² = 1.000000。 它们是泄漏列,任何正式建模都不要用。- 时序特征有冷启动 NaN:每支设备最早的窗口没有历史, 14 列时序特征导致 1,260 行有 NaN、19,979 行齐全。处理方式见第 07 章。
- 方法可迁移,模型不可直接上线。 真实场景必须重新采集、重新标定。
三条纪律(贴在这里,随时回看)
① 口径比代码重要:先排序、再分组、只含历史。
② 分数不是判据:用结构检查证明自己没写错。
③ 信息上限由特征决定,不由超参决定。准备好了就从第 01 章开始装环境。
如果你时间有限,我建议直接从 第 03 章 · 为什么横截面特征到顶了 读起 —— 它会用三个数字告诉你为什么这本书值得读。
目录
暂无章节