第29课:scikit-learn|网格搜索、随机搜索、交叉验证、超参数自动调优全攻略

在这里插入图片描述

文章目录


课前导读

欢迎来到第29课!在之前的算法课程中,你接触了很多超参数:决策树的max_depth、随机森林的n_estimators、SVM的Cgamma……这些参数不同取值会极大影响模型性能。很多人调参靠“手感”——试着改一下,看分数变化,再试下一个。这种方法不仅耗时,而且容易陷入局部最优。

本课将教你系统化、自动化的超参数调优方法。核心思想很简单:定义参数候选范围,用交叉验证评估每个组合,然后选出最佳。网格搜索暴力穷举所有组合,适合参数少的情况;随机搜索随机采样,效率更高,尤其适合高维参数空间。此外,你还将学习如何用对数尺度搜索学习率等跨度大的参数,以及如何利用早停策略加速搜索。学完本课,你将告别“炼丹式”调参,用科学的方法找到最佳模型。

学习目标

完成本课学习后,你将能够:

  1. 解释 交叉验证在超参数调优中的作用:防止信息泄露,提供稳定的性能估计
  2. 使用 GridSearchCV 进行网格搜索,理解参数网格的定义方式
  3. 使用 RandomizedSearchCV 进行随机搜索,掌握参数分布(distributions)的设置
  4. 理解 对数均匀分布(loguniform)在宽范围参数(如学习率)中的应用
  5. 使用 HalvingGridSearchCV / HalvingRandomSearchCV(连续减半搜索)加速调参
  6. 分析 调参结果:cv_results_ 属性,绘制参数与分数的关系图
  7. 避免 常见的调参陷阱:测试集泄露、数据划分不当、过拟合验证集
  8. 应用 嵌套交叉验证评估最终模型的泛化性能

知识点理论讲解

一、超参数与模型参数的区别

  • 模型参数:在训练过程中从数据中学习得到的,如线性回归的系数coef_
  • 超参数:在训练前需要人为设定的,如决策树的深度、SVM的C、随机森林的树数量。超参数的取值直接影响模型的结构和复杂度。

调参的目标:找到一组超参数,使得模型在未见过的数据上表现最佳。

二、交叉验证在调参中的作用

如果我们在同一测试集上反复调参、选择最佳模型,则测试集会逐渐被“污染”,最终评估的泛化性能会被高估。因此,调参时不能触碰测试集,而是用交叉验证来评估每一组超参数的稳定性。

标准流程:

  1. 将原始数据划分为训练集 + 测试集(测试集仅用于最终评估)。
  2. 在训练集上进行交叉验证(如5折),每组超参数得到平均验证分数。
  3. 选择交叉验证分数最高的超参数组合。
  4. 用该组合在整个训练集上重新训练模型,最后在测试集上评估一次。

交叉验证确保调参过程不依赖于某一次特定的数据划分。

三、网格搜索(GridSearchCV)

原理:穷举给定的参数候选值列表,对所有组合进行交叉验证,选择得分最高的一组。

优点:保证在候选空间中找到最优组合(若候选空间包含全局最优)。
缺点:当参数较多、候选值较多时,计算量爆炸(维度灾难)。例如,3个参数,每个有10个候选,需要训练 10^3 = 1000 次模型,每次还要 K 折交叉验证(如5折),总训练次数 = 参数组合数 × K

适用:参数空间小(≤4维),候选值少。

四、随机搜索(RandomizedSearchCV)

原理:在参数空间中按指定分布随机采样一定数量的组合(n_iter),对每个组合进行交叉验证。

优点

  • 效率远高于网格搜索,尤其当大部分参数对性能影响不大时,随机搜索可以更快找到较好的区域。
  • 支持参数分布(如对数均匀分布),可以更智能地搜索宽范围参数。

缺点:不保证找到全局最优(但通常能找到足够好的解)。

适用:参数空间较大,或有一些参数具有宽范围(如学习率 1e-5 到 1)。

五、连续减半搜索(HalvingGridSearchCV / HalvingRandomSearchCV)

原理:一种迭代式搜索策略,初始用大量参数组合,但只用少量资源(如少量样本或少量迭代)评估,保留表现最好的一半,下一轮加倍资源,直到达到全部资源。

