机器学习基础—集成学习Task4(调参)

导语:
今天是集成学习的第四次任务,本次任务的主要内容是调参。在上一任务中,我们了解了模型的特征选择以及模型验证方式,却没有对模型的参数进行调整,本次内容将使用网格搜索随机搜索来对模型的超参数进行调整优化。首先,附上学习链接:
集成学习: EnsembleLearning项目-github.

1.参数与超参数

在机器学习的模型中,我们会经常碰到两类参数:参数和超参数。它们有什么区别呢?
以岭回归为例,模型中的参数 𝜆 和参数w之间有什么不一样?
事实上,参数w是我们通过设定某一个具体的 𝜆 后使用类似于最小二乘法、梯度下降法等方式优化出来的,我们总是设定了 𝜆 是多少后才优化出来的参数w。因此,类似于参数w一样,使用最小二乘法或者梯度下降法等最优化算法优化出来的数我们称为参数,类似于 𝜆 一样,我们无法使用最小二乘法或者梯度下降法等最优化算法优化出来的数我们称为超参数
1.1模型参数是模型内部的配置变量,其值可以根据数据进行估计
进行预测时需要参数;
参数定义了可使用的模型。
参数是从数据估计或获悉的;
参数通常不由编程者手动设置;
参数通常被保存为学习模型的一部分;
参数是机器学习算法的关键,它们通常由过去的训练数据中总结得出 。
1.2模型超参数是模型外部的配置,其值无法从数据中估计
超参数通常用于帮助估计模型参数;
超参数通常由人工指定
超参数通常可以使用启发式设置;
超参数经常被调整为给定的预测建模问题;
超参数取不同的值对于模型的性能有不同的影响。

2.网格搜索与随机搜索

2.1网格搜索GridSearchCV():
网格搜索:https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html?highlight=gridsearchcv#sklearn.model_selection.GridSearchCV
网格搜索结合管道:https://scikit-learn.org/stable/auto_examples/compose/plot_compare_reduction.html?highlight=gridsearchcv
网格搜索的思想非常简单,比如你有2个超参数需要去选择,那你就把所有的超参数选择列出来分别做排列组合。举个例子: 𝜆=0.01,0.1,1.0 和 𝛼=0.01,0.1,1.0 ,你可以做一个排列组合,即:{[0.01,0.01],[0.01,0.1],[0.01,1],[0.1,0.01],[0.1,0.1],[0.1,1.0],[1,0.01],[1,0.1],[1,1]} ,然后针对每组超参数分别建立一个模型,然后选择测试误差最小的那组超参数。换句话说,我们需要从超参数空间中寻找最优的超参数,很像一个网格中找到一个最优的节点,因此叫网格搜索

2.2随机搜索 RandomizedSearchCV() :
https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html?highlight=randomizedsearchcv#sklearn.model_selection.RandomizedSearchCV
网格搜索相当于暴力地从参数空间中每个都尝试一遍,然后选择最优的那组参数,这样的方法显然是不够高效的,因为随着参数类别个数的增加,需要尝试的次数呈指数级增长。有没有一种更加高效的调优方式呢?
那就是使用随机搜索的方式,这种方式不仅仅高效,而且实验证明,随机搜索法结果比稀疏化网格法稍好(有时候也会极差,需要权衡)。参数的随机搜索中的每个参数都是从可能的参数值的分布中采样的。与网格搜索相比,这有两个主要优点:
可以独立于参数数量和可能的值来选择计算成本;
添加不影响性能的参数不会降低效率。

3.实战

本节,我们还是基于Boston数据集进行分析,分别对决策树回归模型和支持向量回归模型进行调参优化,均分别使用网格搜索和随机搜索。
导入数据集,并切分:

#数据导入与数据划分
from sklearn import datasets
import pandas as pd
from sklearn.model_selection import train_test_split

boston = datasets.load_boston()     # 返回一个类似于字典的类
X = boston.data
y = boston.target
features = boston.feature_names
boston_data = pd.DataFrame(X,columns=features)
boston_data["Price"] = y
#boston_data.head()

#数据划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)

3.1 决策树的调参

基于决策树回归的默认参数,对训练集采取十折交叉验证

from sklearn.tree import DecisionTreeRegressor 
from sklearn.model_selection import cross_val_score

reg_tree = DecisionTreeRegressor()
scores = cross_val_score(reg_tree, X_train,y_train, cv=10)
print(scores)                                             
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

