机器学习实验手册
本手册把机器学习知识变成可重复的实验。建议每个实验都保留:问题定义、数据版本、训练/验证/测试划分、基线、指标、错误分析和结论。
1. 环境准备
python -m venv .venv
# Windows: .venv\Scripts\activate
# macOS/Linux: source .venv/bin/activate
python -m pip install -U pip
pip install numpy pandas matplotlib scikit-learn joblib建议把依赖版本写入 requirements.txt;正式实验使用锁定版本的环境,避免不同版本造成结果漂移。
2. 先理解问题与数据
| 问题 | 目标 | 常见指标 |
|---|---|---|
| 回归 | 预测连续数值 | MAE、RMSE、R² |
| 二分类 | 判断两个类别 | Precision、Recall、F1、ROC-AUC、PR-AUC |
| 多分类 | 预测多个互斥类别 | Accuracy、Macro-F1、混淆矩阵 |
| 聚类 | 发现无标签分组 | Silhouette、Davies–Bouldin(结合业务解释) |
| 异常检测 | 找出少数异常样本 | Precision@K、Recall、PR-AUC |
先问清楚:预测发生在什么时候?预测时能拿到哪些特征?漏报和误报哪个代价更高?如果特征包含预测时刻之后才产生的信息,就可能发生数据泄漏。
3. 核心算法的直觉与公式
3.1 线性回归
模型:。常见平方误差目标:
它适合建立可解释基线。注意异常值会显著影响平方误差;特征量纲差异较大时,正则化前通常需要标准化。
3.2 逻辑回归
二元交叉熵:
输出是概率估计,不是天然可靠的业务决策。阈值应根据误报/漏报成本和验证集选择。
3.3 决策树与随机森林
决策树通过特征切分降低节点不纯度。分类常见 Gini:
随机森林对多个随机化决策树进行集成,降低单棵树方差;代价是模型体积、推理开销和解释难度增加。
3.4 梯度提升树
每轮拟合当前模型的残差或损失梯度,逐步修正错误。XGBoost、LightGBM、CatBoost 是表格数据常见强基线。调参时重点关注树深、学习率、树数量、叶子数、采样比例和正则化。
3.5 支持向量机
最大间隔分类器通过间隔与惩罚项权衡泛化和训练误差。核函数可表达非线性边界,但大样本训练成本可能较高;特征尺度对结果影响明显。
4. 可运行分类实验:乳腺癌数据集
下面示例使用 Pipeline,确保标准化只在训练折上拟合,避免先对全量数据标准化造成泄漏。
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, StratifiedKFold, cross_validate
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, test_size=0.2,
random_state=42, stratify=data.target
)
model = make_pipeline(
StandardScaler(),
LogisticRegression(max_iter=3000, class_weight="balanced")
)
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_validate(
model, X_train, y_train, cv=cv,
scoring=["f1", "roc_auc"], return_train_score=False
)
print("CV F1:", scores["test_f1"].mean())
print("CV ROC-AUC:", scores["test_roc_auc"].mean())
model.fit(X_train, y_train)
pred = model.predict(X_test)
prob = model.predict_proba(X_test)[:, 1]
print(confusion_matrix(y_test, pred))
print(classification_report(y_test, pred, target_names=data.target_names))
print("Test ROC-AUC:", roc_auc_score(y_test, prob))说明:该数据集适合教学,不代表真实临床系统。不要把教学实验当作医疗诊断工具。
5. 实验对比:不要只报一个准确率
建议至少比较:
- DummyClassifier:确认模型是否真的优于简单基线。
- LogisticRegression:可解释线性基线。
- RandomForest / HistGradientBoosting:非线性树模型。
- 不同阈值:观察 Precision 与 Recall 的权衡。
- 类别不平衡处理:class_weight、重采样;重采样必须只在训练折内完成。
6. 常见错误排查
| 现象 | 优先检查 |
|---|---|
| 训练分数高、测试分数低 | 过拟合、数据泄漏、分布漂移、样本量 |
| 所有指标都很差 | 标签定义、特征、数据质量、基线和实现 |
| Accuracy 很高但业务效果差 | 类别不平衡,检查 Recall、PR-AUC、混淆矩阵 |
| 交叉验证波动很大 | 样本量、分层划分、分组/时间相关性 |
| 线上效果下降 | 数据漂移、特征计算差异、标签延迟、训练服务不一致 |
时间序列必须按时间切分;同一用户/设备有多条记录时,考虑 Group split,避免同一实体同时进入训练集和测试集。
7. 进阶实验任务
- 用同一数据集比较逻辑回归、随机森林、梯度提升树。
- 绘制学习曲线,判断增加数据是否可能改善泛化。
- 用校准曲线检查概率是否可信。
- 使用 Permutation Importance 分析特征影响,并检查相关特征的解释局限。
- 构建一个带时间切分的预测任务,验证没有未来信息泄漏。
- 保存模型、预处理器、依赖版本和评估报告,写出可复现实验 README。
8. 学习资料
- scikit-learn 用户指南
- scikit-learn 示例
- Hands-On Machine Learning 配套代码
- StatQuest:算法直觉讲解
- Google Machine Learning Crash Course