超参数调优 #

概述 #

超参数调优是寻找模型最优参数配置的过程,对模型性能至关重要。

超参数 vs 参数 #

类型 描述 示例
参数 模型学习得到 权重、偏置
超参数 训练前设置 学习率、树深度

调优方法 #

方法 特点 适用场景
GridSearch 穷举搜索 参数空间小
RandomSearch 随机采样 参数空间大
Bayes优化 智能搜索 计算资源有限
Hyperband 早停策略 大规模搜索

网格搜索 #

基本使用 #

python
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
from sklearn.datasets import load_iris

iris = load_iris()
X, y = iris.data, iris.target

param_grid = {
    'C': [0.1, 1, 10],
    'kernel': ['linear', 'rbf'],
    'gamma': ['scale', 'auto']
}

grid_search = GridSearchCV(
    SVC(),
    param_grid,
    cv=5,
    scoring='accuracy',
    n_jobs=-1
)

grid_search.fit(X, y)

print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳分数: {grid_search.best_score_:.4f}")

参数说明 #

参数 描述
estimator 估计器
param_grid 参数网格
cv 交叉验证折数
scoring 评估指标
n_jobs 并行任务数
verbose 日志详细程度
refit 是否用最佳参数重训练

多指标评估 #

python
scoring = ['accuracy', 'precision_macro', 'recall_macro', 'f1_macro']

grid_search = GridSearchCV(
    SVC(),
    param_grid,
    cv=5,
    scoring=scoring,
    refit='f1_macro'
)

grid_search.fit(X, y)

获取结果 #

python
import pandas as pd

results = pd.DataFrame(grid_search.cv_results_)
print(results[['params', 'mean_test_score', 'std_test_score']].head())

best_model = grid_search.best_estimator_
print(f"最佳模型: {best_model}")

条件参数网格 #

python
param_grid = [
    {'kernel': ['linear'], 'C': [0.1, 1, 10]},
    {'kernel': ['rbf'], 'C': [0.1, 1, 10], 'gamma': ['scale', 'auto']},
    {'kernel': ['poly'], 'C': [0.1, 1, 10], 'degree': [2, 3]}
]

grid_search = GridSearchCV(SVC(), param_grid, cv=5)

随机搜索 #

基本使用 #

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

param_distributions = {
    'C': uniform(0.1, 10),
    'kernel': ['linear', 'rbf', 'poly'],
    'gamma': ['scale', 'auto'],
    'degree': randint(2, 5)
}

random_search = RandomizedSearchCV(
    SVC(),
    param_distributions,
    n_iter=50,
    cv=5,
    random_state=42,
    n_jobs=-1
)

random_search.fit(X, y)

print(f"最佳参数: {random_search.best_params_}")
print(f"最佳分数: {random_search.best_score_:.4f}")

参数说明 #

参数 描述
n_iter 采样次数
param_distributions 参数分布

分布类型 #

python
from scipy.stats import uniform, randint, loguniform, expon

param_distributions = {
    'C': loguniform(1e-3, 1e3),
    'gamma': loguniform(1e-4, 1e1),
    'learning_rate': uniform(0.01, 0.3),
    'n_estimators': randint(50, 500),
    'max_depth': randint(3, 15)
}

GridSearch vs RandomSearch #

python
import matplotlib.pyplot as plt
import numpy as np

grid_scores = []
random_scores = []

for _ in range(10):
    gs = GridSearchCV(SVC(), param_grid, cv=5)
    gs.fit(X, y)
    grid_scores.append(gs.best_score_)
    
    rs = RandomizedSearchCV(SVC(), param_distributions, n_iter=10, cv=5, random_state=np.random.randint(1000))
    rs.fit(X, y)
    random_scores.append(rs.best_score_)

plt.boxplot([grid_scores, random_scores], labels=['GridSearch', 'RandomSearch'])
plt.ylabel('Best Score')
plt.title('GridSearch vs RandomSearch')

Halving 搜索 #

HalvingGridSearchCV #

python
from sklearn.experimental import enable_halving_search_cv
from sklearn.model_selection import HalvingGridSearchCV

param_grid = {
    'C': [0.1, 1, 10, 100],
    'kernel': ['linear', 'rbf'],
    'gamma': ['scale', 'auto']
}

halving_search = HalvingGridSearchCV(
    SVC(),
    param_grid,
    cv=5,
    factor=3,
    random_state=42,
    n_jobs=-1
)

halving_search.fit(X, y)

print(f"最佳参数: {halving_search.best_params_}")
print(f"最佳分数: {halving_search.best_score_:.4f}")

HalvingRandomSearchCV #

python
from sklearn.model_selection import HalvingRandomSearchCV

halving_random = HalvingRandomSearchCV(
    SVC(),
    param_distributions,
    n_candidates=50,
    cv=5,
    factor=3,
    random_state=42
)

halving_random.fit(X, y)

参数说明 #

参数 描述
factor 每轮淘汰比例
resource 资源类型
max_resources 最大资源
min_resources 最小资源

Pipeline 调参 #

基本使用 #

python
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('clf', LogisticRegression(max_iter=1000))
])

