跳转至

13.6   特征工程

小率把“年龄、通勤距离、过去 30 天活动次数、兴趣标签”直接喂给模型。结果模型几乎只盯着通勤距离,因为距离用米表示,数值动不动就是几千;兴趣分只有 0 到 1,像被淹没在表格里。

机器学习不是把原始表格原样倒进去就结束。把原始信息整理成模型能好好使用的变量,叫 特征工程(Feature Engineering)

图 13.6.1 特征工程

明明兴趣也很重要,为什么模型像没看见它?
因为你给模型的尺子不公平。数值范围大的特征会先把距离类模型牵走。

13.6.1   数值特征先摆正尺子

数值特征常见处理包括:

  • 标准化(Standardization):减均值、除标准差。
  • 归一化(Normalization):缩放到固定区间。
  • 截尾(Winsorization):限制极端值影响。
  • 对数变换(Log Transform):压缩长尾分布。

标准化公式是:

\[ z=\frac{x-\bar x}{s} \]

其中 \(\bar x\) 是样本均值,\(s\) 是样本标准差。标准化后,通勤距离和兴趣分都变成“离平均水平几个标准差”,距离计算才更公平。

原来不是模型偏心,是我把变量放在了不同单位的尺子上。
对。特征工程第一步常常是把尺子摆正。

13.6.2   类别、时间、文本都要翻译

模型通常吃数字,但现实数据不只数字。

原始信息 常见做法 注意事项
城市、年级、渠道 One-Hot、Target Encoding 高基数类别要防泄漏
日期时间 周几、月份、是否考试周 周期变量可用 sin/cos
文本 词袋、TF-IDF、Embedding 分词和停用词会影响结果
缺失值 填充 + 是否缺失指示位 缺失本身可能有信息

比如“报名时间 2026-06-06 21:30”本身不容易学习,但拆成“周末、晚上、期末前一周”就更像可用信号。


13.6.3   好特征来自对问题的理解

在活动推荐里,原始列可能是“最近 30 天浏览活动页次数”和“最近 30 天报名次数”。派生一个“浏览后报名率”:

\[ \text{报名转化率}=\frac{\text{报名次数}}{\text{浏览次数}+1} \]

这个特征比两个原始数字更接近“兴趣是否转成行动”。

所以特征工程不是玄学,是把问题翻译成模型更容易学的变量。
没错。模型会算,但人要帮它把问题摆成好算的样子。

13.6.4   用 Pipeline 避免处理流程泄漏

import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.linear_model import LogisticRegression

X = np.array([
    [1.2, 1200, "艺术"],
    [0.3, 3500, "运动"],
    [0.8, 800, "公益"],
    [1.5, 1500, "艺术"],
], dtype=object)
y = np.array([1, 0, 1, 1])

preprocess = ColumnTransformer([
    ("num", StandardScaler(), [0, 1]),
    ("cat", OneHotEncoder(handle_unknown="ignore"), [2]),
])

model = make_pipeline(preprocess, LogisticRegression())
model.fit(X, y)
print(model.predict([[1.0, 1000, "艺术"]]))

把预处理放进 Pipeline,可以确保交叉验证时每一折只用训练折拟合标准化参数和编码规则,避免提前偷看验证集。

特征工程最怕数据泄漏

Target Encoding、缺失填充、标准化、特征选择,都必须在训练折内部完成。先用全量数据处理再交叉验证,会让验证分数虚高。

小率的笔记本

特征工程就是把原始信息变成模型能有效学习的信号。数值要处理尺度,类别要编码,时间和文本要拆出结构,派生特征要贴近问题。所有预处理都要放进可验证的流程里。