跑通一个项目,不等于得到了可信的评估。最值得反复检查的问题是:测试数据是否以某种方式参与了训练流程的决定?

对讲义流程的一处修正

课程的第二次实操强调按步骤理解流程,但不能把“编码、缺失处理在划分前;标准化在划分后”当成通用规则。判断依据应是:这个步骤是否需要从样本中学习信息。

操作 需要注意的边界
依据事先确定的格式规则解析日期、修正单位 可对所有样本使用同一套固定规则
根据中位数补缺失、学习类别词表、计算缩放参数 只在训练数据上拟合
特征选择、PCA、过采样 同样应置于训练或交叉验证折内部
调整异常值阈值、选模型、选超参数 不使用最终测试集做决定

固定的数据质量规则和“看完全部数据才决定的清洗方案”不是一回事。scikit-learn 明确将插补、缩放和特征选择等列为可能发生泄漏的环节,建议先划分并使用流水线。参见 数据泄漏说明。

一个独立编写的最小实验

下面用鸢尾花数据演示技术流程,不使用课程中的临床示例,也不涉及实际医疗判断。需要安装 NumPy 和 scikit-learn。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import StratifiedKFold, cross_val_score, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

X, y = load_iris(return_X_y=True)
X = X.copy()
X[::17, 0] = np.nan
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=7, stratify=y
)
model = Pipeline([
    ("imputer", SimpleImputer(strategy="median")),
    ("scaler", StandardScaler()),
    ("classifier", LogisticRegression(max_iter=1000)),
])
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=7)
scores = cross_val_score(model, X_train, y_train, cv=cv, scoring="accuracy")
model.fit(X_train, y_train)
prediction = model.predict(X_test)

assert prediction.shape == y_test.shape
assert model.named_steps["scaler"].n_samples_seen_ == len(X_train)
assert np.allclose(
    model.named_steps["imputer"].statistics_, np.nanmedian(X_train, axis=0)
)
print("CV mean:", round(float(scores.mean()), 4))
print("Test accuracy:", round(float(accuracy_score(y_test, prediction)), 4))

这里交叉验证接收的是整条流水线,因此每一折会重新拟合自己的预处理。最终模型再在完整训练集上拟合,测试集只接受转换和预测。Pipeline 官方接口说明了各步骤的串联与拟合方式。

验收与限制

  • 能说明每个 fit 看到了哪些样本。
  • 能解释为什么不能先对全量数据做特征选择,再交叉验证。
  • 不根据测试准确率反复修改模型后,仍把它称为一次独立测试。
  • 有重复对象或时间顺序时,重新设计划分方式;Pipeline 本身不会替你解决对象泄漏、未来信息或标签泄漏。

课程对应与整理边界

对应疏锦行《机器学习 26 考/保研基础班》的第二次实操讲义与“渐进式按流程提问”“一次性提问思路”视频目录。本文以流程核验和纠错为主,代码为独立编写;不声称已完整核验这些视频的口头讲解。

原课程