param_grid = {
    'scaler__with_mean': [True, False],
    'clf__C': [0.1, 1, 10],
    'clf__penalty': ['l1', 'l2'],
    'clf__solver': ['liblinear', 'saga']
}

grid_search = GridSearchCV(pipe, param_grid, cv=5)
grid_search.fit(X, y)

ColumnTransformer 调参 #

python
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder

preprocessor = ColumnTransformer([
    ('num', StandardScaler(), [0, 1]),
    ('cat', OneHotEncoder(), [2, 3])
])

pipe = Pipeline([
    ('preprocessor', preprocessor),
    ('clf', LogisticRegression())
])

param_grid = {
    'preprocessor__num__with_mean': [True, False],
    'clf__C': [0.1, 1, 10]
}

多模型调参 #

比较多个模型 #

python
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression

models = {
    'RF': {
        'model': RandomForestClassifier(random_state=42),
        'params': {
            'n_estimators': [50, 100, 200],
            'max_depth': [5, 10, None]
        }
    },
    'SVM': {
        'model': SVC(),
        'params': {
            'C': [0.1, 1, 10],
            'kernel': ['linear', 'rbf']
        }
    },
    'LR': {
        'model': LogisticRegression(max_iter=1000),
        'params': {
            'C': [0.1, 1, 10],
            'penalty': ['l1', 'l2']
        }
    }
}

best_score = 0
best_model = None

for name, config in models.items():
    gs = GridSearchCV(config['model'], config['params'], cv=5)
    gs.fit(X, y)
    print(f"{name}: {gs.best_score_:.4f}")
    if gs.best_score_ > best_score:
        best_score = gs.best_score_
        best_model = gs.best_estimator_

print(f"\n最佳模型: {type(best_model).__name__}")
print(f"最佳分数: {best_score:.4f}")

可视化调参结果 #

热力图 #

python
import seaborn as sns
import pandas as pd

results = pd.DataFrame(grid_search.cv_results_)

pivot = results.pivot_table(
    values='mean_test_score',
    index='param_C',
    columns='param_kernel'
)

plt.figure(figsize=(8, 6))
sns.heatmap(pivot, annot=True, fmt='.4f', cmap='YlGnBu')
plt.title('Grid Search Results')

参数影响图 #

python
plt.figure(figsize=(12, 4))

plt.subplot(131)
plt.plot(results['param_C'], results['mean_test_score'], 'o-')
plt.xlabel('C')
plt.ylabel('Score')

plt.subplot(132)
results.groupby('param_kernel')['mean_test_score'].mean().plot(kind='bar')
plt.xlabel('Kernel')
plt.ylabel('Mean Score')

plt.tight_layout()

并行化 #

使用 n_jobs #

python
grid_search = GridSearchCV(
    SVC(),
    param_grid,
    cv=5,
    n_jobs=-1,
    verbose=1
)

分布式调参 #

python
from joblib import parallel_backend

with parallel_backend('multiprocessing', n_jobs=-1):
    grid_search.fit(X, y)

早停策略 #

使用验证集 #

python
from sklearn.model_selection import train_test_split

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)

best_score = 0
best_params = None

for C in [0.1, 1, 10]:
    for kernel in ['linear', 'rbf']:
        model = SVC(C=C, kernel=kernel)
        model.fit(X_train, y_train)
        score = model.score(X_val, y_val)
        if score > best_score:
            best_score = score
            best_params = {'C': C, 'kernel': kernel}

增量调参 #

python
from sklearn.ensemble import GradientBoostingClassifier

param_grid = {
    'n_estimators': [100, 200, 500],
    'learning_rate': [0.01, 0.1, 0.2],
    'max_depth': [3, 5, 7]
}

grid_search = GridSearchCV(
    GradientBoostingClassifier(
        n_iter_no_change=10,
        validation_fraction=0.1
    ),
    param_grid,
    cv=5
)

最佳实践 #

1. 搜索策略 #

数据量 推荐方法
GridSearch
RandomSearch
HalvingSearch

2. 参数范围 #

python
param_grid = {
    'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000],
    'learning_rate': [0.001, 0.01, 0.1, 0.3]
}

3. 粗细搜索 #

python
coarse_grid = {'C': [0.1, 1, 10, 100]}
coarse_search = GridSearchCV(SVC(), coarse_grid, cv=5)
coarse_search.fit(X, y)
best_C_coarse = coarse_search.best_params_['C']

fine_grid = {'C': np.linspace(best_C_coarse/2, best_C_coarse*2, 10)}
fine_search = GridSearchCV(SVC(), fine_grid, cv=5)
fine_search.fit(X, y)

4. 保存结果 #

python
import joblib

joblib.dump(grid_search, 'grid_search_results.pkl')
loaded = joblib.load('grid_search_results.pkl')

5. 避免数据泄露 #

python
from sklearn.pipeline import Pipeline

pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('clf', SVC())
])

GridSearchCV(pipe, param_grid, cv=5)

下一步 #

掌握超参数调优后,继续学习 特征选择 了解如何选择最优特征!

最后更新:2026-04-04