输出结果:
[ 0.57584384 0.76230218 0.26533074 0.58262038 0.90252792 0.92177621
0.70950286 0.8689153 -0.04602467 0.64067863]
Accuracy: 0.62 (+/- 0.58)
默认参数下,平均得分为0.62。

1.网格搜索
网格搜索GridSearchCV()中的参数param_grid ,用来指定需要调整的参数和相应搜索范围。注意:如果计算机硬件资源有限,尽量别把参数空间选的太大,不然会搜索很长时间,当然这也是网格搜索相比于随机搜索的劣势所在。
ps:我这里的参数空间其实选择得偏大,搜索了20分钟…

#网格搜索调参:
from sklearn.model_selection import GridSearchCV
param_grid = {'criterion':['mse', 'friedman_mse','mae'], 'splitter':['best','random'],
             'max_depth':range(1, 20, 2),'min_samples_split':range(1, 50, 2),'min_samples_leaf':range(1, 20, 1)
             }
gs = GridSearchCV(estimator=reg_tree,
                  param_grid = param_grid,
                  scoring = 'r2',
                  cv = 10)       # 10折交叉验证
gs = gs.fit(X,y)
print("网格搜索最优得分:",gs.best_score_)
print("网格搜索最优参数组合:\n",gs.best_params_)

输出结果:
网格搜索最优得分: 0.4718727627342031
网格搜索最优参数组合:
{‘criterion’: ‘friedman_mse’, ‘max_depth’: 7, ‘min_samples_leaf’: 8, ‘min_samples_split’: 11, ‘splitter’: ‘random’}
将这组参数结果,带回原模型中,看看在训练集上的表现:

from sklearn.tree import DecisionTreeRegressor 
from sklearn.model_selection import cross_val_score

reg_tree = DecisionTreeRegressor(criterion = 'friedman_mse',
                                 max_depth=7, 
                                 min_samples_split=8, 
                                 min_samples_leaf=11,
                                 splitter = 'random'
                                )
scores = cross_val_score(reg_tree, X_train,y_train, cv=10)
print(scores)                                             
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

输出结果:
[0.76420184 0.746425 0.79641714 0.75544673 0.69999772 0.78414491
0.78273386 0.7593623 0.4801556 0.62090345]
Accuracy: 0.72 (+/- 0.19)
可以看出,这次平均得分为0.72,较之前的0.62有很大的提升!而且,十次实验的2倍标准差也由0.58降低到了0.19,足见超参对模型的影响!

2.随机搜索

# 随机搜索调参:
from sklearn.model_selection import RandomizedSearchCV
param_distributions = {'criterion':['mse', 'friedman_mse','mae'], 'splitter':['best','random'],
             'max_depth':range(1, 20, 2),'min_samples_split':range(1, 20, 2),'min_samples_leaf':range(1, 20, 2)
             }
rs = RandomizedSearchCV(estimator=reg_tree,
                  param_distributions = param_distributions,
                  scoring = 'r2',
                  cv = 10)       # 10折交叉验证
rs = rs.fit(X,y)
print("随机搜索最优得分:",rs.best_score_)
print("随机搜索最优参数组合:\n",rs.best_params_)

输出结果:
随机搜索最优得分: 0.3996099807808634
随机搜索最优参数组合:
{‘splitter’: ‘random’, ‘min_samples_split’: 9, ‘min_samples_leaf’: 9, ‘max_depth’: 15, ‘criterion’: ‘mae’}
验证:

from sklearn.tree import DecisionTreeRegressor 
from sklearn.model_selection import cross_val_score

reg_tree = DecisionTreeRegressor(criterion = 'mae',
                                 max_depth=15, 
                                 min_samples_split=9, 
                                 min_samples_leaf=9,
                                 splitter = 'random'
                                )
scores = cross_val_score(reg_tree, X_train,y_train, cv=10)
print(scores)                                             
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

输出结果:
[0.66274662 0.78277035 0.82704868 0.50666923 0.68342449 0.61559652
0.8230043 0.84755478 0.66995966 0.47307991]
Accuracy: 0.69 (+/- 0.25)
从结果来看,较默认参数的模型也有很大提升,虽然略低于网格搜索的结果,但在搜索时间上几乎完胜网格搜索!只用了0.03的精度代价,取极大地减少了搜索时长,这样看来,随机搜索还是很高效的!

3.2 支持向量回归的调参

和回归树的基本步骤都一致,这里我们对SVR进行简述。基于SVR的默认参数,对训练集采取十折交叉验证