优点:比随机搜索更高效,能更早淘汰差参数。
缺点:实现复杂,可能因过早淘汰而错失后期表现好的参数。

六、参数空间的构建

定义参数候选的方式:

  1. 列表{'C': [0.1, 1, 10], 'gamma': [0.01, 0.1, 1]}
  2. 范围(随机搜索)
    • scipy.stats.uniform(loc, scale):均匀分布
    • scipy.stats.loguniform(a, b):对数均匀分布(适合学习率等跨度大的参数)
    • scipy.stats.randint(a, b):整数均匀分布

七、结果分析与最佳模型

搜索完成后,可以从 cv_results_ 属性中提取详细信息:

  • mean_test_score:每组参数的平均交叉验证分数
  • std_test_score:标准差(反映稳定性)
  • params:参数组合
  • rank_test_score:排名

最佳模型可通过 best_estimator_best_params_best_score_ 获取。

八、嵌套交叉验证

当我们想评估整个调优流程(包括参数搜索)的泛化性能时,需要使用嵌套交叉验证:

  • 外层循环:划分训练/测试集,内层循环:对该训练集进行超参数搜索(含交叉验证),然后用得到的模型预测外层测试集。
  • 最终分数是所有外层测试分数的平均值,避免了因调参而导致的测试集信息泄露。

核心原理通俗拆解

网格搜索:试遍所有菜谱

你想做一道最好吃的菜,有盐量(三种)、糖量(三种)、火候(三种)。你把所有 27 种组合都做一遍,请朋友打分(交叉验证),选出最好吃的配方。这就是网格搜索。

随机搜索:随机试菜

27 种组合太多,你只随机试其中的 10 种,大概率也能找到不错的配方,尤其当某些调料对味道影响不大时。

连续减半搜索:比赛淘汰制

先让 100 个选手(参数组合)初赛(用小数据),淘汰 50 个;剩下的复赛(用更多数据),再淘汰一半,直到决出冠军。这样比让所有选手直接比完整比赛更省时间。

底层数学逻辑

1. 交叉验证的方差与偏差

K 折交叉验证的均方误差估计的方差约为 σ²/K,K 越大,估计越稳定,但计算量也越大。通常取 K=5 或 10。

2. 随机搜索的收敛性

随机搜索在参数空间上采样,其找到最优解的概率与采样次数正相关。若最优解区域的体积占比为 p,则采样 n 次至少命中一次的概率为 1 - (1-p)^n。因此当参数空间很大时,随机搜索比网格搜索更高效。

3. 对数均匀分布

对于学习率 η,其有效范围往往跨越多个数量级(如 0.0001 到 0.1)。如果使用均匀分布,大多数点会集中在大值区域,小值区域被忽略。对数均匀分布使得在数量级上均匀采样,例如 10⁻⁴, 10⁻³, 10⁻² 等。

scikit-learn API详解

GridSearchCV

from sklearn.model_selection import GridSearchCV

grid = GridSearchCV(
    estimator,                # 模型对象
    param_grid,               # 参数网格字典
    scoring=None,             # 评估指标(字符串或可调用对象)
    n_jobs=None,              # 并行数
    cv=5,                     # 交叉验证折数
    verbose=0,
    pre_dispatch='2*n_jobs',
    return_train_score=False,
    refit=True,               # 是否用最佳参数在整个训练集上重新训练
    error_score=np.nan
)

grid.fit(X_train, y_train)
print(grid.best_params_)
print(grid.best_score_)
best_model = grid.best_estimator_
test_score = best_model.score(X_test, y_test)

RandomizedSearchCV

from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import uniform, loguniform, randint

param_dist = {
    'C': loguniform(1e-3, 1e3),
    'gamma': loguniform(1e-4, 1e-1),
    'kernel': ['rbf', 'linear']
}

rand = RandomizedSearchCV(
    SVC(), param_distributions=param_dist,
    n_iter=50, cv=5, random_state=42, n_jobs=-1
)
rand.fit(X_train, y_train)

HalvingGridSearchCV / HalvingRandomSearchCV

from sklearn.experimental import enable_halving_search_cv
from sklearn.model_selection import HalvingRandomSearchCV

