Skip to content

提升机器学习模型性能 (续)

构建初始的机器学习模型仅仅是第一步。要达到最优性能,通常需要迭代地进行改进。这包括各种策略,例如数据预处理、特征工程、算法选择以及超参数调优 (hyperparameter tuning)(也称为算法调优)。

大多数机器学习算法都有一些设置,称为超参数 (hyperparameters),这些参数不是从数据中学习得到的,而是在训练过程开始之前设置的。这些超参数控制着学习过程本身的各个方面,例如模型的复杂度或正则化强度。

例子包括:

  • 支持向量机 (SVM) 中的 C 参数。
  • K 近邻 (KNN) 中的 k。
  • 岭回归 (Ridge) 或 Lasso 回归中的 alpha 正则化参数。
  • 随机森林 (Random Forests) 中的树的数量 (n_estimators) 或最大深度 (max_depth)。

相比之下,参数 (parameters)(例如线性回归中的系数或神经网络中的权重)是在训练过程中从数据中学习得到的。

**超参数调优(或优化)**是系统性地搜索超参数值组合的过程,以找到在给定问题和数据集上能够产生最佳模型性能(在验证集上或通过交叉验证评估)的组合。

Scikit-learn 为此提供了出色的工具,主要是网格搜索 (Grid Search) 和随机搜索 (Randomized Search)。

网格搜索对超参数空间的指定子集执行穷举搜索。你定义一个想要尝试的超参数值“网格”,然后 GridSearchCV 会使用交叉验证对所有可能的组合进行模型训练和评估。

优点: 保证找到指定网格内的最佳组合。

缺点: 计算成本可能非常高,特别是当网格很大或涉及很多超参数时(“维度诅咒”)。

示例:对岭回归的 alpha 进行调优

Section titled “示例:对岭回归的 alpha 进行调优”

我们将在 Diabetes 数据集上对岭回归 (Ridge Regression) 的正则化强度 (alpha) 进行调优。

import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.linear_model import Ridge
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 加载 diabetes 数据集
diabetes = load_diabetes()
X, y = diabetes.data, diabetes.target
# 使用正则化时,对数据进行缩放至关重要
# 我们使用 Pipeline 将缩放和模型组合在一起
pipe = Pipeline([
('scaler', StandardScaler()),
('ridge', Ridge())
])
# 定义要搜索的 alpha 值网格
# 对于正则化参数,使用对数范围很常见
alphas = np.logspace(-4, 2, 7) # 示例:从 0.0001 到 100 的 7 个值
param_grid = {'ridge__alpha': alphas} # 注意管道步骤使用 '__' 表示法
# 设置 GridSearchCV
# cv=5 表示 5 折交叉验证
# scoring='neg_mean_squared_error' - GridSearchCV 最大化分数,所以使用负 MSE 进行最小化
grid_search = GridSearchCV(estimator=pipe,
param_grid=param_grid,
cv=5,
scoring='neg_mean_squared_error',
verbose=1) # verbose 显示进度
# 将网格搜索拟合到数据上
grid_search.fit(X, y)
# 打印最佳分数 (平均 CV 分数) 和最佳参数
print(f"Best Cross-Validation Score (Negative MSE): {grid_search.best_score_:.4f}")
print(f"Best Parameters found: {grid_search.best_params_}")
# 访问最佳估计器 (带有最佳 alpha 的 pipeline)
best_model = grid_search.best_estimator_
print(f"\nBest Ridge alpha: {best_model.named_steps['ridge'].alpha}")
Fitting 5 folds for each of 7 candidates, totalling 35 fits
...
Best Cross-Validation Score (Negative MSE): -2921.4895
Best Parameters found: {'ridge__alpha': 1.0}
Best Ridge alpha: 1.0

输出显示了在交叉验证期间获得的最佳负 MSE 分数以及产生此分数的相应 alpha 值(在此示例运行中为 1.0)。使用 Pipeline 确保在每个交叉验证折叠中正确执行了数据缩放。

