使用sklearn实现估计器的调参方法
有些刚刚接触机器学习的人总是弄混超参数和参数的意思,在深度学习中超参数对应着我们的网络学习到的参数,就是每一层的权重w,而参数就是网络的层数或者epoch这些。
而在机器学习中也是如此,举个例子,对于随机森林来说,我们调的树的棵树就是超参数,而参数就是我们模型内部有关书的形状的一些参数。
可以这样说,超参数的选择决定着模型参数的值,我们调整超参数的目的就是使模型内部的参数能够尽可能拟合数据集。
但是我们刚刚接触的时候,不知道每个参数的意义或者是参数范围很广,很难找出一个合适的参数组合使我们模型的效果达到最佳。
scikit-learn中提供了两种搜索参数的策略,一种是GridSearchCV,另外一种就是RandomizedSearchCV,两种的中文解释分别是网格搜索和随机搜索,他们可以根据给定的参数空间进行采样分别对评估器进行评估。
1.网格搜索(GridSearchCV)
GridSearchCV从两部分来看,一部分是GridSearch,另外一部分就是CV,分别是网格搜索和交叉验证,简单地来说就是首先遍历所有的参数选择,然后将每一种参数组合放进模型进行交叉验证取平均分,然后获得达到最高分数的参数组合。
下面我们用代码演示一下:
from sklearn import svm from sklearn.model_selection import GridSearchCV from sklearn.datasets import load_digits X,y=load_digits(return_X_y=True) svc=svm.SVC() # 该列表内部放置了两个字典,所以在参数搜索时可以指定两套方案 param_grid = [ {'C': [1, 10, 100, 1000], 'kernel': ['linear']}, {'C': [1, 10, 100, 1000], 'gamma': [0.001, 0.0001], 'kernel': ['rbf']}, ] clf=GridSearchCV(svc,param_grid,cv=5) # 进行网络搜索 clf.fit(X,y) # 返回最佳模型 clf.best_estimator_ # 返回最佳参数组合 clf.best_params_ # 返回最优分数 clf.best_score_
输出结果:
# 返回最佳参数下的模型 SVC(C=1, break_ties=False, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, gamma=0.001, kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False) # 返回最佳参数组合 {'C': 1, 'gamma': 0.001, 'kernel': 'rbf'} # 返回最佳参数组合下的验证集上最佳的分数 0.9721866295264624
2.随机参数搜索(RandomizedSearchCV)
对于网格搜索来说,我们觉得非常好,能够帮助我们搜索到模型的最优参数,但是这样也会付出一定代价,代价就是要不断地进行迭代尝试所有的参数组合,如果模型较为复杂,参数过多,这样会加重我们的计算。
所以有人相出了一种方式就是我们不讲所有的参数进行尝试,将所有可供选择的参数进行采样,只选出一部分来进行估计。这样就能够帮助我们大大减少计算提高效率。
对于那种类别的参数或者是有限个数的参数就是随机抽取n_iter次,该参数可以由我们来进行设定。对于那种连续性参数,我们就需要构造一种分布,让我们的优化器可以在该分布内进行随机采样,之后我们会对采样后的参数进行组合去进行交叉验证。
举个例子对于SVC模型中的参数C值:我们确实可以采用网格搜索[1,10,100,1000],但是不能够做到连续,只可以在这4个值中进行选择,有人说将列表中的值变得更多,更多它也还是有限个,而且增多会消耗更多的时间去搜索参数。
这是我们可以使用随机参数搜索将C的值构造一种分布,均匀分布、正态分布这些,然后优化器就会从该分布中进行随机抽取值,比如我们将C构造成标准正态分布,此时C的值就可以从满足标准正态分布中进行随机抽取,这样我们获得的值就很随机,不会存在断点效应。
构造分布可以使用scipy库,一般有:
import scipy scipy.stats.uniform(loc=0, scale=4) scipy.stats.expon(scale=100) # 分布器 <scipy.stats._distn_infrastructure.rv_frozen at 0x279582fc3c8>
如果我们想让我们的参数搜索更加精细,就可以适当增大n_iter的数值。
下面用代码演示一下:
import numpy as np from sklearn import svm from sklearn.model_selection import RandomizedSearchCV from sklearn.datasets import load_digits import scipy X,y=load_digits(return_X_y=True) svc=svm.SVC(kernel='linear',C=1) param_grid = [ {'C': scipy.stats.uniform(loc=0, scale=4), 'kernel': ['linear','rbf']}, ] # 该处指定了多个评估指标,在验证时考虑多个指标 scorings=['accuracy','f1_macro'] clf=RandomizedSearchCV(svc,param_grid,cv=2,n_iter=1,refit='accuracy',scoring=scorings,random_state=2021) clf.fit(X,y) clf.best_params_ clf.best_estimator_
输出结果:
# 最佳模型 SVC(C=2.423913115229619, break_ties=False, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False) # 最佳参数组合 {'C': 2.423913115229619, 'kernel': 'rbf'}
多评估指标验证(cross validate)
对于交叉验证,默认是使用模型默认的评估指标,当我们需求较为复杂时,可以考虑使用cross validate进行多评估指标验证。
比如说,现在有100个人,其中有98个好人,2个坏人,如果我们的模型不做任何处理,单纯把所有的人判断成好人,那么模型的准确率也有98%,很高,但是这个准确率显示是不能够衡量我们的模型质量的,尽管识别了98个好人,但是那两个坏人我们的模型是没有衡量出来的,所以单一的评估指标就不行了,可以增加召回率、AUC这些进行衡量。
我们用代码演示一下如何使用cross validate进行多评估指标验证:
from sklearn.model_selection import cross_validate cross_validate(svc,X,y,cv=2,scoring=['accuracy','f1_macro'],return_train_score=True,return_estimator=True)
输出结果:
{'fit_time': array([0.01344371, 0.01591587]), 'score_time': array([0.02537107, 0.01695299]), 'estimator': (SVC(C=1, break_ties=False, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, gamma='scale', kernel='linear', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False), SVC(C=1, break_ties=False, cache_size=200, class_weight=None, coef0=0.0, decision_function_shape='ovr', degree=3, gamma='scale', kernel='linear', max_iter=-1, probability=False, random_state=None, shrinking=True, tol=0.001, verbose=False)), 'test_accuracy': array([0.93325918, 0.94766147]), 'train_accuracy': array([1., 1.]), 'test_f1_macro': array([0.93369535, 0.94782131]), 'train_f1_macro': array([1., 1.])}
上边函数的参数为评估器、X、y、评估方式、是否返回模型在训练集的分数、是否返回模型