halving = HalvingRandomSearchCV(
    estimator, param_distributions=param_dist,
    n_candidates='exhaust',   # 初始候选数
    factor=3,                  # 每轮保留候选数的倒数
    resource='n_samples',     # 资源类型(样本数或迭代次数)
    max_resources='auto',
    min_resources='smallest',
    random_state=42
)

环境配置与依赖安装

本课需要 scipy(用于参数分布)。

conda activate sklearn_tutorial
pip install scipy

完整代码实战(带详细注释)

实战1:GridSearchCV 基础——SVM 调参

# -*- coding: utf-8 -*-
"""
网格搜索 SVM 的 C 和 gamma 参数
数据集:手写数字二分类(0和1)
"""

from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# 加载数据(二分类)
digits = load_digits()
mask = (digits.target == 0) | (digits.target == 1)
X, y = digits.data[mask], digits.target[mask]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建 Pipeline(标准化 + SVM)
pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('svm', SVC())
])

# 参数网格
param_grid = {
    'svm__C': [0.1, 1, 10, 100],
    'svm__gamma': [0.001, 0.01, 0.1, 1],
    'svm__kernel': ['rbf']
}

grid = GridSearchCV(pipe, param_grid, cv=5, scoring='accuracy', n_jobs=-1, verbose=1)
grid.fit(X_train, y_train)

print("最佳参数:", grid.best_params_)
print("最佳交叉验证准确率: {:.4f}".format(grid.best_score_))
print("测试集准确率: {:.4f}".format(grid.score(X_test, y_test)))

实战2:RandomizedSearchCV 高效搜索

# -*- coding: utf-8 -*-
"""
随机搜索 SVM 的 C 和 gamma,使用对数均匀分布
"""

from sklearn.datasets import load_digits
from sklearn.model_selection import RandomizedSearchCV, train_test_split
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from scipy.stats import loguniform

X, y = load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

param_dist = {
    'C': loguniform(1e-2, 1e3),
    'gamma': loguniform(1e-4, 1),
    'kernel': ['rbf', 'linear']
}

rand = RandomizedSearchCV(SVC(), param_distributions=param_dist,
                          n_iter=50, cv=5, scoring='accuracy',
                          random_state=42, n_jobs=-1, verbose=1)
rand.fit(X_train_scaled, y_train)

print("最佳参数:", rand.best_params_)
print("最佳交叉验证准确率: {:.4f}".format(rand.best_score_))
print("测试集准确率: {:.4f}".format(rand.score(X_test_scaled, y_test)))

实战3:随机森林的网格搜索

# -*- coding: utf-8 -*-
"""
随机森林调参:n_estimators, max_depth, min_samples_split
"""

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, GridSearchCV

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

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

rf = RandomForestClassifier(random_state=42)
grid = GridSearchCV(rf, param_grid, cv=5, scoring='accuracy', n_jobs=-1, verbose=1)
grid.fit(X_train, y_train)

print("最佳参数:", grid.best_params_)
print("最佳交叉验证准确率: {:.4f}".format(grid.best_score_))
print("测试集准确率: {:.4f}".format(grid.score(X_test, y_test)))

实战4:GBDT 调参(学习率与树数量)

# -*- coding: utf-8 -*-
"""
使用随机搜索优化 GBDT 的学习率、树数量、深度等
同时利用 early stopping 提前停止(但 RandomizedSearchCV 不支持动态早停,仅演示参数)
"""

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import RandomizedSearchCV, train_test_split
from scipy.stats import loguniform, randint

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

param_dist = {
    'n_estimators': randint(50, 300),
    'learning_rate': loguniform(1e-3, 0.5),
    'max_depth': randint(2, 8),
    'subsample': [0.7, 0.8, 0.9, 1.0],
    'min_samples_split': randint(2, 20)
}

gbdt = GradientBoostingClassifier(random_state=42)
rand = RandomizedSearchCV(gbdt, param_dist, n_iter=30, cv=5, 
                          scoring='roc_auc', random_state=42, n_jobs=-1)
rand.fit(X_train, y_train)

print("最佳参数:", rand.best_params_)
print("最佳交叉验证 AUC: {:.4f}".format(rand.best_score_))
print("测试集 AUC: {:.4f}".format(rand.score(X_test, y_test)))

实战5:分析 cv_results_ 可视化调参过程

