sklearn快速入门教程:(四)模型自动调参

上个教程中我们已经看到在sklearn中调用机器学习模型其实非常简单。但要获得较好的预测效果则需要选取合适的超参数。在实际的项目中其实也有不少参数是由工程师借助其经验手动调整的,但在许多场景下这种方式仍然是很难行得通的。sklearn提供了十分简单易用的调参方法,可以轻松地实现对各类模型的调参。但调参的机制中涉及的概念相对较多,因此本文需要罗列一些必要的原理。

一、 调参的基本思想–交叉验证(Cross Validation)

根据上篇教程的内容我们容易想到,调参的根本目的实际上就是要找到一组合适的超参数,使得模型具有列好的效果,而更专业的说法则是希望让模型得到更好的泛化性能(可以简单理解为样本外的预测效果)。目前使用最为广泛的调参方法之一便是交叉验证,它的思路非常简单:

  • 将样本拆分为 k kk 个子集,用其中 k − 1 k-1k−1个子集的数据训练模型,再在剩下的一个子集上验证模型的性能。当所有子集都被作为测试集轮完一圈之后,计算模型在所有子集上的平均性能。
  • 对每一组超参数对应模型执行上述操作,选出平均性能最好的一组参数作为最优参数。

sklearn官方文档中给出了这样一张图很清楚地描述了这个过程(k-fold cross validation)。

在这里插入图片描述
至于为何要这样做,其理论相对较深,建议初学时不要太过于纠结,先用会即可(因为涉及较深的统计学知识)。其根本目的即是寻找出一组最优超参数,使其在各种样本组合下的平均性能都能达到最优,从而认为这组参数能够使得模型具有最强的泛化性能。

二、 实现交叉验证需要考虑哪些细节

上述描述其实已经给出了k − k-k−折交叉验证的基本实现思路,但这里还有两个细节的问题没有讨论:

  • 子集应该如何划分?
  • 备选的参数组合应该如何生成?
  • 评价模型性能的指标选什么?

实际上这两个问题非常复杂,子集划分可以有许多种方式:

  • k-fold: 随机将训练集划分为k kk个
  • leave-one-out: 将子集划分为n nn 个,即每个子集只有一个样本
  • hold-out: 将n nn个样本中的m mm个随机挑出作为测试集(当然也可以指定测试集)

备选参数的选择也有多种方式:

  • grid-search: 即给出每个超参数的备选范围,对所有组合进行穷举
  • random search: 以某种方式生成多种超参数的组合,穷举所有随机生成的结果

至于模型的评价指标,也是层出不穷:

  • 分类问题:分类精度、平衡精度、平均精度等
  • 回归问题:最大误差、均方误差、均方根误差等

这些选择,通常也只能根据具体问题结合经验进行选择。(这的确也是一件很麻烦的事情 )。

三、 sklearn中的实现方式(以GridSearchCV和SVR为例)

GridSearchCV即网格搜索的交叉验证法,这是最为常用的方法之一。在sklearn的官方文档中给出了该方法详细的输入参数和说明,而通常我们只需要考虑以下几个参数即可:

参数名称说明
estimator被调参的模型,即上一教程中提到的各类模型的class,比如tree,RandomForestRegressor等具体模型,以对象实例的形式传递。
param_grid被调参数的grid,以字典形式传递。
scoring模型评价指标,给出具体指标的名称字符串即可,如'accuracy','neg_mean_squared_error'等。
cv这个变量比较复杂。一般来说我们直接取整数即可,也就是k-fold中的k即可。特别地当k等于样本个数时,它就是留一法。

为方便起见我们先用官方给出的示例代码做一些说明:

>>> from sklearn import svm, datasets
>>> from sklearn.model_selection import GridSearchCV
>>> iris = datasets.load_iris()
>>> parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}
>>> svc = svm.SVC()
>>> clf = GridSearchCV(svc, parameters)
>>> clf.fit(iris.data, iris.target)
GridSearchCV(estimator=SVC(),
             param_grid={'C': [1, 10], 'kernel': ('linear', 'rbf')})
>>> sorted(clf.cv_results_.keys())
['mean_fit_time', 'mean_score_time', 'mean_test_score',...
 'param_C', 'param_kernel', 'params',...
 'rank_test_score', 'split0_test_score',...
 'split2_test_score', ...
 'std_fit_time', 'std_score_time', 'std_test_score']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这里面需要特别说明有几个问题:

