sklearn的GridSearchCV——网格搜索超参数调优

基本使用

参数不冲突

参数不冲突时,直接用一个字典传递参数和要对应的候选值给GridSearchCV即可

我这里的参数冲突指的是类似下面这种情况:
① 参数取值受限:参数a='a'时,参数b只能取'b',参数a='A'时,参数b能取'b'或'B'
② 参数互斥:参数 a 或 b 二者只能选一个

from sklearn import datasets
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
iris = datasets.load_iris()
model = SVC(random_state=seed)

# 需调参数及候选值
parameters = {
    'C': [0.1, 1, 10], 
    'kernel': ['rbf', 'linear']
}

# 评价依据
# https://scikit-learn.org/stable/modules/model_evaluation.html#scoring-parameter
scores = {
    'acc': 'accuracy',         # 准确率
    'f1_mi': 'f1_micro',       # 一种多分类f1值
}

# 网格搜索实例
gs = GridSearchCV(
    model,
    parameters,
    cv=5,                      # 交叉验证数
    scoring=scores,            # 评价指标
    refit='f1_mi',             # 在此指标下,用最优表现的参数重新训练模型
#     return_train_score=True,   # gs.cv_results_额外保存训练集的评价结果
    verbose=1,                 # 日志信息,默认0不输出
    n_jobs=2                   # 并行加速
)

# 一共要跑的任务数=参数1候选值*...*参数i候选值*交叉验证数
# 这里就是3*2*5=30
gs.fit(iris.data, iris.target)

借助 make_scorer 可以自定义评价指标,如果指标越小越好,那么需要设置greater_is_better=False,sklearn会将这样的指标取负,越小越好取负之后就等同于越大越好。

from sklearn.metrics import make_scorer
def custom_loss_func(y_true, y_pred):
    return len(y_true[y_true!=y_pred])/len(y_true)
# greater_is_better=False,指标越小越好
# needs_proba=False,指标通过标签计算,不是通过概率
loss_socre = make_scorer(custom_loss_func, greater_is_better=False, needs_proba=False)
scores = {
    'acc': 'accuracy',         # 准确率
    'f1_mi': 'f1_micro',       # 一种多分类f1值
    'loss': loss_socre         # 自定义评价指标
}

再通过 gs.best_params_ 获取最优模型的参数,gs.best_estimator_取得最优模型(想这样操作的话GridSearchCV的refit参数不能为False),

print("最优参数")
print(gs.best_params_)
print("最佳模型的评分")
print(gs.best_score_)
print("最优模型")
best_model = gs.best_estimator_  # GridSearchCV的refit参数不能为False

gs.cv_results_ 存放了网格搜索的结果,如果想查看可以借助pandas,我们这里只列出了和评价指标有关的结果

"""
用表格查看训练信息
"""
cv_results = pd.DataFrame(gs.cv_results_)
# 查看其他指标的结果和参数,比如这里按平均准确率排序
cv_results = cv_results.sort_values(by="mean_test_acc", ascending=False)
shown_columns = ["mean_test_"+col for col in scores.keys()] + ["params"]
cv_results[shown_columns].head(3)

参数冲突

参数冲突时,互斥参数搜索空间用不同字典来描述,然后将这些字典放到列表中,再传递给GridSearchCV

parameters = [
    {
        'C': [0.1, 1, 10], 
        'kernel': ['rbf', 'linear']
    },
    {
        'C': [0.1, 1, 10],
        'kernel': ['poly'],
        'degree': [1, 3, 5]
    }
]

复合调参

管道可以用来连接多个操作,比如特征选择+模型训练,数据处理+模型训练等等。如果这些操作也有参数可调,可以用 GridSearchCV 对它们一起调参

from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.feature_selection import SelectKBest, chi2, f_classif
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
iris = datasets.load_iris()

pipe = Pipeline([
    ('selector', SelectKBest()),       # 特征选择
    ('model', SVC(random_state=seed))  # 模型
])

# “双下划线”指定要调整的部件及其参数
parameters = [
    {
        'selector__score_func': [chi2, f_classif],
        'selector__k': [2, 3, 4],
        'model__C': [0.1, 1, 10], 
        'model__kernel': ['rbf', 'linear']
    },
    {
        'selector__score_func': [chi2, f_classif],
        'selector__k': [2, 3, 4],
        'model__C': [0.1, 1, 10],
        'model__kernel': ['poly'],
        'model__degree': [1, 3, 5]
    }
]


gs = GridSearchCV(
    pipe,
    parameters,
    cv=5,
    scoring='accuracy',
    verbose=1,
    n_jobs=2,
)

gs.fit(iris.data, iris.target)

这时候获得的 best_estimator_ 是管道,我们可以用索引获取需要的组件(特征选择器或模型)

print("最优组合")
# best_pipe = gs.best_estimator_
best_selector = gs.best_estimator_[0]
best_model = gs.best_estimator_[1]

 

posted @ 2020-04-27 23:42  那少年和狗  阅读(5478)  评论(0编辑  收藏  举报