# -*- coding: utf-8 -*-
"""
从 cv_results_ 中提取结果,绘制参数与分数关系图
"""

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import GridSearchCV

X, y = make_classification(n_samples=500, n_features=10, random_state=42)

param_grid = {
    'n_estimators': [50, 100, 150, 200],
    'max_depth': [5, 10, 15, 20]
}
rf = RandomForestClassifier(random_state=42)
grid = GridSearchCV(rf, param_grid, cv=3, return_train_score=True)
grid.fit(X, y)

results = pd.DataFrame(grid.cv_results_)
# 绘制 max_depth 固定时,n_estimators 对分数的影响
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
for depth in [5, 10, 15, 20]:
    subset = results[results['param_max_depth'] == depth]
    axes[0].plot(subset['param_n_estimators'], subset['mean_test_score'], 'o-', label=f'depth={depth}')
axes[0].set_xlabel('n_estimators')
axes[0].set_ylabel('交叉验证准确率')
axes[0].legend()
axes[0].set_title('不同 max_depth 下 n_estimators 的影响')

# 热力图展示参数交互
pivot = results.pivot(index='param_max_depth', columns='param_n_estimators', values='mean_test_score')
im = axes[1].imshow(pivot.values, cmap='viridis', aspect='auto')
axes[1].set_xticks(range(len(pivot.columns)))
axes[1].set_xticklabels(pivot.columns)
axes[1].set_yticks(range(len(pivot.index)))
axes[1].set_yticklabels(pivot.index)
axes[1].set_xlabel('n_estimators')
axes[1].set_ylabel('max_depth')
axes[1].set_title('平均测试分数热力图')
plt.colorbar(im, ax=axes[1])
plt.tight_layout()
plt.show()

实战6:嵌套交叉验证评估泛化性能

# -*- coding: utf-8 -*-
"""
嵌套交叉验证:外层 CV 评估调优流程,内层 CV 进行参数搜索
避免因调参导致的测试集信息泄露
"""

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import cross_val_score, GridSearchCV, KFold
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

X, y = load_breast_cancer(return_X_y=True)

# 定义 Pipeline 和参数网格
pipe = Pipeline([('scaler', StandardScaler()), ('svm', SVC())])
param_grid = {'svm__C': [0.1, 1, 10], 'svm__gamma': [0.01, 0.1, 1]}

# 内层 CV:GridSearchCV 自动做交叉验证
inner_cv = KFold(n_splits=5, shuffle=True, random_state=42)
outer_cv = KFold(n_splits=5, shuffle=True, random_state=42)

# 使用 cross_val_score 的 estimator 参数传入 GridSearchCV 对象
clf = GridSearchCV(pipe, param_grid, cv=inner_cv, scoring='accuracy')
nested_scores = cross_val_score(clf, X, y, cv=outer_cv, scoring='accuracy')

print(f"嵌套交叉验证平均准确率: {nested_scores.mean():.4f} (+/- {nested_scores.std():.4f})")

# 非嵌套的对比:直接在全部数据上做 GridSearchCV,再评估(会高估)
clf.fit(X, y)  # 这已经污染了测试信息
print(f"非嵌套(全数据调参)最佳准确率: {clf.best_score_:.4f}")

实战7:HalvingRandomSearchCV 加速调参

# -*- coding: utf-8 -*-
"""
连续减半随机搜索,加快调参速度
"""

from sklearn.experimental import enable_halving_search_cv
from sklearn.model_selection import HalvingRandomSearchCV
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from scipy.stats import randint, loguniform

X, y = make_classification(n_samples=2000, n_features=20, random_state=42)

param_dist = {
    'n_estimators': randint(20, 200),
    'max_depth': randint(3, 20),
    'min_samples_split': randint(2, 20),
    'max_features': loguniform(0.1, 1.0)
}

rf = RandomForestClassifier(random_state=42)
halving = HalvingRandomSearchCV(rf, param_dist, n_candidates='exhaust',
                                factor=3, resource='n_samples',
                                min_resources='smallest', cv=3,
                                random_state=42, n_jobs=-1, verbose=1)
halving.fit(X, y)

print("最佳参数:", halving.best_params_)
print("最佳交叉验证分数:", halving.best_score_)

实战8:自定义评分函数

