Python机器学习笔记GridSearchCV(⽹格搜索)
在机器学习模型中,需要⼈⼯选择的参数称为超参数。⽐如随机森林中决策树的个数,⼈⼯神经⽹络模型中隐藏层层数和每层的节点个数,正则项中常数⼤⼩等等,他们都需要事先指定。超参数选择不恰当,就会出现⽋拟合或者过拟合的问题。⽽在选择超参数的时候,有两个途径,⼀个是凭经验微调,另⼀个就是选择不同⼤⼩的参数,带⼊模型中,挑选表现最好的参数。
微调的⼀种⽅法是⼿⼯调制超参数,直到找到⼀个好的超参数组合,这么做的话会⾮常冗长,你也可能没有时间探索多种组合,所以可以使⽤Scikit-Learn的GridSearchCV来做这项搜索⼯作。下⾯让我们⼀⼀探索。
1,为什么叫⽹格搜索(GridSearchCV)?
GridSearchCV的名字其实可以拆分为两部分,GridSearch和CV,即⽹格搜索和交叉验证。这两个名字都⾮常好理解。⽹格搜索,搜索的是参数,即在指定的参数范围内,按步长依次调整参数,利⽤调整的参数训练学习器,从所有的参数中找到在验证集上精度最⾼的参数,这其实是⼀个训练和⽐较的过程。
GridSearchCV可以保证在指定的参数范围内找到精度最⾼的参数,但是这也是⽹格搜索的缺陷所在,他要求遍历所有可能参数的组合,在⾯对⼤数据集和多参数的情况下,⾮常耗时。
2,什么是Grid Search⽹格搜索?
Grid Search:⼀种调参⼿段;穷举搜索:在所有候选的参数选择中,通过循环遍历,尝试每⼀种可能性,表现最好的参数就是最终的结果。其原理就像是在数组⾥找到最⼤值。这种⽅法的主要缺点是⽐较耗时!
所以⽹格搜索适⽤于三四个(或者更少)的超参数(当超参数的数量增长时,⽹格搜索的计算复杂度会呈现指数增长,这时候则使⽤随机搜索),⽤户列出⼀个较⼩的超参数值域,这些超参数⾄于的笛卡尔积(排列组合)为⼀组组超参数。⽹格搜索算法使⽤每组超参数训练模型并挑选验证集误差最⼩的超参数组合。
2.1,以随机森林为例说明GridSearch⽹格搜索
下⾯代码,我们要搜索两种⽹格,⼀种是n_estimators,⼀种是max_features。GridSearch会挑选出最适合的超参数值。
del_lection import GridSearchCV
param_grid = [
{'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},
{'bootstrap': [Fal], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]},
]
forest_reg = RandomForestRegressor()
grid_arch = GridSearchCV(forest_reg, param_grid, cv=5,
高山流水古琴曲
scoring='neg_mean_squared_error')
grid_arch.fit(housing_prepared, housing_labels)戒指右手中指含义
中国昆明 sklearn 根据param_grid的值,⾸先会评估3×4=12种n_estimators和max_features的组合⽅式,接下来在会在bootstrap=Fal 的情况下(默认该值为True),评估2×3=6种12种n_estimators和max_features的组合⽅式,所以最终会有12+6=18种不同的超参数组合⽅式,⽽每⼀种组合⽅式要在训练集上训练5次, 所以⼀共要训练18×5=90 次,当训练结束后,你可以通过best_params_获得最好的组合⽅式。
grid_arch.best_params_
输出结果如下:
{‘max_features’: 8, ‘n_estimators’: 30}
得到最好的模型:
grid_arch.best_estimator_
输出如下:
RandomForestRegressor(bootstrap=True, criterion=‘m’, max_depth=None,
max_features=8, max_leaf_nodes=None, min_impurity_decrea=0.0,
min_impurity_split=None, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
n_estimators=30, n_jobs=1, oob_score=Fal, random_state=None,
verbo=0, warm_start=Fal)
如果GridSearchCV初始化时,refit=True(默认的初始化值),在交叉验证时,⼀旦发现最好的模型
(estimator),将会在整个训练集上重新训练,这通常是⼀个好主意,因为使⽤更多的数据集会提升模型的性能。
以上⾯有两个参数的模型为例,参数a有3中可能,参数b有4种可能,把所有可能性列出来,可以表⽰成⼀个3*4的表格,其中每个cell 就是⼀个⽹格,循环过程就像是在每个⽹格⾥遍历,搜索,所以叫grid arch。
2.2,以Xgboost为例说明GridSearch⽹格搜索
下⾯以阿⾥IJCAI⼴告推荐数据集与XgboostClassifier分类器为例,⽤代码形式说明sklearn中GridSearchCV的使⽤⽅法。(此⼩例的代码是参考这⾥:)
import pandas as pd
import xgboost as xgb论文的引言
id_arch import GridSearchCV
#导⼊训练数据
traindata = pd.read_csv("/traindata_",p = ',')
traindata = traindata.t_index('instance_id')
trainlabel = traindata['is_trade']
del traindata['is_trade']
print(traindata.shape,trainlabel.shape)
#分类器使⽤ xgboost
clf1 = xgb.XGBClassifier()
#设定⽹格搜索的xgboost参数搜索范围,值搜索XGBoost的主要6个参数
param_dist = {
'n_estimators':range(80,200,4),
'max_depth':range(2,15,1),
'learning_rate':np.linspace(0.01,2,20),
'subsample':np.linspace(0.7,0.9,20),
'colsample_bytree':np.linspace(0.5,0.98,10),
'min_child_weight':range(1,9,1)
}
#GridSearchCV参数说明,clf1设置训练的学习器
#param_dist字典类型,放⼊参数搜索范围
#scoring = 'neg_log_loss',精度评价⽅式设定为“neg_log_loss“
#n_iter=300,训练300次,数值越⼤,获得的参数精度越⼤,但是搜索时间越长
#n_jobs = -1,使⽤所有的CPU进⾏训练,默认为1,使⽤1个CPU
grid = GridSearchCV(clf1,param_dist,cv = 3,scoring = 'neg_log_loss',n_iter=300,n_jobs = -1)
#在训练集上训练
草帽饼
grid.fit(traindata.values,np.ravel(trainlabel.values))
#返回最优的训练器
best_estimator = grid.best_estimator_
print(best_estimator)
tenda路由器#输出最优训练器的精度
这⾥关于⽹格搜索的⼏个参数在说明⼀下,评分参数“scoring”,需要根据实际的评价标准设定,阿⾥的IJCAI的标准
时“neg_log_loss”,所以这⾥设定为“neg_log_loss”,sklearn中备选的评价标准如下:在⼀些情况下,sklearn中没有现成的评价函数,sklearn是允许我们⾃定义的,但是需要注意格式。
接下来看⼀下我们定义的评价函数:
ics import make_scorer
def logloss(act, pred):
epsilon = 1e-15
pred = sp.maximum(epsilon, pred)
pred = sp.minimum(1-epsilon, pred)
ll = sum(act*sp.log(pred) + sp.subtract(1, act)*sp.log(sp.subtract(1, pred))) ll = ll * -1.0/len(act)
return ll
#这⾥的greater_is_better参数决定了⾃定义的评价指标是越⼤越好还是越⼩越好loss = make_scorer(logloss, greater_is_better=Fal)
score = make_scorer(logloss, greater_is_better=True)
定义好以后,再将其带⼊GridSearchCV函数就好。
这⾥再贴⼀下常⽤的集成学习算法⽐较重要的需要调参的参数:
2.3,以SVR为例说明GridSearch⽹格搜索
以两个参数的调优过程为例:
from sklearn.datats import load_iris
from sklearn.svm import SVC
del_lection import train_test_split
iris_data = load_iris()
X_train,X_test,y_train,y_test = train_test_split(iris_data.data,iris_data.target,random_state=0)
# grid arch start
best_score = 0
for gamma in [0.001,0.01,1,10,100]:
for c in [0.001,0.01,1,10,100]:
# 对于每种参数可能的组合,进⾏⼀次训练
svm = SVC(gamma=gamma,C=c)
svm.fit(X_train,y_train)
score = svm.score(X_test,y_test)
# 找到表现最好的参数
if score > best_score:
best_score = score肺结核治疗
best_parameters = {'gamma':gamma,"C":c}
print('Best socre:{:.2f}'.format(best_score))
print('Best parameters:{}'.format(best_parameters))
输出结果:
Best socre:0.97
Best parameters:{'gamma': 0.001, 'C': 100}
2.4 上⾯调参存在的问题是什么呢?
绣眼鸟大叫
原始数据集划分成训练集和测试集以后,其中测试集除了⽤作调整参数,也⽤来测量模型的好坏;这样做导致最终的评分结果⽐实际效果好。(因为测试集在调参过程中,送到了模型⾥,⽽我们的⽬的是将训练模型应⽤到unen data上)。
2.5 解决⽅法是什么呢?
对训练集再进⾏⼀次划分,分为训练集和验证集,这样划分的结果就是:原始数据划分为3份,分别为:训练集,验证集和测试集;其中训练集⽤来模型训练,验证集⽤来调整参数,⽽测试集⽤来衡量模型表现好坏。
代码: