F FisherHub Docs

模型评估与调优

为什么评估很重要

模型评估是机器学习流程中不可或缺的一环。没有科学的评估方法,我们无法判断模型是否真正有效,也无法比较不同模型的优劣。

核心评估指标

分类指标

以二分类为例,基于混淆矩阵(Confusion Matrix)定义:

  • TP(True Positive) — 正类被正确预测为正类
  • TN(True Negative) — 负类被正确预测为负类
  • FP(False Positive) — 负类被错误预测为正类(误报)
  • FN(False Negative) — 正类被错误预测为负类(漏报)

准确率(Accuracy)

所有预测中正确的比例:

Accuracy = (TP + TN) / (TP + TN + FP + FN)

在类别不平衡的情况下准确率可能产生误导。例如 95% 负类、5% 正类的数据集,模型全部预测为负类也能达到 95% 的准确率。

精确率(Precision)与召回率(Recall)

Precision = TP / (TP + FP)   — 预测为正类中有多少是真正的正类
Recall    = TP / (TP + FN)   — 所有正类中有多少被找了出来

精确率和召回率往往此消彼长。具体选择哪个指标取决于业务场景:

  • 垃圾邮件检测:更看重 Precision(误删正常邮件不可接受)
  • 癌症筛查:更看重 Recall(漏诊后果严重)

F1 分数

精确率和召回率的调和平均数:

F1 = 2 × (Precision × Recall) / (Precision + Recall)
from sklearn.metrics import (
    accuracy_score, precision_score, 
    recall_score, f1_score, classification_report
)

y_true = [0, 1, 1, 0, 1, 0]
y_pred = [0, 1, 0, 0, 1, 1]

print(f"准确率: {accuracy_score(y_true, y_pred):.2f}")
print(f"精确率: {precision_score(y_true, y_pred):.2f}")
print(f"召回率: {recall_score(y_true, y_pred):.2f}")
print(f"F1: {f1_score(y_true, y_pred):.2f}")
print(classification_report(y_true, y_pred))

ROC 曲线与 AUC

ROC 曲线展示不同阈值下 TPR(True Positive Rate)与 FPR(False Positive Rate)的关系。AUC(Area Under Curve)是曲线下面积,值越大说明模型分类能力越强。

回归指标

  • MAE(平均绝对误差) — 直观反映预测误差大小
  • MSE(均方误差) — 对大误差施加更大惩罚
  • RMSE — MSE 的平方根,与原始单位一致
  • R²(决定系数) — 模型解释了多少方差
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

y_true = [3.0, 2.5, 4.0, 3.5]
y_pred = [2.8, 2.7, 3.8, 3.6]

print(f"MAE: {mean_absolute_error(y_true, y_pred):.3f}")
print(f"MSE: {mean_squared_error(y_true, y_pred):.3f}")
print(f"R²: {r2_score(y_true, y_pred):.3f}")

交叉验证

交叉验证是评估模型泛化能力的核心技术,通过反复将数据划分为训练集和验证集来获得更稳健的性能估计。

K-Fold 交叉验证

将数据分成 K 份,轮流将其中一份作为验证集,其余 K-1 份作为训练集,最终取 K 次评估的平均值。

from sklearn.model_selection import cross_val_score, KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris

iris = load_iris()
model = RandomForestClassifier()

kfold = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, iris.data, iris.target, 
                         cv=kfold, scoring="accuracy")

print(f"每折准确率: {scores}")
print(f"平均准确率: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})")

其他交叉验证方法

  • Stratified K-Fold — 保持每折的类别分布与整体一致
  • Leave-One-Out(LOO) — 每次只留一个样本做验证
  • Time Series Split — 时间序列数据专用,避免未来信息泄露

超参数调优

超参数是训练开始前需要设定的参数,不同于模型在训练过程中学习的参数。

穷举所有超参数组合,简单但计算成本高。

from sklearn.model_selection import GridSearchCV

param_grid = {
    "n_estimators": [50, 100, 200],
    "max_depth": [None, 10, 20],
    "min_samples_split": [2, 5, 10]
}

grid_search = GridSearchCV(
    RandomForestClassifier(),
    param_grid,
    cv=5,
    scoring="f1",
    n_jobs=-1
)
grid_search.fit(X_train, y_train)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳得分: {grid_search.best_score_:.3f}")

在参数空间中随机采样,通常比网格搜索更高效。在同样的预算下能探索更多的参数组合。

贝叶斯优化

使用高斯过程或 Tree-Structured Parzen Estimators(TPE)来建模超参数与模型性能的关系,在参数空间中智能地选择下一个要尝试的点。库:Hyperopt、Optuna。

import optuna

def objective(trial):
    n_estimators = trial.suggest_int("n_estimators", 50, 300)
    max_depth = trial.suggest_int("max_depth", 5, 30)
    lr = trial.suggest_float("lr", 1e-4, 1e-1, log=True)

    model = SomeModel(n_estimators, max_depth, lr)
    score = cross_val_score(model, X, y, cv=3).mean()
    return score

study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=50)
print(f"最佳参数: {study.best_params}")

过拟合与欠拟合

  • 过拟合 — 模型在训练集上表现好但验证集上差。解决:增加数据量、降低模型复杂度、正则化、早停
  • 欠拟合 — 模型在训练集上表现就不够好。解决:增强特征、增加模型复杂度、减少正则化

模型评估与调优是一个迭代的过程,需要结合领域知识和实验经验才能达到理想的效果。