# -*- coding: utf-8 -*-
"""
使用自定义评分函数进行调参(例如,F2 分数,更注重召回率)
"""

from sklearn.metrics import fbeta_score, make_scorer
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier

X, y = make_classification(n_samples=500, weights=[0.9], random_state=42)

# 自定义 F2 分数(beta=2,召回率权重更高)
f2_scorer = make_scorer(fbeta_score, beta=2)

param_grid = {'n_estimators': [50, 100], 'max_depth': [5, 10]}

rf = RandomForestClassifier(random_state=42)
grid = GridSearchCV(rf, param_grid, scoring=f2_scorer, cv=3)
grid.fit(X, y)
print("最佳参数(按 F2):", grid.best_params_)
print("最佳 F2 分数:", grid.best_score_)

案例实操演示

案例:完整调优流程(XGBoost 风格,使用 GBDT 模拟)

# 一个完整的调优流程:数据划分 -> 随机搜索 -> 细化网格搜索 -> 最终评估
from sklearn.datasets import fetch_california_housing
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split, RandomizedSearchCV, GridSearchCV
from sklearn.metrics import mean_squared_error
from scipy.stats import loguniform, randint

# 加载数据
X, y = fetch_california_housing(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 第一阶段:随机搜索宽范围
param_dist = {
    'n_estimators': randint(50, 500),
    'learning_rate': loguniform(0.01, 0.5),
    'max_depth': randint(3, 10),
    'subsample': [0.7, 0.8, 0.9, 1.0],
    'min_samples_split': randint(2, 20)
}
gbdt = GradientBoostingRegressor(random_state=42)
rand = RandomizedSearchCV(gbdt, param_dist, n_iter=30, cv=3, scoring='neg_mean_squared_error',
                          random_state=42, n_jobs=-1)
rand.fit(X_train, y_train)

# 第二阶段:缩小范围,网格搜索精细调优
best_params = rand.best_params_
# 围绕最佳值附近构建网格
param_grid = {
    'n_estimators': [max(50, best_params['n_estimators']-50), best_params['n_estimators'], best_params['n_estimators']+50],
    'learning_rate': [best_params['learning_rate'] * 0.5, best_params['learning_rate'], best_params['learning_rate'] * 2],
    'max_depth': [best_params['max_depth']-1, best_params['max_depth'], best_params['max_depth']+1],
    'subsample': [best_params['subsample']-0.1, best_params['subsample'], best_params['subsample']+0.1],
}
# 清理超出范围的值
param_grid['n_estimators'] = [x for x in param_grid['n_estimators'] if x >= 10]
param_grid['max_depth'] = [x for x in param_grid['max_depth'] if x >= 1]
param_grid['subsample'] = [x for x in param_grid['subsample'] if 0 < x <= 1]

grid = GridSearchCV(gbdt, param_grid, cv=3, scoring='neg_mean_squared_error', n_jobs=-1)
grid.fit(X_train, y_train)

best_gbdt = grid.best_estimator_
y_pred = best_gbdt.predict(X_test)
rmse = mean_squared_error(y_test, y_pred, squared=False)
print(f"最终测试集 RMSE: {rmse:.4f}")

常见报错与避坑指南

报错1:ValueError: Invalid parameter ... for estimator

原因:参数名拼写错误,或参数不属于该模型(比如对 Pipeline 中的步骤需要加 步骤名__ 前缀)。

解决:使用 estimator.get_params().keys() 查看可用参数名。

报错2:UserWarning: One or more of the test scores are non-finite

原因:某些参数组合导致模型无法拟合(如 C 太大导致 SVM 不收敛)。

解决:设置 error_score=np.nan,或调整参数范围避免极端值。

报错3:n_iter 过大导致运行时间过长

解决:先用较小的 n_iter 探索,再细化范围。

报错4:网格搜索时内存爆炸

原因n_jobs=-1 并行训练多个模型,每个模型会复制数据。

解决:减少 n_jobs,或使用 pre_dispatch 限制同时运行的作业数。

避坑总结

  1. 始终保留独立的测试集,调参时绝不触碰。
  2. 参数空间设计:对数量级差异大的参数(如学习率)使用对数分布。
  3. 交叉验证折数:数据量大时可用 3-5 折,小数据用 10 折。
  4. 优先随机搜索:当参数空间超过 3 维时,随机搜索效率更高。
  5. 利用 refit=True:搜索完成后再训练全量训练集,保证模型容量。

知识点总结

本课系统讲解了超参数自动调优的核心技术:

基础概念

  1. 交叉验证:在调参中提供稳定评估,防止过拟合验证集。
  2. 训练/验证/测试集划分:调参只在训练+验证上进行,测试集最后使用一次。

搜索方法

  1. 网格搜索:穷举候选组合,适合低维空间。
  2. 随机搜索:随机采样,效率高,支持分布采样。
  3. 连续减半搜索:迭代式淘汰,更快。
  4. 自定义评分make_scorer 包装业务指标。

参数空间设计

  1. 列表:离散候选值。
  2. 整数范围randint
  3. 均匀分布uniform
  4. 对数均匀分布loguniform(用于跨度大的参数)。

结果分析

  1. cv_results_:详细记录每次评估的结果。
  2. best_params_best_score_best_estimator_

进阶

  1. 嵌套交叉验证:无偏估计调优流程的泛化性能。
  2. Pipeline 中的调参:使用 步骤名__参数名

课后练习题

选择题

  1. 在超参数调优中,如果参数空间为 5 维,每维有 10 个候选值,网格搜索需要训练多少次模型(K=5 折)?
    A. 5 B. 50 C. 50000 D. 250000

  2. 以下哪种参数分布最适合搜索学习率(0.0001 到 0.1)?
    A. 均匀分布 B. 对数均匀分布 C. 整数均匀分布 D. 正态分布

  3. 嵌套交叉验证的目的是:
    A. 加速调参 B. 无偏估计调参流程的泛化性能 C. 减少参数数量 D. 提高模型准确率

填空题

from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import loguniform

# 1. 定义参数分布
param_dist = {
    'C': loguniform(1e-3, 1e3),
    'gamma': ________(1e-4, 1e-1)   # 使用 loguniform
}

# 2. 创建随机搜索对象,迭代 30 次,5 折交叉验证
rand = RandomizedSearchCV(SVC(), param_dist, n_iter=30, cv=5, random_state=42)

# 3. 训练
rand.fit(X_train, y_train)

# 4. 获取最佳参数
best_params = rand.________

# 5. 获取最佳分数
best_score = rand.________

实操题

  1. 网格搜索随机森林:在 load_breast_cancer 数据集上,使用 GridSearchCV 搜索随机森林的 n_estimators([50,100,150])和 max_depth([5,10,None])。输出最佳参数和测试准确率。

  2. 随机搜索 SVM:在 load_digits 全量数据(10类)上,使用 RandomizedSearchCV 搜索 SVM 的 C(对数均匀 0.001~1000)和 gamma(对数均匀 0.0001~1),迭代 50 次。绘制参数与分数的散点图,分析哪些区域分数高。

  3. 自定义评分与早停:在 make_classification 生成的不平衡数据(正例 5%)上,使用 RandomizedSearchCV 搜索 GBDT 的参数,评分指标使用 fbeta_score(beta=2)。输出最佳参数,并对比使用 accuracy 评分的结果有何不同。

思考题

假设你有一个包含 10 万样本、200 个特征的数据集,你需要训练一个随机森林,并调优它的 4 个超参数。你估计网格搜索需要 5000 次训练,每次训练需要 1 秒(K=5 折,每个模型 0.2 秒),总时间约 5000 秒,太长了。请设计一个分阶段的调优策略,在总时间控制在 1000 秒左右的情况下,尽可能找到好的参数组合。写出你的方案和理由。


下一课预告:第30课(项目实战专属)我们将完成一个工业级综合项目——机器学习全流程项目落地,涵盖从业务分析到模型部署的完整链路。这是专栏的收官之作,敬请期待!


🔗《30节课 scikit-learn 从入门到精通》系列课程导航

去订阅

第一部分:基础入门 & 环境准备(1-6 课)
第二部分:数据预处理 & 数据集操作(7-12 课)
第三部分:传统机器学习回归算法(13-17 课)
第四部分:分类算法精讲(18-23 课)
第五部分:聚类 & 降维 & 集成学习(24-29 课)
第六部分:结业大型项目实战(第 30 课)

🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thomas.Sir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值