4、网格搜索(Grid Search):原理、优缺点、在药物模型中的应用
网格搜索,说白了就是「暴力枚举」。你给它一个参数列表,它就把所有组合挨个试一遍。我刚开始做超参数调优那会儿,觉得这方法太笨了,直到有一次在分子活性预测模型上,随机搜索怎么都找不到最优解,网格搜索一把就给我干到了 0.89 的 AUC,嗯,从那以后我再也不敢小看它了。
4.1 网格搜索的核心原理
它的逻辑特别简单:你预先设定好每个超参数的候选值,然后生成这些值的笛卡尔积。对每一组参数组合,训练一次模型,评估性能,最后选出表现最好的那一组。
举个例子,假设你要调两个参数:learning_rate 和 n_estimators。
learning_rate候选值:[0.01, 0.1, 0.5]n_estimators候选值:[50, 100, 200]
那么网格搜索会生成 3 × 3 = 9 组组合。每组都跑一遍,最后告诉你哪组最好。你想想看,如果参数多了,候选值又细,这个组合数会膨胀得非常快。
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestRegressor
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [10, 20, None],
'min_samples_split': [2, 5, 10]
}
# 我在项目中习惯用 5 折交叉验证,这样评估更稳
grid_search = GridSearchCV(
estimator=RandomForestRegressor(),
param_grid=param_grid,
cv=5,
scoring='r2',
n_jobs=-1,
verbose=1
)
grid_search.fit(X_train, y_train)
print("Best params:", grid_search.best_params_)
print("Best score:", grid_search.best_score_)
我个人习惯把 verbose 设为 1,这样能看到进度条。跑大网格的时候,心里有底。
4.2 参数空间的定义技巧
参数空间怎么定义,直接影响搜索效果。我早期踩过一个坑:把所有参数都塞进网格,结果组合数爆炸,跑了三天三夜还没跑完。
后来我总结出几条经验:
- 先粗后细:第一轮用大步长扫一遍,锁定好区域,第二轮再精细搜索。
- 区分参数类型:离散型参数(如树的数量)适合网格,连续型参数(如学习率)更适合用对数尺度。
- 控制候选值数量:每个参数别超过 5-6 个候选值,否则组合数会失控。
| 参数类型 | 示例 | 候选值设计建议 |
|---|---|---|
| 离散型 | n_estimators, max_depth | 均匀间隔,如 [50, 100, 150, 200] |
| 连续型 | learning_rate, gamma | 对数尺度,如 [0.001, 0.01, 0.1] |
| 布尔型 | bootstrap, use_gpu | 直接枚举 True/False |
| 类别型 | kernel, solver | 列出所有可能取值 |
4.3 网格搜索的优缺点分析
咱们不绕弯子,直接说优缺点。我做决策的时候喜欢列一张表,一目了然。
| 优点 | 缺点 |
|---|---|
| 实现简单,几乎零门槛 | 维度灾难:参数每多一个,组合数翻几倍 |
| 结果可解释,知道每组的性能 | 计算成本高,不适合大规模调优 |
| 适合参数间有交互的场景 | 需要人工预设候选值,依赖先验知识 |
| 并行化容易(n_jobs=-1 搞定) | 连续型参数只能用离散近似,可能漏掉最优 |
为什么会这样?说白了就是「穷举」的代价。你想想看,如果我要调 5 个参数,每个给 10 个候选值,那就是 10 万种组合。跑一次模型要 1 分钟,10 万分钟就是 69 天。这个账一算,你就知道网格搜索不是万能的了。
4.4 在药物模型中的应用场景
网格搜索在药物研发中特别常用在以下几个地方:
4.4.1 分子性质预测(QSAR/QSPR)
这类模型通常用随机森林或 XGBoost,参数不多。我在做 CYP450 抑制活性预测时,就用网格搜索调了三个参数:
param_grid = {
'n_estimators': [100, 200, 300],
'max_depth': [5, 10, 15],
'learning_rate': [0.05, 0.1, 0.2]
}
# 3 × 3 × 3 = 27 组,跑起来很快
# 我在自己机器上只花了 40 分钟就出结果了
4.4.2 药物-靶标相互作用预测
这类任务常用图神经网络或矩阵分解模型。有一次我帮团队调一个 DeepDTA 模型的超参数,网格搜索帮我找到了最优的嵌入维度和卷积核大小组合。
param_grid = {
'embedding_dim': [64, 128, 256],
'kernel_size': [3, 5, 7],
'dropout': [0.2, 0.3, 0.5]
}
# 我建议先把 dropout 固定到 0.3,调完前两个参数再细搜 dropout
4.4.3 药物 ADMET 预测
ADMET(吸收、分布、代谢、排泄、毒性)预测是药物研发的关键环节。我遇到过一个小样本数据集,只有 200 个分子,但网格搜索仍然有效——因为参数空间控制得小。
from sklearn.svm import SVR
param_grid = {
'C': [0.1, 1, 10],
'gamma': ['scale', 'auto'],
'kernel': ['rbf', 'linear']
}
# 2 × 2 × 3 = 12 组,小样本下几分钟跑完
4.5 避坑指南
subsample, colsample_bytree, min_child_weight 等,组合数直接飙到 648 组。跑了 8 个小时,结果发现最优参数就在一个很窄的区间里。从那以后,我学会了先做一次随机搜索,缩小范围,再用网格精调。
几点具体建议:
- 别一次性全调:先调最重要的 2-3 个参数,其他用默认值。
- 注意资源规划:先算一下总组合数 × 单次训练时间 × 交叉验证折数,如果超过 8 小时,果断换方法。
- 别忽略早停:如果模型本身支持早停(如 XGBoost 的
early_stopping_rounds),一定要开,可以节省大量时间。
4.6 网格搜索的完整工作流程
下面这张图展示了我做网格搜索的完整流程,你可以把它当作自己的操作手册:
4.7 什么时候该用网格搜索
我个人的决策流程是这样的:
- 先估算一下组合数。如果 ≤ 50 组,直接上网格搜索。
- 如果组合数在 50-200 之间,考虑减少候选值或者先做一次随机搜索定位。
- 如果组合数 > 200,果断换随机搜索或贝叶斯优化。
嗯,这里要注意:在药物模型中,很多场景的数据量不大(几百到几千个分子),模型本身也不复杂(随机森林、SVM、浅层神经网络)。这种情况下,网格搜索反而是最省心的选择。你想想看,花一个小时跑完,拿到最优参数,比花半小时折腾随机搜索的候选方案更靠谱。