随机搜索从指定的统计分布(或列表中)随机抽取固定数量 (n_iter) 的超参数组合。它不会尝试所有组合,而是探索参数空间的随机子集。

优点: 计算效率比网格搜索高得多,尤其是在超参数很多的情况下。通常能更快地找到非常好的(即使不是绝对最优的)超参数。

缺点: 不保证找到最优组合;结果取决于迭代次数和随机采样。

示例:对岭回归的 alpha 进行调优

Section titled “示例:对岭回归的 alpha 进行调优”

我们将使用随机搜索更有效地探索更广泛的 alpha 值范围。

import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.linear_model import Ridge
from sklearn.model_selection import RandomizedSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from scipy.stats import uniform # 用于从均匀分布中采样
# 加载 diabetes 数据集
diabetes = load_diabetes()
X, y = diabetes.data, diabetes.target
# 设置 pipeline
pipe = Pipeline([
('scaler', StandardScaler()),
('ridge', Ridge())
])
# 定义要采样的参数分布
# 从 0 到 10 的均匀分布中采样 alpha
param_distributions = {
'ridge__alpha': uniform(loc=0, scale=10) # 从 U(0, 10) 中采样
}
# 设置 RandomizedSearchCV
# n_iter 控制采样多少个参数设置
# random_state 确保结果可复现
random_search = RandomizedSearchCV(estimator=pipe,
param_distributions=param_distributions,
n_iter=50, # 尝试 50 种随机组合
cv=5,
scoring='neg_mean_squared_error',
random_state=42,
verbose=1)
# 将随机搜索拟合到数据上
random_search.fit(X, y)
# 打印最佳分数和最佳参数
print(f"Best Cross-Validation Score (Negative MSE): {random_search.best_score_:.4f}")
print(f"Best Parameters found: {random_search.best_params_}")
# 访问最佳估计器
best_model = random_search.best_estimator_
print(f"\nBest Ridge alpha: {best_model.named_steps['ridge'].alpha:.4f}")
Fitting 5 folds for each of 50 candidates, totalling 250 fits
...
Best Cross-Validation Score (Negative MSE): -2921.4214
Best Parameters found: {'ridge__alpha': 0.9370821941623886}
Best Ridge alpha: 0.9371

随机搜索探索了从均匀分布中采样的 50 个不同的 alpha 值。最佳分数与网格搜索找到的非常接近,但如果在网格搜索空间大得多时,计算量可能更少。找到的最佳 alpha 大约为 0.937。

除了超参数调优,还可以考虑以下策略:

  • 特征工程 (Feature Engineering): 从现有特征创建新特征,选择相关特征,或移除不相关/冗余的特征。
  • 数据增强/收集 (Data Augmentation/Collection): 获取更多相关的训练数据。
  • 处理缺失数据 (Handling Missing Data): 使用适当的插补技术。
  • 处理类别不平衡 (Addressing Class Imbalance): 使用 SMOTE、ADASYN 等技术或调整类别权重。
  • 算法选择 (Algorithm Selection): 尝试不同类型的算法,它们可能更适合数据的结构。
  • 集成方法 (Ensemble Methods): 组合多个模型(例如 Bagging, Boosting, Stacking)通常能带来比单一模型更好的性能和鲁棒性。

对于复杂的搜索空间或计算成本高昂的模型,存在更高级的技术:

  • 贝叶斯优化 (Bayesian Optimization): 使用概率模型引导搜索,以更有前景的超参数区域为目标(例如,使用 scikit-optimize 或 Hyperopt 等库)。
  • 逐次减半 / HyperBand (Successive Halving / HyperBand): 迭代地将资源分配给有前景的配置,快速淘汰效果差的配置(例如,较新版本 scikit-learn 中的 HalvingGridSearchCV, HalvingRandomSearchCV)。