4. 网格搜索(Grid Search)原理与Python实现

4.1 什么是网格搜索

网格搜索,说白了就是暴力试参数。你定好一组候选值,程序把所有组合跑一遍,挑出表现最好的。

我刚开始调参时总嫌它“笨”,觉得有优化算法为啥还用手动?结果有一次项目 deadline 压得很紧,随机搜索跑了几百次都没找到稳定区域,最后靠网格搜索把关键参数一网打尽。嗯,从那以后我对它的态度就变了——简单不一定没用,关键看场景。

它的核心逻辑就三步:

  1. 定义参数网格(每个参数取哪些值)
  2. 对网格中所有组合,用交叉验证评估模型
  3. 选平均分数最高的那组参数

4.2 搜索空间与组合爆炸

网格搜索最大的坑是什么?组合数太多,跑不动。假设你有两个参数:max_depth 取 5 个值,n_estimators 取 10 个值,那就要跑 50 次;如果再加一个 min_samples_split 取 4 个值,就是 200 次。再乘以 5 折交叉验证,就是 1000 次训练。

表格里我列了常见搜索方式的对比,你感受一下:

方法策略搜索次数(示例)适用场景
网格搜索穷举所有组合高(组合数乘积)参数少(≤3)、取值范围已知
随机搜索随机采样中(可指定次数)参数多、计算资源有限
贝叶斯优化基于历史结果选点低(几十次)参数多、单次训练成本高
我个人习惯是先做一次粗略的随机搜索,找到“好球区”,再用网格搜索精细调。这样既省时间又能保证精度。

4.3 Python实现:用Scikit-learn搞定

最直接的工具就是 GridSearchCV。来,看个完整的栗子:

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris

# 加载数据
X, y = load_iris(return_X_y=True)

# 定义模型
model = RandomForestClassifier(random_state=42)

# 定义参数网格
param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [3, 5, None],
    'min_samples_split': [2, 5, 10]
}

# 网格搜索 + 5折交叉验证
grid = GridSearchCV(
    estimator=model,
    param_grid=param_grid,
    cv=5,
    scoring='accuracy',
    n_jobs=-1,          # 用所有CPU
    verbose=1
)

# 开跑
grid.fit(X, y)

# 输出最佳参数
print("Best params:", grid.best_params_)
print("Best score:", grid.best_score_) 

跑完之后,grid.best_params_ 就是你的最优参数组合。grid.best_score_ 是对应的平均交叉验证分数。

4.4 结果怎么看

光拿到最佳参数还不够,我建议你把所有组合的分数都看一眼。有时候次优参数更稳定——我在项目中就遇到过这种情况:最优参数在验证集上高 0.5%,但测试集上反而掉 2%,明显过拟合了。

用 cv_results_ 可以拿到全部明细:

import pandas as pd

results = pd.DataFrame(grid.cv_results_)
# 只选关心的列
cols = ['params', 'mean_test_score', 'std_test_score']
print(results[cols].sort_values('mean_test_score', ascending=False))

输出类似:

                                             params  mean_test_score  std_test_score
0      {'n_estimators': 100, 'max_depth': 5, ...}          0.9733          0.0231
12     {'n_estimators': 200, 'max_depth': 5, ...}          0.9667          0.0302
...                                                       ...               ...

注意看 std_test_score——标准差大意味着模型在不同折上表现不稳定,这种参数组合要小心。

核心结论:不要只盯着 mean_test_score,std_test_score 同样重要。稳定优先,准确率差一点可以接受。

4.5 优点与局限

  • 优点:结果可复现、理解直观、能找到全局最优(在给定网格内)
  • 缺点:计算量随参数数量指数增长;对连续参数只能做粗离散化

什么时候别用?参数维度超过 4 个,或者单次训练就要半小时以上。这时候你强行上网格搜索,等结果出来项目都黄了。

我曾经有一次对 6 个参数做网格搜索,每个取 5 个值,组合数 5^6 = 15625,再乘 5 折就是 78,125 次训练。跑了两天还没出结果……后来乖乖换成随机搜索,20 分钟搞定。

4.6 完整流程图

下面这张图把整个流程串起来了,你跟着箭头走一遍就能记住。仔细看,每个分支都在强调“组合”和“评估”:

网格搜索核心流程 定义参数网格 遍历所有参数组合 例如:max_depth ∈ [3,5,None];n_estimators ∈ [50,100,200] 5折交叉验证评估 计算平均准确率与标准差 还有组合? 循环 选择平均分数最高的参数 本质:穷举 + 交叉验证 → 选出在验证集上最稳定的配置

这条线走下来很清晰:先搭网格,再挨个试,最后挑最好的。记住这个流程,以后遇到调参任务,不至于手忙脚乱。

小技巧:如果参数中有连续值(比如学习率),你可以先做对数均匀采样,把值固定成类似 [0.001, 0.01, 0.1, 1] 的网格,再套用网格搜索。