引言
真实项目的数据是「脏的、异构的」:数值列要缩放、类别列要编码、缺失值要填充,然后才能训练。把这些步骤串成可复用的 Pipeline,并从中选出真正有用的特征,是机器学习从「单机实验」走向「工程落地」的分水岭。本文覆盖 sklearn 的 Pipeline 与 ColumnTransformer 用法、三大类特征选择方法(过滤/包裹/嵌入)、RFE 递归消除与正则化选特征,以及最关键的防泄漏纪律。
前置:/ml-feature-engineering/(清洗/构造/编码)、/ml-model-evaluation/(交叉验证)、/ml-supervised-regression/(回归流程)。
目录
- 1. 为什么需要 Pipeline
- 2. Pipeline 基础:串起预处理与模型
- 3. ColumnTransformer:异构数据的分列处理
- 4. 特征选择三大类:过滤包裹嵌入
- 5. 过滤法:SelectKBest 与统计检验
- 6. 包裹法:RFE 递归特征消除
- 7. 嵌入法:正则化与树模型重要性
- 8. 特征选择的最大坑:数据泄漏
- 9. Pipeline 与交叉验证的配合
- 10. 速查表与一句话记忆
- 延伸阅读
1. 为什么需要 Pipeline
1.1 裸写流程的三大问题
# 反模式:散乱的预处理代码
X = impute(X) # 填充
X = scale(X) # 缩放
X = encode(X) # 编码
model.fit(X, y) # 训练
- 容易漏步骤:上线时少做一步预处理,模型直接崩
- 无法复用:换模型/换数据要重写一整套
- 泄漏风险:手动在训练前对全量数据做预处理,验证折的信息被污染
1.2 Pipeline 是什么
Pipeline 把「一串变换 + 一个最终模型」打包成一个可整体 fit/预测的对象,内部步骤顺序执行、中间结果自动传递:
数据 → 填充 → 缩放 → 编码 → 模型 → 预测
记忆:Pipeline = 预处理链 + 模型打包成一个可复用对象——防漏步骤、防泄漏、可整体交叉验证。
2. Pipeline 基础:串起预处理与模型
2.1 最小 Pipeline
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
pipe = Pipeline([
("scale", StandardScaler()),
("clf", LogisticRegression(max_iter=1000)),
])
pipe.fit(X_train, y_train) # 一步训练整条链
y_pred = pipe.predict(X_test) # 一步预测(自动预处理)
2.2 参数访问与网格搜索
Pipeline 让超参搜索变得「参数路径化」:
from sklearn.model_selection import GridSearchCV
params = {"clf__C": [0.1, 1.0, 10.0]} # 步骤名__参数名
gs = GridSearchCV(pipe, params, cv=5)
gs.fit(X_train, y_train)
记忆:Pipeline 一步 fit/一步 predict;超参用「步骤名__参数名」寻址,GridSearchCV 自动做带预处理的交叉验证。
3. ColumnTransformer:异构数据的分列处理
3.1 问题:不同列要不同处理
一个表里既有数值列(要缩放)、又有类别列(要编码)、还有可能要 drop 的 ID 列——不能对全表做同一种预处理。
3.2 分列处理
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
num_cols = ["age", "income"]
cat_cols = ["city", "job"]
pre = ColumnTransformer([
("num", StandardScaler(), num_cols),
("cat", OneHotEncoder(handle_unknown="ignore"), cat_cols),
])
pipe = Pipeline([("pre", pre), ("clf", LogisticRegression())])
3.3 配合 DataFrame 的输出检查
X_out = pre.fit_transform(X_train)
print(X_out.shape) # 确认编码后的列数,避免意外
记忆:ColumnTransformer 让「不同列走不同预处理管道」——数值列缩放、类别列独热、多余列 drop,一次 fit 全自动。
4. 特征选择三大类:过滤包裹嵌入
| 类别 | 思路 | 代表 | 特点 |
|---|---|---|---|
| 过滤法 | 与目标的相关统计 | SelectKBest、方差阈值 | 快、与模型无关 |
| 包裹法 | 按模型表现选子集 | RFE、前向搜索 | 准、慢、易过拟合 |
| 嵌入法 | 训练中学特征权重 | L1 回归、树重要性 | 平衡、常用 |
三类各有取舍:过滤最快但忽略特征交互,包裹按模型效果选最贴合但贵,嵌入法性价比最高。
记忆:三类特征选择——过滤看统计快而糙、包裹看模型效果准而慢、嵌入在训练中学习权重最平衡。
5. 过滤法:SelectKBest 与统计检验
5.1 方差阈值:删掉「不变」的列
零方差的列毫无信息量,先删:
from sklearn.feature_selection import VarianceThreshold
sel = VarianceThreshold(threshold=0.0) # 删零方差
X_sel = sel.fit_transform(X)
5.2 SelectKBest:按检验选 Top-K
from sklearn.feature_selection import SelectKBest, f_classif
# f_classif:单变量方差分析 F 检验(分类用)
sel = SelectKBest(f_classif, k=20)
X_sel = sel.fit_transform(X, y)
其他评分函数:mutual_info_classif(互信息,可捕捉非线性)、chi2(卡方,需非负特征)。
5.3 在 Pipeline 里用
pipe = Pipeline([
("scale", StandardScaler()),
("select", SelectKBest(f_classif, k=20)),
("clf", LogisticRegression()),
])
记忆:过滤法快而糙——VarianceThreshold 删零方差、SelectKBest 按 F 检验/互信息/卡方选 Top-K,适合高维数据的粗筛。
6. 包裹法:RFE 递归特征消除
6.1 RFE 的思路
RFE(Recursive Feature Elimination)反复训练模型,每次砍掉权重最小的特征,递归直到留下指定数量:
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier
rfe = RFE(RandomForestClassifier(n_estimators=100), n_features_to_select=15)
rfe.fit(X_train, y_train)
print(rfe.support_) # 每列是否被选中
print(rfe.ranking_) # 每列排名(1 = 最优)
6.2 用交叉验证定特征数
RFECV 用交叉验证自动选「分数不再提升」的特征数,避免手选 n_features_to_select:
from sklearn.feature_selection import RFECV
rfecv = RFECV(RandomForestClassifier(n_estimators=100), cv=5)
rfecv.fit(X_train, y_train)
print(rfecv.n_features_) # 自动选出的最优特征数
记忆:RFE 递归「训练→砍最小权重特征」直到目标数,RFECV 用交叉验证自动定最优特征数——准但慢,特征多时先粗筛再 RFE。
7. 嵌入法:正则化与树模型重要性
7.1 L1 正则让不重要权重归零
线性模型加 L1(Lasso)后,不重要的特征权重被压成 0——选特征即选非零权重:
from sklearn.linear_model import Lasso, LogisticRegression
# 回归用 Lasso,分类用 LogisticRegression(penalty='l1', solver='liblinear')
sel = Lasso(alpha=0.01).fit(X_scaled, y)
nonzero = (sel.coef_ != 0) # True = 保留该特征
7.2 树模型特征重要性
随机森林/梯度提升自带特征重要性,按重要性阈值裁掉尾部特征:
from sklearn.ensemble import RandomForestClassifier
import numpy as np
rf = RandomForestClassifier(n_estimators=200).fit(X, y)
imp = rf.feature_importances_
keep = imp > np.quantile(imp, 0.3) # 砍掉最低 30%
记忆:嵌入法在训练里学特征权重——L1 把不重要特征压成 0、树模型按重要性裁尾部;性价比最高,生产最常用。
8. 特征选择的最大坑:数据泄漏
8.1 泄漏的典型场景
在交叉验证之前就用全量数据做选择/缩放,让验证折的统计信息(均值/方差/选择结果)渗入训练——分数虚高、上线崩盘:
# 反模式:先对全量数据选特征,再交叉验证
X_all_sel = SelectKBest(k=20).fit_transform(X_all, y) # 泄漏!选择用了全量 y
scores = cross_val_score(model, X_all_sel, y, cv=5)
8.2 正确做法:选择器放进 Pipeline
让选择器作为 Pipeline 的一步,交叉验证的每一折只在训练折上 fit 选择器:
# 正确:选择器在 Pipeline 里,每折只对训练部分 fit
pipe = Pipeline([
("scale", StandardScaler()),
("select", SelectKBest(k=20)),
("clf", LogisticRegression()),
])
scores = cross_val_score(pipe, X, y, cv=5) # 无泄漏
记忆:特征选择/缩放的 fit 必须发生在每一折的训练集上——把选择器放进 Pipeline 让交叉验证自动防泄漏,这是铁的纪律。
9. Pipeline 与交叉验证的配合
9.1 完整落地模板
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import classification_report
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
pipe = Pipeline([
("pre", ColumnTransformer([...])),
("select", SelectKBest(...)),
("clf", RandomForestClassifier(n_estimators=200)),
])
gs = GridSearchCV(pipe, param_grid, cv=5, scoring="f1")
gs.fit(X_tr, y_tr)
print(classification_report(y_te, gs.predict(X_te)))
9.2 调试与扩展
# 想看中间结果:pipe.named_steps 拿到任一步
# 想加步骤:中间插入 estimators 即可
# 想序列化:joblib.dump(pipe, "pipe.pkl") 一键保存整条链
# 上线一致性:预测端加载同一个 pipe,预处理自动带上
记忆:Pipeline + 交叉验证是防泄漏的标准组合——train_test_split 切分、GridSearchCV 调参、named_steps 调试、joblib 一键上线,预处理随模型一起部署。
10. 速查表与一句话记忆
| 工具 | 用途 | 一句话 |
|---|---|---|
| Pipeline | 串起预处理+模型 | 一步 fit、一步预测 |
| ColumnTransformer | 异构分列处理 | 数值缩放/类别编码分流 |
| VarianceThreshold | 删零方差 | 无信息列先删 |
| SelectKBest | 按检验选 Top-K | 过滤法代表 |
| RFE/RFECV | 递归砍最小权重 | 包裹法、准而慢 |
| Lasso / 树重要性 | 嵌入法选特征 | 训练中自动学权重 |
| GridSearchCV | Pipeline 调参 | 步骤名__参数名 |
一句话记忆:Pipeline 让预处理+模型打包成一个可复用、可整体交叉验证的对象(ColumnTransformer 分列处理异构数据);特征选择三条路——过滤法按统计粗筛(SelectKBest)、包裹法按模型效果精选(RFE)、嵌入法在训练里学权重(Lasso/树重要性);最大的坑是数据泄漏——选择器和缩放器必须在每一折的训练集上 fit,放进 Pipeline 让交叉验证自动防泄漏;落地时 joblib 保存整条链,上线预测与训练用同一个预处理路径。
延伸阅读
- /ml-feature-engineering/ — 特征清洗、构造、编码与防泄漏纪律
- /ml-model-evaluation/ — 交叉验证与过拟合
- /ml-supervised-classification/ — 分类任务全流程
- /ml-model-interpretability/ — 特征重要性与 SHAP
- [[ai-ml]] — 大规模特征工程与训练流水线
- sklearn Pipeline 文档
- sklearn 特征选择文档
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。