(1)参数网格的设定(第4行)

变量parameters即是param_grid的值。可以看到它是以==字典(dict)==的形式给出的。一般在写程序的时候如果参数较多,我们其实更喜欢看这样的写法:

parameters = {
    			'kernel':('linear', 'rbf'), 
    			'C':[1, 10]
			  }
  • 1
  • 2
  • 3
  • 4

这里就需要回顾一下python的基本数据结构。字典类型的本质其实就是典型的key-value结构。在花括号中每一个逗号分隔的就是字典的一条记录,这条记录中冒号左边是key的名称,用单引号,冒号右边则是value。注意这里非常非常舒服的一点是这个value可以是任意的合法类型。那么这样一来,我们只需要考虑每个参数的取值范围即可,非常方便。

在设好了这样的GridSearchCV中我们只需要将这样的一个字典传入,函数将自动根据设定的范围对每种组合进行穷举。比如上面这段代码实际上给出的是这样的一种组合:

kernel = 'linear', C = 1
kernel = 'linear', C = 10
kernel = 'rbf', C = 1
kernel = 'rbf', C = 10
  • 1
  • 2
  • 3
  • 4

试想如果我们有非常多的超参数需要调(比如随机森林就有非常多的超参数),如果自己动手写循环那么一个参数就是一个循环,非常麻烦。而sklearn则给我们提供了一种非常简单的实现方式。

(2)返回类型

GridSearchCV从最后一行代码中可以看到,返回值的类型其实很复杂,内容特别多。而这里我们首先关注的就是两个东西:

  • 最优参数 best_params_:它是以字典的形式存储,比如上述代码运行完成后,可以直接通过clf.best_params_来查看具体的最优参数,并且保留了原参数名。
  • **最优模型 **best_estimator_ : best_estimator_就是在整个过程中表现最好的那一个模型(平均性能最优)。它的本质就是sklearn中的estimator,再说得直接一点,如果被调的模型是SVR,那么它就是SVR;如果被调的是tree那么它就是tree。根据我们前面所讲,如果想要用它来进行预测,则直接对它进行操作即可,即调用clf.best_estimator.predict(X)

上述两个参数是与我们最直接关心的,当然还有更多的详细参数,这些内容在具体问题中对应读取查看就可以了。

另外,我们之前提到过除了GridSearchCV之外还有另外的随机调参方法,它叫做RandomizedSearchCV,而这里随了对随机方法的指定以外,基本用法和其它参数的设定也几乎一模一样。

四、 其它问题

(1)并行计算

并行计算是sklearn中的另一个亮点,它对一些能够并行的方法提前进行了封装,在使用的时候只需要简单一个参数即可。在GridSearchCV中,只需要在输入参数中设定n_jobs大于等于2即可,这个参数即是代表需要用来并行的核心数量。比如:

# 使用两个核心并行
clf = GridSearchCV(svc, parameters, n_jobs =2)
# 使用全部的核心并行
clf = GridSearchCV(svc, parameters, n_jobs =-1)
  • 1
  • 2
  • 3
  • 4

另外特别要注意的一点是,sklearn的并行没有任何对硬件的保护机制。简单地说就是它会尽一切可能压榨CPU的效率,在能超频的时候它一点也不会客气。这在用大量级的数据集,网格较密和核心较多的时候要特别小心。因为超频的代价就是CPU的温度会瞬间飙升,至于会不会引起硬件的其它问题目前还没遇到,但一定要慎用

(2)自定义调参

从常理上讲,sklearn本身是开源的,源码实际上可以进行修改。不过sklearn本身也提供了一些方便的接口供用户进行自定义。比如上面提到的评价指标,sklearn就提供了详细的文档供开发者参考。比如:

自定义指标:3.3. Metrics and scoring: quantifying the quality of predictions — scikit-learn 1.1.3 documentation

使用多指标:3.2. Tuning the hyper-parameters of an estimator — scikit-learn 1.1.3 documentation

当然,集合的划分等问题也可以自定义,可以参考:

CV Splitter: Glossary of Common Terms and API Elements — scikit-learn 1.1.3 documentation

五、小结

那么到这里,从如何调用sklearn的基本库到如何进行自动调参就全部讲解完毕。学到这一步相信许多同学已经可能在标准数据集和一些自己的数据集上调出较好的模型了。更多的内容待后续继续讲解。

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值