本文目录导读:

我来详细讲解如何使用Scikit-learn进行网格搜索(Grid Search)和交叉验证(CV),这是调参的重要方法。
基础概念
网格搜索(Grid Search):在指定的参数范围内,遍历所有可能的参数组合 交叉验证(Cross Validation):将数据分成多份,轮流作为验证集
完整示例代码
1 基础网格搜索
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# 加载数据
iris = load_iris()
X, y = iris.data, iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 定义模型
svm = SVC()
# 定义参数网格
param_grid = {
'C': [0.1, 1, 10, 100],
'gamma': [0.001, 0.01, 0.1, 1],
'kernel': ['rbf', 'linear']
}
# 创建网格搜索对象
grid_search = GridSearchCV(
estimator=svm,
param_grid=param_grid,
cv=5, # 5折交叉验证
scoring='accuracy', # 评分标准
n_jobs=-1, # 使用所有CPU核心
verbose=1 # 显示进度
)
# 执行网格搜索
grid_search.fit(X_train, y_train)
# 查看结果
print("最佳参数:", grid_search.best_params_)
print("最佳交叉验证得分:", grid_search.best_score_)
# 在测试集上评估
y_pred = grid_search.predict(X_test)
print("测试集得分:", grid_search.score(X_test, y_test))
# 显示详细结果
print("\n所有参数组合的得分:")
results = grid_search.cv_results_
for mean_score, params in zip(results['mean_test_score'], results['params']):
print(f"参数: {params}, 平均得分: {mean_score:.3f}")
2 不同评分指标
from sklearn.metrics import make_scorer, f1_score, recall_score, precision_score
# 使用F1分数作为评分指标
grid_search_f1 = GridSearchCV(
svm, param_grid, cv=5,
scoring='f1_macro', # 多分类F1
n_jobs=-1
)
# 自定义评分函数
def custom_scorer(y_true, y_pred):
"""自定义评分函数:F1和准确率的加权平均"""
f1 = f1_score(y_true, y_pred, average='micro')
accuracy = sum(y_true == y_pred) / len(y_true)
return 0.3 * f1 + 0.7 * accuracy
custom_scorer = make_scorer(custom_scorer)
grid_search_custom = GridSearchCV(
svm, param_grid, cv=5,
scoring=custom_scorer,
n_jobs=-1
)
3 随机森林的网格搜索
from sklearn.ensemble import RandomForestClassifier
# 随机森林的参数网格
rf_param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}
rf = RandomForestClassifier(random_state=42)
rf_grid_search = GridSearchCV(
rf, rf_param_grid, cv=5,
scoring='accuracy',
n_jobs=-1,
verbose=2
)
# 执行搜索(由于参数组合多,可能需要较长时间)
rf_grid_search.fit(X_train, y_train)
print("\n随机森林最佳参数:", rf_grid_search.best_params_)
print("随机森林最佳得分:", rf_grid_search.best_score_)
4 多阶段网格搜索
# 第一阶段:粗搜索
stage1_param_grid = {
'n_estimators': [10, 50, 100, 200],
'max_depth': [None, 10, 20, 50]
}
stage1_search = GridSearchCV(rf, stage1_param_grid, cv=3, n_jobs=-1)
stage1_search.fit(X_train, y_train)
print("第一阶段最佳参数:", stage1_search.best_params_)
# 第二阶段:在最佳参数附近精细搜索
best_params = stage1_search.best_params_
stage2_param_grid = {
'n_estimators': [
best_params['n_estimators'] - 25,
best_params['n_estimators'],
best_params['n_estimators'] + 25
],
'max_depth': [
best_params['max_depth'] - 5 if best_params['max_depth'] else 15,
best_params['max_depth'],
best_params['max_depth'] + 5 if best_params['max_depth'] else 25
],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}
stage2_search = GridSearchCV(rf, stage2_param_grid, cv=5, n_jobs=-1)
stage2_search.fit(X_train, y_train)
print("第二阶段最佳参数:", stage2_search.best_params_)
5 可视化结果
import matplotlib.pyplot as plt
import numpy as np
def plot_grid_search_results(grid_search, param1, param2):
"""可视化网格搜索结果"""
results = grid_search.cv_results_
scores = results['mean_test_score'].reshape(
len(grid_search.param_grid[param1]),
len(grid_search.param_grid[param2])
)
plt.figure(figsize=(10, 8))
plt.imshow(scores, interpolation='nearest', cmap='viridis')
plt.xlabel(param2)
plt.ylabel(param1)
plt.colorbar(label='Accuracy')
# 设置刻度
plt.xticks(range(len(grid_search.param_grid[param2])),
grid_search.param_grid[param2])
plt.yticks(range(len(grid_search.param_grid[param1])),
grid_search.param_grid[param1])
# 显示数值
for i in range(scores.shape[0]):
for j in range(scores.shape[1]):
plt.text(j, i, f'{scores[i, j]:.3f}',
ha='center', va='center', color='white')
plt.title('Grid Search Results')
plt.tight_layout()
plt.show()
# 使用示例
plot_grid_search_results(grid_search, 'C', 'gamma')
高级技巧
1 使用Pipeline进行网格搜索
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
# 创建Pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('pca', PCA()),
('classifier', SVC())
])
# Pipeline的参数网格
pipeline_param_grid = {
'pca__n_components': [2, 3, 4],
'classifier__C': [0.1, 1, 10],
'classifier__kernel': ['rbf', 'linear']
}
pipeline_grid_search = GridSearchCV(
pipeline, pipeline_param_grid, cv=5, n_jobs=-1
)
pipeline_grid_search.fit(X_train, y_train)
2 并行处理和早停
from sklearn.model_selection import PredefinedSplit
from sklearn.exceptions import FitFailedWarning
import warnings
warnings.filterwarnings('ignore', category=FitFailedWarning)
# 自定义交叉验证
test_fold = np.zeros(len(X_train))
test_fold[:int(len(X_train)*0.8)] = -1 # 最后20%作为验证集
ps = PredefinedSplit(test_fold)
# 带错误处理的网格搜索
grid_search_robust = GridSearchCV(
svm, param_grid, cv=ps,
scoring='accuracy',
n_jobs=-1,
error_score=0, # 失败的参数组合得分为0
return_train_score=True # 返回训练分数
)
grid_search_robust.fit(X_train, y_train)
3 保存和加载结果
import joblib
# 保存网格搜索对象
joblib.dump(grid_search, 'grid_search_model.pkl')
# 加载网格搜索对象
loaded_grid_search = joblib.load('grid_search_model.pkl')
# 保存最佳模型
best_model = grid_search.best_estimator_
joblib.dump(best_model, 'best_svm_model.pkl')
# 保存结果到CSV
import pandas as pd
results_df = pd.DataFrame(grid_search.cv_results_)
results_df.to_csv('grid_search_results.csv', index=False)
实用建议
1 参数网格设计建议
# 合理的参数搜索范围
param_grid_suggestions = {
# SVM
'svm': {
'C': [0.01, 0.1, 1, 10, 100],
'gamma': [0.001, 0.01, 0.1, 1, 'scale', 'auto'],
'kernel': ['rbf', 'poly', 'sigmoid']
},
# Random Forest
'rf': {
'n_estimators': [50, 100, 200, 500],
'max_depth': [None, 10, 20, 30, 50],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4],
'max_features': ['sqrt', 'log2']
},
# XGBoost
'xgb': {
'learning_rate': [0.01, 0.1, 0.3],
'max_depth': [3, 5, 7, 10],
'n_estimators': [100, 200, 500],
'subsample': [0.8, 0.9, 1.0]
}
}
2 注意事项
- 计算资源:参数组合过多时,考虑使用RandomizedSearchCV
- 过拟合:使用交叉验证防止过拟合
- 数据泄露:确保只在训练集上进行特征选择和预处理
- 结果解释:关注参数对模型性能的实际影响
网格搜索是机器学习中不可或缺的调参工具,合理使用可以显著提升模型性能。