Python案例如何用Scikit-learn做网格搜索CV

wen python案例 1

本文目录导读:

Python案例如何用Scikit-learn做网格搜索CV

  1. 基础概念
  2. 完整示例代码
  3. 高级技巧
  4. 实用建议

我来详细讲解如何使用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 注意事项

  1. 计算资源:参数组合过多时,考虑使用RandomizedSearchCV
  2. 过拟合:使用交叉验证防止过拟合
  3. 数据泄露:确保只在训练集上进行特征选择和预处理
  4. 结果解释:关注参数对模型性能的实际影响

网格搜索是机器学习中不可或缺的调参工具,合理使用可以显著提升模型性能。

抱歉,评论功能暂时关闭!