import numpy as np
from sklearn.svm import SVR     # 引入SVR类
from sklearn.pipeline import make_pipeline   # 引入管道简化学习流程
from sklearn.preprocessing import StandardScaler # 由于SVR基于距离计算,引入对数据进行标准化的类

pipe_SVR = make_pipeline(StandardScaler(),
                                                         SVR())
scores = cross_val_score(estimator=pipe_SVR,
                                                     X = X_train,
                                                     y = y_train,
                                                     scoring = 'r2',
                                                      cv = 10)       # 10折交叉验证

print(scores)                                             
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

输出结果:
[0.6108792 0.68514438 0.77364945 0.73473133 0.42834443 0.50937689
0.76837655 0.47761131 0.55608138 0.51236629]
Accuracy: 0.61 (+/- 0.24)
默认参数下,平均得分为0.61,和DTR差不多。

1.网格搜索

# 下面我们使用网格搜索来对SVR调参:
from sklearn.pipeline import Pipeline
pipe_svr = Pipeline([("StandardScaler",StandardScaler()),("svr",SVR())])
param_range = [0.0001,0.001,0.01,0.1,1.0,10.0,100.0,1000.0]
param_grid = [{"svr__C":param_range,"svr__kernel":["linear"]},  # 注意__是指两个下划线,一个下划线会报错的
                            {"svr__C":param_range,"svr__gamma":param_range,"svr__kernel":["rbf"]}]
gs = GridSearchCV(estimator=pipe_svr,
                                                     param_grid = param_grid,
                                                     scoring = 'r2',
                                                      cv = 10)       # 10折交叉验证
gs = gs.fit(X,y)
print("网格搜索最优得分:",gs.best_score_)
print("网格搜索最优参数组合:\n",gs.best_params_)

输出结果:
网格搜索最优得分: 0.6081303070817127
网格搜索最优参数组合:
{‘svr__C’: 1000.0, ‘svr__gamma’: 0.001, ‘svr__kernel’: ‘rbf’}
将这组参数结果,带回原模型中,看看在训练集上的表现:

pipe_SVR = make_pipeline(StandardScaler(),
                         SVR(C = 1000,gamma = 0.001,kernel = 'rbf'))
scores = cross_val_score(estimator=pipe_SVR,
                                                     X = X_train,
                                                     y = y_train,
                                                     scoring = 'r2',
                                                      cv = 10)       # 10折交叉验证

print(scores)                                             
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

输出结果:
[0.73338924 0.84677416 0.91733933 0.74984134 0.65726569 0.78470909
0.92336592 0.76859679 0.71849082 0.53738096]
Accuracy: 0.76 (+/- 0.22)
可以看出,这次平均得分直接飙升为为0.76,较之前的0.61有很大的提升

2.随机搜索

# 下面我们使用随机搜索来对SVR调参:
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import uniform  # 引入均匀分布设置参数
pipe_svr = Pipeline([("StandardScaler",StandardScaler()),("svr",SVR())])
distributions = dict(svr__C=uniform(loc=1.0, scale=4),    # 构建连续参数的分布
                     svr__kernel=["linear","rbf"],                                   # 离散参数的集合
                    svr__gamma=uniform(loc=0, scale=4))

rs = RandomizedSearchCV(estimator=pipe_svr,
                                                     param_distributions = distributions,
                                                     scoring = 'r2',
                                                      cv = 10)       # 10折交叉验证
rs = rs.fit(X,y)
print("随机搜索最优得分:",rs.best_score_)
print("随机搜索最优参数组合:\n",rs.best_params_)

输出结果:
随机搜索最优得分: 0.42996846334756544
随机搜索最优参数组合:
{‘svr__C’: 3.642395002760625, ‘svr__gamma’: 0.06358694538974197, ‘svr__kernel’: ‘rbf’}
验证:

pipe_SVR = make_pipeline(StandardScaler(),
                         SVR(C = 3.642395002760625,gamma = 0.06358694538974197,kernel = 'rbf'))
scores = cross_val_score(estimator=pipe_SVR,
                                                     X = X_train,
                                                     y = y_train,
                                                     scoring = 'r2',
                                                      cv = 10)       # 10折交叉验证

print(scores)                                             
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

输出结果:
[0.78270166 0.84261926 0.89393961 0.78892547 0.61062187 0.70809241
0.89456358 0.64741532 0.66281865 0.60651905]
Accuracy: 0.74 (+/- 0.21)
从结果来看,较默认参数的模型也有很大提升,略低于网格搜索的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值