1. 方差与偏差
在前文中我们已经提到了有关方差(Variance)与偏差(bias)的概念,这里系统的进行介绍。
首先我们先来介绍过拟合的概念。我们在最开始的时候就介绍过,样本集需要分割成训练样本和测试样本,训练样本用于训练模型,测试样本用于评估模型。但我们也可以使用训练样本来计算模型精度。
下面这张图中是一个一元特征空间的拟合问题,横坐标是特征值,纵坐标是对应的y值,蓝色点是分割出来的训练样本集,黄色点是测试样本集。这一眼看上去就是一个很简单的线性回归(我们这里只是用这个问题进行举例,希望大家把这个线性回归看做一个很“复杂”的问题)。
下图三个模型中大家觉得哪个模型是预测最准确的呢?
相信大家一眼看过去,心里已经有了答案,但你有没有思考过,你为什么会得出这样的结论呢?
我们一个个来看。首先,左图的模型看起来非常完美,这个模型完美就完美在非常的“均匀”,用一个参数来衡量,就是测试样本计算得到的均方根误差最小,而训练样本计算得到的均方根误差最大;右图的模型则非常的“离谱”,测试样本计算得到的均方根误差最大,而训练样本计算得到的均方根误差最小,差不多为0,预测值与真实值基本一样;中间这个模型介于两者之间。
在机器学习算法的实际应用中,我们都希望得到左图的“完美模型”,而事实是,由于机器学习算法非常“强大”的拟合能力,使得我们得到右图的过拟合模型。这个时候我们就希望通过调参,来使得我们的机器学习模型能够尽可能的靠近“完美模型”(但事实上往往没有办法得到完美模型的,我们能够得到的最佳模型基本就是中间这幅图)。
事实上,方差与偏差就是描述机器学习模型准确性的两个概念,这时候我们需要上一张经典示意图来帮助理解:
大家回顾一下在岭回归与Lasso回归那一节我们曾经说过,加入正则项之后,我们是通过牺牲偏差来减小模型的方差的,用这幅图来解释就是,我们没有办法得到左上那种完美模型,因此我们退而求其次,通过加入惩罚项,使得模型的方差减小,但偏差增加,也就是选择了左下这种模型(当然,我们的偏差没有那么大,是在允许范围内的偏差)。
方差过大或者偏差过大,模型的精确度都会很差劲,如下图所示,左上和右下的模型表型都很差,但他们影响模型精确度的方式不一样,方差过大会使得样本点预测值更加“分散”,方差体现的是模型在测试集上表现的稳健程度;而偏差过大则会使样本点预测值更加“偏离”,偏差体现的是模型在测试集上的偏离程度。
一个模型的差误有方差与偏差以及噪声,在这里我们统称为“泛化误差”,接下来这张图非常重要,需要仔细体会。
在模型复杂度比较小的时候,方差可能会比较低(因为此时模型简单,比较稳健),偏差可能会比较大(因为模型欠拟合),但随着模型复杂度的增加,模型越来越准确,模型的偏差逐渐减小(可以理解为,训练集样本计算的误差逐渐变小,模型逐渐过拟合),模型的方差逐渐增大(可以理解为,测试集样本计算的误差逐渐变大,模型逐渐过拟合)。
调参的意义是:尽量降低模型的复杂性,使得模型略微欠拟合或者略微过拟合的情况下,方差尽可能的小。
2. 调参工具
在正式介绍调参之前,我们还需要了解一些调参工具。
2.1 K折交叉验证
有时候我们的样本集数据很少,只有几百个乃至于几十个,这个时候其实偶然性很大,在统计学意义上来说即便划分测试集与样本集也意义不大,这个时候我们可以使用K折交叉验证。
将数据分成1,2,3...k一共k份,然后将第i份数据作为测试集验证精度,其余k-1份作为建模集,这样训练k次,将每次训练得到的精度结果进行平均作为该模型的精度,这就是k折交叉验证。
调参是一个黑盒优化的过程,它不像我们在前面介绍各种算法时提到的凸优化问题可以求极值可以梯度下降,我们所要优化的“函数”是看不见的或者说不能确切描述的,犹如盲人摸象,只能这里摸一下,那里戳一下,然后得到一个大概的轮廓。
其实调参方法很多,包括Grid search(网格搜索)、Random search(随机搜索),还有Genetic algorithm(遗传算法)、Paticle Swarm Optimization(粒子群优化)、Bayesian Optimization(贝叶斯优化)、TPE、SMAC等。
以下介绍三种最常用的调参方法。
2.2 网格搜索
在Lasso回归那一节我们介绍过网格搜索。其实这个很好理解,我们虽然不知道使得模型精度最好的参数是什么,但我们知道他的大概范围,那么我们就在这个大概范围内以一定间隔选取一些数进行尝试,通过测试集或者K折交叉验证来选取出最佳的精度。
举个例子。假设我们想要y=ax这个模型的a值,我们使用网格搜索,假设我们已经知道a很大概率大于0,那我们就从(0,1000]这个范围内,每隔100试一次,[100,200,300,400,500,600,700,800,900,1000],结果发现当a=100时,测试集精度最高,这个时候你说a=100模型最佳,那当然可以。但是你有没有想过,有可能在0到100之间有比100更加优秀的参数取值呢?因此我们上一步粗略的确定范围之后,再从(0, 100]范围内每隔10试一次,以此类推,直到找到最佳参数为止。当然了,具体情况具体讨论,调参需要灵活的手脑结合,这里只是举了一个例子帮助理解。
当有两个参数a,b的时候,a的范围设置在[1,2,3,4,5],b的范围设置在[0.2,0.4,0.8,1.0]。这个时候我们需要遍历a,b的所有有可能的组合,也就是一个“网格”了。
这种方法的缺点也是显而易见的,很明显这就是一个遍历的方法,因此计算量是显而易见的大,尤其是在多个参数,参数范围过大难以确定,再加上多次K折的时候,效率非常差。举例假设有3个参数,每个参数的取值有1000个,再加上5次k折,那么就需要训练:3*1000*5=15000次。
2.3 随机搜索
随机搜索是在网格搜索上做了一个优化,以避免掉一些不必要的计算,从而获得更加高的效率。本质上就是一种瞎猜罢了,相对于网格搜索提高了效率,但也更加容易陷入局部最优。
2.4 贝叶斯优化
贝叶斯优化在黑盒优化中可以说是使用范围最广,表现也相对比较好的一种算法。
目前贝叶斯优化算法应用最广的是SMBO(Sequential Model-Based Optimazation),即基于模型的序列优化。目前有三种常见的SMBO算法:基于高斯过程回归的序列超参优化、基于随机森林算法代理的序列超参优化(即 smac),基于TPE算法代理的序列超参优化。算法众多但基本思想类似,这里以smac为例进行介绍。当然了实际使用贝叶斯优化有很多现成的算法包,并不需要掌握其基础原理,感兴趣的话可以看看。
所谓的贝叶斯优化实际上也是将黑盒假设成了某一个具体的已知模型,我们称为代理模型,例如smac算法的代理模型为随机森林模型,这个随机森林模型的输入是超参数空间的随机取值params_config,输出则是在当前这个params_config下,模型的表现metric_val,最后通过拟合这个模型,来获得其局部最优的metric_val,此时的params_config就是我们调参的结果了。
然而拟合这个代理模型的代价是巨大的,因为我们知道每次得到一个(params_config, metric_val)的代价都需要我们训练一次(X, y), 因此我们引入贝叶斯优化的概念,借助先验后验的知识,来使得代价最小。
如图smac-1所示,左图是待拟合的代理模型,在横轴,也就是params_config轴范围内,每一处模型的方差都是相等且都是很大的,因为此时没有已知点,在随机引入一个已知的(params_config, metric_val)后,图像发生了变化,在该点附近的方差变小了。
贝叶斯优化每次都只引入一个新的点,那么问题来了,我们如何确定下一个点的config呢?这时候就要提到一个非常关键的函数acquisition function,这个函数就是帮助计算接下来要引入哪一个点,这个函数具体原理有兴趣可以自行查找资料,总之它比较感兴趣的下一个点有两个条件:1. 离目前的已知点较远,也就是该点周围的方差较大;2.离全局最优的点足够近。
根据这个原则,当我们找到足够多的已知点后,就可以拟合代理模型,最后求得该代理模型的全局最优值best metric_val以及其对应的params_config。
3. 超参数
光有了工具还不够,调参调参,有了“调”的工具,我们还需要了解我们调整的“参”到底是什么,有什么样的范围和性质,才能动手去调。
我们以岭回归算法为例,在该算法中,权重矩阵是我们可以通过训练集样本数据计算得到的,但惩罚项的系数不可以,这种不可以通过训练集样本求解得到的,模型固有的参数,就是超参数,它影响着我们模型的精度,但是却不可以直接计算得出,因此我们就需要用上面介绍的那些黑盒优化的方式来进行调试。
举一个不恰当的例子,厂家在生产自行车的时候,自行车的轮胎直径、各零件的尺寸,都可以通过设计图计算得到,这些参数不需要也不能随便调整,都是根据其他零件的尺寸相配套计算得出的。但是自行车的坐垫高度却需要根据不同的使用者进行调整至最舒适的高度。这里的坐垫高度就像是超参数,需要根据不同的训练集调整至不同的值,使得预测效果最佳。当然不调整也可以,你也可以坐着特别高的坐垫骑车,只不过比较容易发生危险罢了。
以下介绍几种常用机器学习算法的参数(基本都是以Python的Sklearn为例)
3.1 SVM参数
首先推荐一个链接:https://www.cnblogs.com/pinard/p/6117515.html
这个链接非常详细的归纳了SVM函数的参数,可以当做工具书查阅。但这里我们只介绍两个对于SVM最重要的参数:
1. 惩罚系数C
在介绍SVM的时候我们提到过一个软间隔的概念,有需要的可以回顾一下,如下图所示,通常二分类问题并不是完全线性可分的,会有一些“交错”的点。图中黑色线是最佳超平面,而虚线到直线的距离就是软间隔,同时两个虚线之间的点就是支持向量。惩罚系数就是对这个软间隔的大小进行设置的参数。
默认C=1,C越趋近于0,软间隔越大,支持向量越多,模型的容错性越强,模型越“稳健”。一般需要通过交叉验证来选择一个合适的C。一般来说,如果噪音点较多时,C需要小一些。如果用我们上面介绍的方差与偏差的理论来解释,请看下面这张图,当C越接近0,我们可以看做把总体泛化误差向左推。反之亦然。
2. 核函数
在SVM那节我们说过,针对线性不可分的情况,SVM是通过把低维特征向量映射到高维特征空间使其变得线性可分的,因此核函数的选择对于SVM算法至关重要。
在scikit-learn中,内置的核函数一共有4种,当然如果你认为线性核函数不算核函数的话,那就只有三种。
1)线性核函数(Linear Kernel)表达式为:K(x,z)=x∙z,就是普通的内积,LinearSVC 和 LinearSVR 只能使用它。
2) 多项式核函数(Polynomial Kernel)是线性不可分SVM常用的核函数之一,表达式为:K(x,z)=(γx∙z+r)^d ,其中,γ,r,d都需要自己调参定义,比较麻烦。
3)高斯核函数(Gaussian Kernel),在SVM中也称为径向基核函数(Radial Basis Function,RBF),它是libsvm默认的核函数,当然也是scikit-learn默认的核函数。表达式为:K(x,z)=exp(−γ||x−z||^2), 其中,γ大于0,需要自己调参定义。
4)Sigmoid核函数(Sigmoid Kernel)也是线性不可分SVM常用的核函数之一,表达式为:K(x,z)=tanh(γx∙z+r), 其中,γ,r都需要自己调参定义。
一般情况下,对非线性数据使用默认的高斯核函数会有比较好的效果,如果你不是SVM调参高手的话,建议使用高斯核来做数据分析。
除去以上惩罚系数与核函数的参数需要调参外,SVM还有正则化参数需要调参,因为在Lasso回归里面已经讲过这个问题,因此不再赘述。
3.2 RF参数
还是先上链接:scikit-learn随机森林调参小结:https://www.cnblogs.com/pinard/p/6160412.html
这个链接对RF的每一个参数的讲解都非常详细了。
在介绍随机森林的时候我们说过,bagging的方法是将一堆弱学习器集成为强学习器,因此,参数又分为单个决策树参数和整体的框架参数
1. 框架参数
下面我们来看RF重要的Bagging框架的参数,由于RandomForestClassifier和RandomForestRegressor参数绝大部分相同,这里会将它们一起讲,不同点会指出。
1)n_estimators: 也就是最大的弱学习器的个数。一般来说n_estimators太小,容易欠拟合,n_estimators太大,计算量会太大,并且n_estimators到一定的数量后,再增大n_estimators获得的模型提升会很小,所以一般选择一个适中的数值。默认是100。
2) oob_score :即是否采用袋外样本来评估模型的好坏。这个不是超参数,默认识False。个人推荐设置为True,因为袋外分数反应了一个模型拟合后的泛化能力(而且有时候这个值比K折验证的精度值,比如均方根误差之类的,更能有效反应模型精度)。
3)criterion: 即CART树做划分时对特征的评价标准。分类模型和回归模型的损失函数是不一样的。分类RF对应的CART分类树默认是基尼系数gini,另一个可选择的标准是信息增益。回归RF对应的CART回归树默认是均方差mse,另一个可以选择的标准是绝对值差mae。一般来说选择默认的标准就已经很好的。
从上面可以看出, RF重要的框架参数比较少,主要需要关注的是 n_estimators,即RF最大的决策树个数,调参一般一上来就先调这个值。
2. 决策树参数
这部分参数学习之前,一定要先认真回顾决策树中的CART树算法。
1) 单棵决策树使用的最大特征数max_features: 可以使用很多种类型的值,默认是"auto",意味着每棵树划分时最多考虑√N个特征;如果是"log2"意味着划分时最多考虑log2N个特征;如果是"sqrt"或者"auto"意味着划分时最多考虑√N个特征。如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑(百分比xN)取整后的特征数。其中N为样本总特征数。一般我们用默认的"auto"就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
2) 决策树最大深度max_depth: 默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。
3) 内部节点再划分所需最小样本数min_samples_split: 这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
4) 叶子节点最少样本数min_samples_leaf: 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
5)叶子节点最小的样本权重和min_weight_fraction_leaf:这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。 默认是0,就是不考虑权重问题。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
6) 最大叶子节点数max_leaf_nodes: 通过限制最大叶子节点数,可以防止过拟合,默认是"None”,即不限制最大的叶子节点数。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。
7) 节点划分最小不纯度min_impurity_split: 这个值限制了决策树的增长,如果某节点的不纯度(基于基尼系数,均方差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。一般不推荐改动默认值1e-7。
上面决策树参数中最重要的包括最大特征数max_features, 最大深度max_depth, 内部节点再划分所需最小样本数min_samples_split和叶子节点最少样本数min_samples_leaf。
还是用这张图来解释,根据上文对每一个参数的解释,我们知道,max_depth和max_features这两个参数变大时,都是将模型总体的泛化精度向右推,模型变复杂;min_sample_split和min_sample_leaf这两个参数变大时,都是将模总体的泛化精度向左推,模型变简单。
3.3 GBDT参数
与随机森林相同,GBDT算法的参数也分为框架参数和单个弱学习器的参数。
链接在这儿:https://www.cnblogs.com/pinard/p/6143927.html
1. 框架参数
首先,我们来看boosting框架相关的重要参数,相比较RF而言,GBDT的框架参数要复杂一些。由于GradientBoostingClassifier和GradientBoostingRegressor的参数绝大部分相同,我们下面会一起来讲,不同点会单独指出。
1)n_estimators: 也就是弱学习器的最大迭代次数,或者说最大的弱学习器的个数。一般来说n_estimators太小,容易欠拟合,n_estimators太大,又容易过拟合,一般选择一个适中的数值。默认是100。在实际调参的过程中,我们常常将n_estimators和下面介绍的参数learning_rate一起考虑。
2)learning_rate: 即每个弱学习器的权重缩减系数ν,也称作步长,在原理篇的正则化章节我们也讲到了,加上了正则化项,我们的强学习器的迭代公式为。ν的取值范围为0<ν≤1。对于同样的训练集拟合效果,较小的ν意味着模型收敛速度慢,我们需要更多的弱学习器的迭代次数。通常我们用步长和迭代最大次数一起来决定算法的拟合效果。所以这两个参数n_estimators和learning_rate要一起调参。一般来说,可以从一个小一点的ν开始调参,默认是1。
3) subsample: 即我们在原理篇的正则化章节讲到的子采样,取值为(0,1]。注意这里的子采样和随机森林不一样,随机森林使用的是放回抽样,而这里是不放回抽样。如果取值为1,则全部样本都使用,等于没有使用子采样。如果取值小于1,则只有一部分样本会去做GBDT的决策树拟合。选择小于1的比例可以减少方差,即防止过拟合,但是会增加样本拟合的偏差,因此取值不能太低。推荐在[0.5, 0.8]之间,默认是1.0,即不使用子采样。
4) init: 即我们的初始化的时候的弱学习器,拟合对应原理篇里面的f0(x),如果不输入,则用训练集样本来做样本集的初始化分类回归预测。否则用init参数提供的学习器做初始化分类回归预测。一般用在我们对数据有先验知识,或者之前做过一些拟合的时候,如果没有的话就不用管这个参数了。
5)loss: 即我们GBDT算法中的损失函数。分类模型和回归模型的损失函数是不一样的。
对于分类模型,有对数似然损失函数"deviance"和指数损失函数"exponential"两者输入选择。默认是对数似然损失函数"deviance"。在原理篇中对这些分类损失函数有详细的介绍。一般来说,推荐使用默认的"deviance"。它对二元分离和多元分类各自都有比较好的优化。而指数损失函数等于把我们带到了Adaboost算法。
对于回归模型,有均方差"ls", 绝对损失"lad", Huber损失"huber"和分位数损失“quantile”。默认是均方差"ls"。一般来说,如果数据的噪音点不多,用默认的均方差"ls"比较好。如果是噪音点较多,则推荐用抗噪音的损失函数"huber"。而如果我们需要对训练集进行分段预测的时候,则采用“quantile”。
6)alpha:这个参数只有GradientBoostingRegressor有,当我们使用Huber损失"huber"和分位数损失“quantile”时,需要指定分位数的值。默认是0.9,如果噪音点较多,可以适当降低这个分位数的值。
2. 弱学习器参数
这里我们再对GBDT的类库弱学习器的重要参数做一个总结。由于GBDT使用了CART回归决策树,因此它的参数基本来源于决策树类,也就是说,和DecisionTreeClassifier和DecisionTreeRegressor的参数基本类似。如果你已经很熟悉决策树算法的调参,那么这一节基本可以跳过。不熟悉的朋友可以继续看下去。
1) 划分时考虑的最大特征数max_features: 可以使用很多种类型的值,默认是"None",意味着划分时考虑所有的特征数;如果是"log2"意味着划分时最多考虑log2Nlog2N个特征;如果是"sqrt"或者"auto"意味着划分时最多考虑N−−√N个特征。如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑(百分比xN)取整后的特征数。其中N为样本总特征数。一般来说,如果样本特征数不多,比如小于50,我们用默认的"None"就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
2) 决策树最大深度max_depth: 默认可以不输入,如果不输入的话,默认值是3。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。
3) 内部节点再划分所需最小样本数min_samples_split: 这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
4) 叶子节点最少样本数min_samples_leaf: 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
5)叶子节点最小的样本权重和min_weight_fraction_leaf:这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。 默认是0,就是不考虑权重问题。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
6) 最大叶子节点数max_leaf_nodes: 通过限制最大叶子节点数,可以防止过拟合,默认是"None”,即不限制最大的叶子节点数。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。
7) 节点划分最小不纯度min_impurity_split: 这个值限制了决策树的增长,如果某节点的不纯度(基于基尼系数,均方差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。一般不推荐改动默认值1e-7。
4. 链接
机器学习-随机森林-调参的案例
https://www.pianshen.com/article/9427349161/