《李航统计学习方法》与刘建平博客学习笔记——监督学习部分
前几日看完了李航的《统计学习方法》这本书,按照个人的学习习惯,第一遍往往看的比较快速,大概了解本书的内容,和一些知识点的内容概要,对于知识点的详细细节,比如公式手动推导和相关代码等等,留给第二遍。由于有第一遍的经验,第二遍学起来不至于毫无头绪,也能大概分清楚学习的重点。
这第二遍打算结合刘建平Pinard - 博客园,并做一些笔记,记录一下。笔记内容主要是一些知识点的进一步简化总结,节省自己后续翻看复习的时间,干这一行要学的东西很多,并且学的东西,只要一段时间不用就会忘得干干净净,用到时需要复习是在所难免的。
其中公式的推导过程省略,具体的推导过程参考的是《统计学习方法》哔哩哔哩_bilibili,视频中有详细的公式推导,也有例子,讲的比较适合初学者。
以及b站的另一个小up老弓的学习日记的个人空间_哔哩哔哩_bilibili,内容虽然比较少,但是讲的比较通俗易懂。
1. 机器学习基础概论
《统计学习方法》第一章主要介绍了统计学习和监督学习概论相关的知识,对学习种类、正则化、过拟合、监督学习与无监督学习等等进行了简要介绍。这些概要类且属于概念性的知识记录下来意义不大,所以本节记录的主要内容还是刘建平博客的相关内容,将前四个小结集合在一起,并对内容进行简要概括,便于后续复习。
1.1 梯度下降
1.1.1 梯度下降介绍与相关概念
1.1.1.1 梯度与梯度下降运用
梯度是一个数学的概念,在高等数学中偏导数那个章节重点介绍了,概括来说就是对一个多元函数的每个变量进行求偏导,然后将偏导数结合成一个向量,这个向量就是梯度向量。结合高中的导数知识,就知道这个偏导数结合成的梯度向量,就表示了当前点的函数变化方向,顺着这个方向,就可以找到最大值或者最小值。
需要注意的是,顺着梯度的方向走下去,找到的不一定是最大(小)值,有可能只是一个区域的最小值,当然如果函数是凹(凸)函数,那找到的就是最大(小)值,也就是找到了全局最优解。
梯度下降算法在机器学习和深度学习中常常和损失函数一起出现,用于求解函数的参数。所谓的损失函数概括来说就是,通过学习得到了一个解决问题的函数,但是这个函数和真实的情况肯定存在一定的误差,这个误差就可以理解为损失。此时主要的解决思路就是让这个损失降到最小,小到可以满足要求,此种满足要求的状态既可以理解为函数收敛了。那么梯度下降算法就可以用在这里,不断地迭代,求解出损失函数的最小值。(当然梯度下降算法不仅仅用于此)
1.1.1.2 梯度下降相关概念
-
步长(Learning rate):步长决定了在梯度下降迭代的过程中,每一步沿梯度负方向前进的长度。结合类似于描点划线,点与点之间的距离就是步长,步长越小,曲线越平滑,越接近于实际,但是计算量也会更大(过小容易过拟合)。
-
特征(feature):指的是样本中输入部分。即在训练时,每个样本的特征输入,如果是监督学习,就是人工贴的每个样本的标签。
-
假设函数(hypothesis function):在监督学习中,为了拟合输入样本,而使用的假设函数 \(h_{\theta}(x)\)。这个假设函数与实际的yi输出进行作差,所得就是顺势函数,这个做差的方式很多,即衍生出了不同的损失函数。
-
损失函数(loss function):为了评估模型拟合的好坏,通常用损失函数来度量拟合的程度。损失函数极小化,意味着拟合程度最好,对应的模型参数即为最优参数。在线性回归中,损失函数通常为样本输出和假设函数的差取平方。比如对于m个样本\((x_i,y_i)(i=1,2,...m)\),采用线性回归,损失函数为:
\[J(\theta_0, \theta_1) = \sum\limits_{i=1}^{m}(h_\theta(x_i) - y_i)^2 \]其中xi表示第i个样本特征,yi表示第i个样本对应的输出,\(h_{\theta}(x_i)\)为假设函数。
1.1.2 梯度下降算法详解
详细的公式见刘建平博客,以下为个人理解与总结。
1.1.2.1 代数法
-
确定模型的假设函数与损失函数
以线性回归为例,假设函数为\(h_\theta(x_1, x_2, ...x_n) = \theta_0 + \theta_{1}x_1 + ... + \theta_{n}x_{n}\),其中θi为参数。这很好理解,xi为输入特征,这是计算前就注定的值,某种角度来说,它不是未知数,这和数学不同。之所以θi为参数,是因为学习的目的就是搞清楚这些特征(xi)的权重如何设置,才能使得到的函数更好的预测。进一步假设x0=1,那么可以得到损失函数为:
\[J(\theta_0, \theta_1..., \theta_n) = \frac{1}{2m}\sum\limits_{j=1}^{m}(h_\theta(x_0^{(j)}, x_1^{(j)}, ...x_n^{(j)}) - y_j)^2 \] -
算法相关参数初始化:主要是初始化\(\theta_0, \theta_1..., \theta_n\),算法终止距离ε,以及步长α。θ一般设置为0,一开始给各个特征的权重都设置为一样。偏导得到的梯度作为方向,步长即是算法下降的速度。终止距离即人为设置的满意阈值,低于这个阈值,就认为收敛了。
-
算法过程:
- 先对损失函数进行偏导计算,得到梯度。然后乘以步长得到当前下降的距离b。
- 看对于所有的θi,b都小于ε。如果都小于,说明后续的下降幅度已经很小,当前得到的点,已经很接近真实值了,停止计算。
- 如果不小于,则要继续计算,继续计算就要更新参数θ。更新方式为原先的θ减去b。(更新方式不同,也会有不同的影响,后续说明)
1.1.2.2 矩阵法
即将上述代数公式用矩阵的形式的表示,其实就是高数中线性代数的逆用,将代数算法,转化为矩阵算法。多出的知识是本科阶段没学过的矩阵求导。
1.1.2.3 算法优化
主要有以下几种优化方式:
- 算法的步长选择:即多取几个步长试试,看损失函数是否在变小,变小则尝试成功。步长太大不好,太小也不好,步长太大,会导致迭代过快,甚至有可能错过最优解。步长太小,迭代速度太慢,很长时间算法都不能结束。
- 算法参数的初始值选择:之前说道,梯度下降求出的不一定是全局最值,而是区域极值。所以初始点的选择就显得很重要,因为所有极值中的最小值就是全局最值。选择的方式也是多尝试,选择使损失函数最小的初值。
- 归一化:由于样本不同特征的取值范围不一样,可能导致迭代很慢,为了减少特征取值的影响,可以对特征数据归一化。
1.1.3 梯度下降算法种类
分类的依据,就是每次进行计算的样本个数
- 批量梯度下降法(Batch Gradient Descent):即使用所有的样本来进行更新。这也是最常用的。
- 随机梯度下降法(Stochastic Gradient Descent):和BGD是两个极端,即在m个样本中,随机挑选一个进行计算更新。
- 小批量梯度下降法(Mini-batch Gradient Descent):由于上述两种过于极端,各有优缺点,BGD准确度高但是训练慢,SGD训练快但不准确,所以折中就得到MDG。即选择的样本不多不少。
1.1.4 梯度下降法和其他无约束优化算法的比较
在机器学习中的无约束优化算法,除了梯度下降以外,还有最小二乘法,牛顿法和拟牛顿法。
梯度下降法和最小二乘法相比,梯度下降法需要选择步长,而最小二乘法不需要。梯度下降法是迭代求解,最小二乘法是计算解析解。如果样本量不算很大,且存在解析解,最小二乘法比起梯度下降法要有优势,计算速度很快。但是如果样本量很大,用最小二乘法由于需要求一个超级大的逆矩阵,这时就很难或者很慢才能求解解析解了,使用迭代的梯度下降法比较有优势。
梯度下降法和牛顿法/拟牛顿法相比,两者都是迭代求解,不过梯度下降法是梯度求解,而牛顿法/拟牛顿法是用二阶的海森矩阵的逆矩阵或伪逆矩阵求解。相对而言,使用牛顿法/拟牛顿法收敛更快。但是每次迭代的时间比梯度下降法长。
所以对于这几个优化算法的底层原理还是要有一定的了解,对于不同的项目选择不同的优化算法。这几种算法在《统计学习方法》中都有详细介绍,都比较简单,很好理解。
1.1.5 最小二乘法
承接上个小节,简单整理最小二乘法。之前详细了解了最小二乘法的发现和推导过程,感叹形式这么简单的公式发现的过程尽然如此复杂。
梯度下降算法的原理概括就是先求差,看差值满不满足,不满足就迭代更新参数,再求差,知道满足要求为止。而最小二乘法和梯度下降算法要解决的问题一样,损失函数也一样,区别是不需要迭代,而是在于对损失函数求偏导后,让导函数等于0,得到若干个有关θ的多元方程组。然后各个θ的求值,就转化为了方程组的求值。
然后将代数转化为矩阵进行计算,这就变成了线性代数中的齐次线性方程组的求解,所以才会需要解逆矩阵,当逆矩阵的维数太大时,计算显然会很耗时。
1.2 精确率与召回率,RoC曲线与PR曲线
上来就是几个拗口的概念:
- True Positives,TP:预测为正样本,实际也为正样本的特征数
- False Positives,FP:预测为正样本,实际为负样本的特征数
- True Negatives,TN:预测为负样本,实际也为负样本的特征数
- False Negatives,FN:预测为负样本,实际为正样本的特征数
其实记忆也很简单,记住英文单词的意思就行。并且这是个概念不是最重要的,主要是为下面几个概念服务的。
1.2.1 精确率(precision),召回率(Recall)
-
精确率:计算公式如下,可以理解为预测为正类的样本中,有多少是被分对了的。
\[P = \frac{TP}{TP + FP } \] -
召回率:计算公式如下,可以理解为在实际正类中,有多少正类被发现了。
\[R = \frac{TP}{TP + FN } \]这两个指标共同决定模型的好坏,因此结合得到综合指标F1,公式如下:
\[\frac{2}{F_1} = \frac{1}{P} + \frac{1}{R} \]结合上述两个指标的理解,可以看到,精确率和召回率的侧重点不同。一个侧重预测值,一个侧重实际值。根据不同的问题,对于两者就有不同的侧重,所以引入β,即给两个指标加上权重,得到新的综合指标:
\[F_\beta = \frac{(1+\beta^2)*P*R}{\beta^2*P + R} \]
1.2.2 RoC曲线和PR曲线
再引入两个指标:
-
灵敏度(true positive rate ,TPR):其实就是召回率,公式和意义都一样。
\[TPR = \frac{TP}{TP + FN } \] -
1-特异度(false positive rate, FPR):即实际负例中,错误得识别为正例的负例比例。公式如下:
\[FPR = \frac{FP}{FP + TN } \]
以上述两个指标为坐标值画图,就可以得到两个曲线:
- RoC曲线:以TPR为y轴,以FPR为x轴。意义就是TPR越高,FPR越小,我们模型和算法就越高效。因为正类判断正确的多,错误误判为正类的少。对应于曲线就是越靠近左边越好,也即是曲线下的面积越大越好。
- PR曲线:以精确率为y轴,以召回率为x轴,就得到了PR曲线(precision and recall)。精确率越高,召回率越高,模型和算法就越高效。也就是画出来的PR曲线越靠近右上越好。

所以,在训练测试完成之后,根据数据绘制出两个曲线,就可以得出模型的优劣。
2. 线性回归
2.1 基本原理小结
回归问题和分类问题是机器学习的两个大类,对于m个样本,每个样本对应于n维特征和一个结果输出,对于新的一个待预测样本,对应的输出应该是多少,如果输出是连续的则是回归,否则就是分类。
2.1.1 模型函数与损失函数
有上述小结的知识,可以很简单的得到线性回归的模型和损失函数,如下:
对于模型的求解方法,最常用的就是梯度下降法和最小二乘法,上述章节有详细说明。
2.2 线性回归的推广
2.2.1 多项式回归
所谓多项式回归,就是模型中涉及了x的多次,则变为了多项式回归。具体的计算方法就是通过换元法,使其转换成线性回归的形式。
其实很好理解,也就是把多个特征融合成一个特征,这么做回新增特征,但实际上所有的特征都是由原始的特征组成的。
2.2.2 广义线性回归
多项式回归属于对特征进行了扩展,广义线性回归就属于对输出y进行扩展。即原本y和x不成线性关系,但是对y进行基本转换,比如取对数后,与x成线性了。
这也可以用线性回归的方法解决,也很好理解,将y取反对数就行了。
2.3 线性回归的正则化
为了防止模型的过拟合,需要加入正则化项。一般有L1正则化和L2正则化。首先说一下L1和L2的区别,两者都是p范数的一种:
2.3.1 p范数:
如果
那么p范数就是
- L1范数,即p = 1
- L2范数,即p = 2
2.3.2 Lasso回归(L1正则化)
即正则化项添加的是L1范数(||θ||1),模型为:
Lasso回归可以将一些特征的系数变小,从而增强模型的泛化能力。求解办法一般为坐标轴下降法和最小角回归法。
但是Lasso回归有一个很大的问题,由于L1范数用的是绝对值之和,导致损失函数有不可导的点(几何上很好理解)。也就是说,最小二乘法,梯度下降法,牛顿法与拟牛顿法对它统统失效了。
所以,采用了两种全新的求极值解法,坐标轴下降法(coordinate descent)和最小角回归法( Least Angle Regression, LARS)。
2.3.2.1 坐标轴下降法
坐标轴下降和梯度下降存在共性,都是迭代法,通过启发式的方式一步步迭代求解函数的最小值。但是不同的是迭代的方向不同。
坐标轴下降也就是随着坐标轴的方向下降,遵循的数学原理:一个可微的凸函数J(θ), 其中θ是nx1的向量,即有n个维度。如果在某一点θ,使得J(θ)在每一个坐标轴上都是最小值,那么J(θi)就是一个全局的最小值。
于是的优化目标就是在θ的n个坐标轴上(或者说向量的方向上)对损失函数做迭代的下降,当所有的坐标轴上都达到收敛时,我们的损失函数最小,此时的θ即为要求的结果。
基于几何的角度,这个方法很好理解。
2.3.2.1 最小角回归法
再介绍这一章节时,刘在博客中介绍了两个备用算法,也写了详细的公式,但是原理其实也很简单,博客中的两个图像就能很好的说明这两个算法。
-
前向选择算法

图中所示的是只有两个特征的例子,首先在X1和X2中找到更接近Y的特征,然后Y向X1的方向投影,较长的虚线就是差值。然后再讲差值在X2上投影,得到较短的虚线,由于斜边永远长于直角边,所以差值只会越来越小,利用这个原理,一步步的迭代,直到所有的特征用完,总会找到差值最小,最接近于Y的模拟值。
此算法有点在于计算快,效率很高,但是缺点在于每次都是投影,误差很大,算法很粗糙。
-
前向梯度算法

图中所给的依然是两个特征的例子,其中ε是一个很小的常量,当ε很小时,可以很好的逼近Y。
首先看Y相对于X1和X2,哪个残差更小(向量差),选择更小的方向,向着相同的方向前进一步,再次计算差值,一次次的进一步,一次次的逼近Y。
相比于第一个方法,显然更加精确,但是问题就在于计算的复杂度也更高,而最小角度回归法即是这两种方法的折中。
-
最小角回归法

图中所给的依然是两个特征的例子,和前向梯度算法不同的是,这次不是只走一小步,而是一直沿着残差更小的方向走,直到X1方向上的剩余部分和X2的模值一样就行,此时下一步的进行方向就是X1和X2的角平分线方向,一直走,直到残差足够小的时候停止。
如果是多维特征的情况,则沿着平分线的方向走,知道第三个特征对应的残差和X1X2一样时,则也加入到评测残差的成员中。
最小角回归法是一个适用于高维数据的回归算法,其主要的优点有:
- 特别适合于特征维度n 远高于样本数m的情况。
- 算法的最坏计算复杂度和最小二乘法类似,但是其计算速度几乎和前向选择算法一样
- 可以产生分段线性结果的完整路径,这在模型的交叉验证中极为有用
主要的缺点是:
由于LARS的迭代方向是根据目标的残差而定,所以该算法对样本的噪声极为敏感。
Lasso回归是在ridge回归的基础上发展起来的,如果模型的特征非常多,需要压缩,那么Lasso回归是很好的选择。一般的情况下,普通的线性回归模型就够了。
2.3.3 Ridge回归(L2正则化)
即正则化项添加的是L2范数(||θ||2),模型为:
Ridge回归在不抛弃任何一个特征的情况下,缩小了回归系数,使得模型相对而言比较的稳定,但和Lasso回归比,这会使得模型的特征留的特别多,模型解释性差。计算方法一般采用最小二乘法,即对模型求导得到:
然后求解θ,得到结果:
注:
以上仅为理论知识,实际上的训练案例还需要注意很多,比如正则化项前的系数α的大小,对于最后训练结果的影响。具体还要看刘博客中的例子,但是主要的重点还是后续的深度学习,机器学习阶段的案例,感觉没有过于深入的实现。
刘的博客中列举了scikit-learn 线性回归算法库小结 ,后续涉及可以当工具文档看看。
3. 逻辑回归
第一次看到逻辑回归这个词的时候,总以为他是回归算法的一种,了解了一下发现,他其实是一种分类算法,可以做二分类也可以做多分类。之所以名字中带有回归,是因为原理中含有回归模型的影子。
3.1 基本原理
上述提到线性回归的时候有过说明,当模型的输出Y为连续的时候,则是回归问题,否则是分类问题,那么回归问题如何向分类问题转化,就引出了一个非常基本的结论,当x处于某一个实数段则给一个定值,下一个实数段给另外一个定值,则就将Y离散化了,相当于又套了一层函数g(Y),实现了线性到离散的转化。
3.2 二元逻辑回归
3.2.1 模型由来
上述的的g(Y)函数取一个非常著名的函数,即可得到二元逻辑回归的模型,即sigmod函数:
显然,当z趋于正无穷时,值为1,趋于负无穷时,值为0,那么以中间点0.5划分,则很简单明了的实现了0,1的分布。此外,这个函数的导函数也很好计算:
如果令z = xθ ,则得到了二元逻辑回归的一般形式:
3.2.2 损失函数
由于分类问题对应的模型输出是离散的,则回归问题中的模型推导方法都无法使用。
对于分类问题的损失函数推导,则采用了最大似然函数的方法。由于先前考研的时光,让我对于概率统计这门课程还是比较熟悉的,最大似然函数的计算方法基本烂熟于心了。似然函数得解法,对于一些特殊的函数计算需要一点技巧,其余基本差不多。关键还是在于待计算的这个函数怎么构建。
对于二元逻辑回归,可以根据如下推导过程,得到损失函数。
上述结合而得的公式即是待计算的函数。
对于多元的函数,损失函数即为:
3.2.3 损失函数的优化与正则化
对于损失函数的优化,即为最大似然函数求解,概率统计中提供了一个方法,即是对参数求偏导,然后用最大似然结果作为输出。当然也可以用梯度下降、坐标轴下降和等牛顿法。这些方法,前序章节中有提及,并且知道大概原理就行,一般无需自己手动写优化算法,一些机器学习和深度学习的库中都集成了这些优化算法,计算时,只是调用一个函数的事。
逻辑回归的正则化和线性回归一样,分为L1,L2的正则化,公式如下:
3.2.4 多元逻辑回归
对于多元转化为二元,其实也很好理解,即选择多元中的一元或多元作为1,剩下的作为0,即可得到二分类。
推导过程刘博客中有详细解释,精髓就是用到一个式子:
对比以下多元和二元的结果如下:
二元:
多元:
注:
刘博客中列举了逻辑回归相关的库,scikit-learn 逻辑回归类库使用小结,后期有所涉及可以当工具书看。
4. 感知机
4.1 原理
感知机这玩意儿是最简单的分类模型,他的分类原理就是用一个超平面,将空间中的元素分为两个部分,即完成了分类。拿二维平面举例,就是用一个直线将平面分割为两部分,显然以这个直线列一个方程,则在这条直线的上方的点代入方程则大于0,否则小于0,也就完成了分类。
如果这条直线无法找到,那就是线性不可分的分类集合,所以感知机的适用场景非常的受限制。并且如果是线性可分的,这条直线往往不是唯一的,所以感知机的解也不是唯一的,这和初始值的选择有很大关系。
感知机现在已经基本不用于实践,但是是很多算法比如向量机和深度学习神经网络的基础,可以了解一下。
4.2 模型与损失函数以及优化算法
- 模型函数
-
损失函数
假设判断为1的为分类正确,即yθ∙x > 0,则另一方则是分类错误,感知机的损失函数就是所有误分类的样本到超平面的距离之和:
\[- \sum\limits_{x_i \in M}y^{(i)}\theta \bullet x^{(i)}\big / ||\theta||_2 \]研究可以发现,分子和分母都含有θ,当分子的θ扩大N倍时,分母的L2范数也会扩大N倍。也就是说,分子和分母有固定的倍数关系。那么可以固定分子或者分母为1,然后求另一个即分子自己或者分母的倒数的最小化作为损失函数,这样可以简化损失函数。在感知机模型中,采用的是保留分子,即最终感知机模型的损失函数简化为:
\[J(\theta) = - \sum\limits_{x_i \in M}y^{(i)}\theta \bullet x^{(i)} \]
-
优化算法
感知机的损失函数已经获得,对于此种损失函数可以使用梯度下降发或者牛顿法,但是由于只是误分类点参与了函数构建,所以只能使用随机梯度下降或者小批量梯度下降
由于采取的是随机梯度下降,则每次参与迭代的就只有一个点,所以梯度下降函数为:
\[\theta = \theta + \alpha y^{(i)}x^{(i)} \]即每次取一个误分类点,迭代得到新的θ,然后看训练集里面是否还有误分类点,有则继续迭代,无则得到结果。
4.3 感知机模型的算法对偶形式
首先按照上述梯度下降函数进一步扩展得到下式,其中j为被多次误分类而更新的样本j。其中由于α是定值,所以可以让αm = β,进一步花间公式。
上述公式每次迭代都需要计算一次xy的内积,所以可以在迭代前直接将所有元素的内积计算好,迭代时直接代入,这样比每次循环的时候再计算更省时间。
5. 决策树
决策树算法在机器学习中算是很经典的一个算法系列了。它既可以作为分类算法,也可以作为回归算法,同时也特别适合集成学习比如随机森林。并且算法很形象,理解起来也比较简单。
在写代码时,经常会用到条件判断语句,条件判断中还会嵌套条件判断语句,而决策树算法的核心,就是判断哪一个条件作为条件进行判断,才会更好更快速的解决问题。
5.1 ID3
ID3生成决策树,主要是引入了信息论中的熵的概念,这在考研复试时的通信原理中,已经有了充分的了解。熵度量了事物的不确定性,越不确定的事物,它的熵就越大,即越不确定,所含的信息量越多。
进而引出联合分布和条件分布:
那么I(X,Y) = H(X) - H(X|Y),就度量了X在知道Y以后不确定性减少程度,在ID3中称为信息增益。依据这个信息增益进行构建,信息增益大,则越适合用来分类。
以下的图像更加形象的体现了这个问题:

-
ID3具体计算步骤
刘的博客以及李航的书上都写了一大段文字述说这个算法计算步骤,也有比较多的概念符号,但其实原理十分的简单,一大段的文字描述不如一个例子来的直接易懂,李航的书上的P75的例子看懂就行,大概步骤就是先算出总的信息熵,然后分别以各个可以作为分类的特征为条件算条件信息熵,然后用总信息熵减去条件信息熵得到信息增益,比较各个信息增益哪个大,大的那个更适合作为分类。
-
ID3的缺点
a) ID3没有考虑连续特征,比如长度,密度都是连续值,无法在ID3运用。这大大限制了ID3的用途。
b) ID3采用信息增益大的特征优先建立决策树的节点。很快就被人发现,在相同条件下,取值比较多的特征比取值少的特征信息增益大。比如一个变量有 2个值,各为1/2,另一个变量为3个值,各为1/3,其实他们都是完全不确定的变量,但是取3个值的比取2个值的信息增益大。如果校正这个问题呢?
c) ID3算法对于缺失值的情况没有做考虑
d) 没有考虑过拟合的问题
5.2 C4.5
针对ID3的四个问题,经过进一步的改进,得到了C4.5算法,这个算法也被称为20世纪十大算法之首。针对这四个问题,下面这个链接详细举例说明了C4.5如何从ID3进化得来:决策树之C4.5算法 - 知乎 (zhihu.com)
-
连续特征的处理
对于连续的特征采取了连续特征的特征离散化,给了这么个名字,其实就是对于m个连续的特征,取相邻两个特征的中间值进行信息增益的计算,信息增益最大的作为分类点。这与离散属性不同的是,如果当前节点为连续属性,则该属性后面还可以参与子节点的产生选择过程。
-
信息增益作为标准容易偏向于取值较多的特征的问题
对于这个问题就选择放弃使用信息增益作为标准,而是选择信息增益比,即是信息增益和特征熵的比值
\[I_R(D,A) = \frac{I(A,D)}{H_A(D)} \]\[D为样本特征输出的集合,A为样本特征,对应的特征熵为:H_A(D) = -\sum\limits_{i=1}^{n}\frac{|D_i|}{|D|}log_2\frac{|D_i|}{|D|} \]其中n为特征A的类别数,Di为特征A的第i个取值对应的样本个数。|D|为样本个数。
由于特征数多的特征,对应的特征熵HA(D)也越大,这样一作除法,就解决了用信息增益总是偏向于特征数更多的特征的问题。
-
缺失值的处理
对于此问题的处理,刘博客中以及李航的书中只做了文字的说明,并没有例子。问题的处理分两步走,由于文字的描述有几个名词类似,导致光看文字理解起来不太方便,所以这个问题的处理还是看西瓜书比较好,西瓜书P86,对于此问题有很好的例子说明。
主要分为以下两步:
-
一是在样本某些特征缺失的情况下选择划分的属性
即在计算某个属性的信息增益时,直接忽视该属性缺失的样本,用剩下的样本进行计算。计算得到结果后,乘以一个系数,即不缺失该属性的样本在总体样本中的占比。按照此方法计算其他的属性,然后比较大小,选择信息增益或者信息增益比最大的那个作为分类属性。
-
二是选定了划分属性,对于在该属性上缺失特征的样本的处理。
确定了划分属性之后,需要将该属性下的各类特征进行分支,比如属性A有三种特征A1、A2、A3,其中A1有5个样本,A2有3个样本,A3有4个样本,还有一个样本是缺失该属性的,对于这个缺失该属性的样本,则直接在A1、A2、A3每一个特征下都放一个,但是要乘以权重,A1下乘以5/13,A2下乘以3/13,A3下乘以4/13。
-
-
过拟合问题
在Cart中会提及树的剪枝,C4.5也是用的正则化的剪枝。
-
C4.5的缺点
-
由于决策树算法非常容易过拟合,因此对于生成的决策树必须要进行剪枝。剪枝的算法有非常多,C4.5的剪枝方法有优化的空间。
-
C4.5生成的是多叉树,即一个父节点可以有多个节点。很多时候,在计算机中二叉树模型会比多叉树运算效率高。如果采用二叉树,可以提高效率。
-
C4.5只能用于分类,如果能将决策树用于回归的话可以扩大它的使用范围。
-
C4.5由于使用了熵模型,里面有大量的耗时的对数运算,如果是连续值还有大量的排序运算。如果能够加以模型简化可以减少运算强度但又不牺牲太多 准确性的话,那就更好了。
上述的缺点进一步的优化,便引出了CART算法。
-
5.3 CART
-
最优特征选择方法
简而言之,cart的最优特征选择方法,不是用的信息熵,而是用的基尼系数,基尼系数的计算方法如下:
\[在分类问题中,假设有K个类别,第k个类别的概率为p_k:Gini(p) = \sum\limits_{k=1}^{K}p_k(1-p_k) = 1- \sum\limits_{k=1}^{K}p_k^2 \]\[对于个给定的样本D,假设有K个类别, 第k个类别的数量为C_k:Gini(D) = 1-\sum\limits_{k=1}^{K}(\frac{|C_k|}{|D|})^2 \]\[如果根据特征A的某个值a,把D分成D1和D2两部分,则在特征A的条件下,D的基尼系数表达式为:Gini(D,A) = \frac{|D_1|}{|D|}Gini(D_1) + \frac{|D_2|}{|D|}Gini(D_2) \]选用基尼系数小的那个作为划分属性点,基尼系数代表的是模型的不纯度,基尼系数越小,模型越纯。
这样计算有以下几个好处,解决了c4.5的几个缺点:
-
由对数计算转换为了平方计算,提升了计算速度
-
由属性的多分类,转化为了二分类,类似清晰、稍模糊、模糊三类可以分为清晰和不清晰两类。计算机计算二叉树快很多,这也提升了计算速度
-
此外,运用基尼系数计算和使用信息增益计算差别不大,只有在45°角的时候,有些差异,所以可以很好的替代。

-
-
连续特征和离散特征处理的改进
对于连续特征的处理和c4.5类似,只不过挑选是根据基尼系数来选的,而不是信息增益熵,这也很好理解。
对于离散特征值的处理,用的是上述的不停的二叉分类,得到的是一颗二叉树
对于缺失值的处理和c4.5类似
-
CAET分类树与回归树的建立
分类树的建立和c4.5类似,只不过只做二叉分类,并且判断的阈值由信息增益比换成了基尼系数。
主要看一下回归树,因为c4.5是不做回归任务的。
首先,回归树与分类树,两者的区别在于样本输出,如果样本输出是离散值,那么这是一颗分类树。如果果样本输出是连续值,那么那么这是一颗回归树。
除了概念的不同,CART回归树和CART分类树的建立和预测的区别主要有下面两点:
-
连续值的处理方法不同
分类采用的是基尼系数的大小,回归用的是和方差的度量方式。即,对分为两类的数据集D1、D2,求出使D1和D2各自集合的均方差最小,同时D1和D2的均方差之和最小所对应的特征和特征值划分点,公式如下(其中,c1为D1数据集的样本输出均值,c2为D2数据集的样本输出均值):
\[\underbrace{min}_{A,s}\Bigg[\underbrace{min}_{c_1}\sum\limits_{x_i \in D_1(A,s)}(y_i - c_1)^2 + \underbrace{min}_{c_2}\sum\limits_{x_i \in D_2(A,s)}(y_i - c_2)^2\Bigg] \]
-
-
决策树建立后做预测的方式不同。
对于分类树,选择的是概率最大的那个叶子节点作为分类,而回归树输出的不是类别,它采用的是用最终叶子的均值或者中位数来预测输出结果。
-
剪枝
ID3和C4.5有一个最明显的问题就是,他们只负责生成树,这就导致没有类似线性回归的正则化去拟合的功能。去拟合的一个形象的解释就是,避免模型的输出太多导致泛化能力太差,对应到树这种数据结构,就是树不能太复杂,应该尽量使树更简单,且分类功能不减,这就涉及到了剪枝。
CART采用的办法是后剪枝法,即先生成决策树,然后产生所有可能的剪枝后的CART树,然后使用交叉验证来检验各种剪枝的效果,选择泛化能力最好的剪枝策略。
对于去拟合,肯定就需要一个损失函数,cart树剪枝时,对于任意的一刻子树T的损失函数如下:
\[C_{\alpha}(T_t) = C(T_t) + \alpha |T_t| \]其中,α为正则化参数,这和线性回归的正则化一样。C(Tt)为训练数据的预测误差,α度量。|Tt|是子树T的叶子节点的数量。显然α越大,剪枝的越厉害,区域无穷时,则根节点对应的单节点就是最优解。
上述的损失函数对应的是当前T子树没有进行剪枝时的,如果将T子树减掉,只留根节点,则对应的损失函数为:
\[C_{\alpha}(T) = C(T) + \alpha \]显然,当α很小时,|Tt|占主导,Cα(Tt) < Cα(T),当α很大时,α占主导Cα(Tt) > Cα(T),所以可以肯定的是,在这其间肯定存在一个α,使得Cα(Tt) = Cα(T),计算公式为:
\[\alpha = \frac{C(T)-C(T_t)}{|T_t|-1} \]既然剪枝之后损失函数一样,那么肯定选择剪掉枝条,使得树更加简便。
进一步对每一个子树都做一次计算,得到很多个α,然后对于每一个α做交叉验证,选择效果最好的那个α作为剪枝系数,得到对应的树。
刘博客和一些机器学习相关的书上,都详细的cart树的建立过程的文字描述,并且还有例子,scikit-learn中的决策树使用的就是cart决策树,详细的算法过程和实现代码,感觉除非面试会问,没有必要深挖,重要的是要会用相关的包,以及了解该包的输入和输出。
-
CART的缺点
1)无论是ID3, C4.5还是CART,在做特征选择的时候都是选择最优的一个特征来做分类决策,但是大多数,分类决策不应该是由某一个特征决定的,而是应该由一组特征决定的。这样决策得到的决策树更加准确。这个决策树叫做多变量决策树。在选择最优特征的时候,多变量决策树不是选择某一个最优特征,而是选择最优的一个特征线性组合来做决策。这个算法的代表是OC1。
2)如果样本发生一点点的改动,就会导致树结构的剧烈改变。这个可以通过集成学习里面的随机森林之类的方法解决。
5.4 决策树的优缺点
决策树算法的优点:
- 简单直观,生成的决策树很直观。
- 基本不需要预处理,不需要提前归一化,处理缺失值。
- 使用决策树预测的代价是O(log2m)。 m为样本数。
- 既可以处理离散值也可以处理连续值。很多算法只是专注于离散值或者连续值。
- 可以处理多维度输出的分类问题。
- 相比于神经网络之类的黑盒分类模型,决策树在逻辑上可以得到很好的解释
- 可以交叉验证的剪枝来选择模型,从而提高泛化能力。
- 对于异常点的容错能力好,健壮性高。
决策树算法的缺点:
- 决策树算法非常容易过拟合,导致泛化能力不强。可以通过设置节点最少样本数量和限制决策树深度来改进。
- 决策树会因为样本发生一点点的改动,就会导致树结构的剧烈改变。这个可以通过集成学习之类的方法解决。
- 寻找最优的决策树是一个NP难的问题,一般是通过启发式方法,容易陷入局部最优。可以通过集成学习之类的方法来改善。
- 有些比较复杂的关系,决策树很难学习,比如异或。这个就没有办法了,一般这种关系可以换神经网络分类方法来解决。
- 如果某些特征的样本比例过大,生成决策树容易偏向于这些特征。这个可以通过调节样本权重来改善。
6. K近邻
K近邻算法,顾名思义,就是物以类聚人以群分,对于你的分类,看和你最近的那几个邻居是什么性质就可以将你分类了。K近邻算法多用在图像分割的场景。
该算法既可以做分类,也可以做回归,区别在于输出的方式不同。分类时,一般是选择多数表决法,即训练集里和预测的样本特征最近的K个样本,预测为里面有最多类别数的类别。做回归时,一般是选择平均法,即最近的K个样本的样本输出的平均值作为回归预测值。
6.1 算法三要素
这三个最终的要素是k值的选取,距离度量的方式和分类决策规则。后续以分类距离,分类决策规则,一般固定选择多数表决法,所以注重前两个要素即可。
-
k值的选取
对于k值的选择,没有一个固定的经验,一般根据样本的分布,选择一个较小的值,可以通过交叉验证选择一个合适的k值。
选择较小的k值,就相当于用较小的领域中的训练实例进行预测,训练误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是泛化误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合
选择较大的k值,就相当于用较大领域中的训练实例进行预测,其优点是可以减少泛化误差,但缺点是训练误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单。
也就是k值得选择大了不行,小了也不行,大了不精确,小了训练慢,容易过拟合。这种情况其他的算法也有类似的变量,很好理解。
-
距离度量
一般采用的就是欧式距离,即:
\[D(x,y) = \sqrt{(x_1-y_1)^2 + (x_2-y_2)^2 + ... + (x_n-y_n)^2} = \sqrt{\sum\limits_{i=1}^{n}(x_i-y_i)^2} \]也有曼哈顿距离和闵可夫斯基距离,不太重要,了解即可。
\[曼哈顿距离:D(x,y) =|x_1-y_1| + |x_2-y_2| + ... + |x_n-y_n| =\sum\limits_{i=1}^{n}|x_i-y_i| \]\[闵可夫斯基距离:D(x,y) =\sqrt[p]{(|x_1-y_1|)^p + (|x_2-y_2|)^p + ... + (|x_n-y_n|)^p} =\sqrt[p]{\sum\limits_{i=1}^{n}(|x_i-y_i|)^p} \]
6.2 K近邻的实现
一种最直接的办法就是蛮力实现,即计算待预测样本和每一个训练集样本的距离,这样简单方便,但显然不适合多特征大样本的情况,所以主要有以下两种方法实现
6.2.1 KD树
KD树算法没有一开始就尝试对测试样本分类,而是先对训练集建模,建立的模型就是KD树,建好了模型再对测试集做预测。
所谓的KD树就是K个特征维度的树,注意这里的K和KNN中的K的意思不同。KNN中的K代表最近的K个样本,KD树中的K代表样本特征的维数。
即分三步走,建树、找邻居、预测
-
建树
书上和博客中做了一段文字的解释,其实没有必要去理解,这些机器学习的基本算法,主要看案例即可,看案例是最节省时间,也最好理解的,以下是具体逻辑图和例子:

比如有二维样本6个,{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},构建KD树的具体步骤为:
1)找到划分的特征。6个数据点在x,y维度上的数据方差分别为6.97,5.37,所以在x轴上方差更大,用第1维特征建树。
2)确定划分点(7,2)。根据x维上的值将数据排序,6个数据的中值为7,所以划分点的数据是(7,2)。这样,该节点的分割超平面就是通过(7,2)并垂直 于:划分点维度的直线x=7;
3)确定左子空间和右子空间。 分割超平面x=7将整个空间分为两部分:x<=7的部分为左子空间,包含3个节点={(2,3),(5,4),(4,7)};另一部分为右子空间,包含 2个节点={(9,6),(8,1)}。
4)用同样的办法划分左子树的节点{(2,3),(5,4),(4,7)}和右子树的节点{(9,6),(8,1)}。最终得到KD树。
最后得到的KD树如下:

其实就是找到所有特征中方法最大的,然后找到该维特征的中位数,然后小与中位数的放一边,其他的放另一边,迭代下去即可得到KD树。
-
找邻居
还是直接举例说明,一下是例子和结果
用3.1建立的KD树,来看对点(2,4.5)找最近邻的过程。
先进行二叉查找,先从(7,2)查找到(5,4)节点,在进行查找时是由y = 4为分割超平面的,由于查找点为y值为4.5,因此进入右子空间查找到(4,7),形成搜索路径<(7,2),(5,4),(4,7)>,但 (4,7)与目标查找点的距离为3.202,而(5,4)与查找点之间的距离为3.041,所以(5,4)为查询点的最近点; 以(2,4.5)为圆心,以3.041为半径作圆,如下图所示。可见该圆和y = 4超平面交割,所以需要进入(5,4)左子空间进行查找,也就是将(2,3)节点加入搜索路径中得<(7,2),(2,3)>;于是接着搜索至(2,3)叶子节点,(2,3)距离(2,4.5)比(5,4)要近,所以最近邻点更新为(2,3),最近距离更新为1.5;回溯查找至(5,4),直到最后回溯到根结点(7,2)的时候,以(2,4.5)为圆心1.5为半径作圆,并不和x = 7分割超平面交割,如下图所示。至此,搜索路径回溯完,返回最近邻点(2,3),最近距离1.5。
对应的图如下:

其实就是先按照中位数定区域,2 < 7,所以先找到左区域(5,4)。然后由于左区域是先根据y=4划分上下区域的,又4.5 > 4,所以找到上区域的(4,7)。又因为(4,7)比(5,4)离(2,4.5)更远,所以还是定到(5,4),然后依据圆心和半径画圆(上图中的圆)。发现圆和y = 4有交界,则继续找子树,找到(2,3),继续画圆,发现和(7,2)对应的x=7的超平面无交界,则结束,得到最近点。(找到(7,2)是因为(5,4)已经参与过画圆,在其内部画的小圆肯定没交点)
-
预测
按照上述找最近点的方式找到k个近邻点,这个k值事先确定好,每找到一个近邻点,则不放回,避免下一次的寻找。然后判断这找出的k个近邻点大多数属于哪一类,那这个预测点就分为哪一类。
显然KD树避免了很多次距离的计算,一些样本点,直接就被跳过计算距离了。
6.2.2 球树
球树的引入就是因为KD树存在缺点,缺点就是KD树的划分区域是按照矩形划分的,矩形最难处理的就是矩形的角,按照下图所示,只要黑点离星星点再远一点,画圆时,就会和左上角的矩形有交界,那么就要检查这个区域,但其实近邻点都是很近的点,这个区域的值,其实大多数时候,是不需要检查的。

为了避免矩形的角,那就选择磨平他的棱角,这就有了球树。
-
建立

-
先构建一个超球体,这个超球体是可以包含所有样本的最小球体。
-
从球中选择一个离球的中心最远的点,然后选择第二个点离第一个点最远,将球中所有的点分配到离这两个聚类中心最近的一个上,然后计算每个聚类 的中心,以及聚类能够包含它所有数据点所需的最小半径。这样得到了两个子超球体,和KD树里面的左右子树对应。
3)对于这两个子超球体,递归执行步骤2). 最终得到了一个球树。
上述过程已经很详细,即将大圆内部的样本按照距离最远来分类,而不是类似感知机那样的,画超平面分开。所以划分之后的区域是圆形,避免了矩形的棱角,造成的多余计算的问题。
-
-
找邻居
使用球树找出给定目标点的最近邻方法是首先自上而下贯穿整棵树找出包含目标点所在的叶子,并在这个球里找出与目标点最邻近的点,这将确定出目标点距离它的最近邻点的一个上限值,然后跟KD树查找一样,检查兄弟结点,如果目标点到兄弟结点中心的距离超过兄弟结点的半径与当前的上限值之和,那么兄弟结点里不可能存在一个更近的点;否则的话,必须进一步检查位于兄弟结点以下的子树。
检查完兄弟节点后,向父节点回溯,继续搜索最小邻近值。当回溯到根节点时,此时的最小邻近值就是最终的搜索结果。
上述是刘博客中的文字,简单总结就是,先确定包含当前目标的球(叶子节点),然后在球中找一个离目标最近的点,得到距离a。然后看兄弟节点,如果兄弟节点对应的球的半径加上距离a小于当前目标到兄弟节点球心的距离,则兄弟节点内部,肯定无更近距离的点。然后回溯父节点,找伯叔节点,循环上述找最近点的过程,直到回溯到根节点。

-
预测
和KD一样,找k个近邻点,在按照多数投票,确定分类。
球树虽然比KD树需要找寻的近邻点少,但是显然计算距离的时候,计算更复杂一点,所以这又是一个权衡,根据样本集的特征来进行选择。
6.3 扩展
-
少数群体问题处理与限定半径
即在分类问题中,可能某一个分类的样本数量特别的少,甚至比规定的k值还小,所以最后在找到k个近邻点的时候,肯定包含了其他类别的点,这就导致了误差。为了解决这个问题,所以在最开始就规定了一个限定半径。即只在这个半径内部找近邻点。
-
质心算法
即将一个区域内的所有样本的所有特征值求平均值,这个平均值就称为质心。然后这一类的所有点就被这个质心点代表了,后续所有的计算与寻找近邻就不用对这个类中的所有点计算,只要计算这个代表就可以,简化了计算,但显然会有一定的误差。
这两个算法,感觉都算不上算法。在我心中算法一般都是比较有难度的,这两种算法,书上都是给一段概念,有文字描述,还有例子和图,其实都是很简单很显而易见的东西,没必要用那么多的篇幅。
6.4 优缺点
KNN的主要优点有:
- 理论成熟,思想简单,既可以用来做分类也可以用来做回归
- 可用于非线性分类
- 训练时间复杂度比支持向量机之类的算法低,仅为O(n)
- 和朴素贝叶斯之类的算法比,对数据没有假设,准确度高,对异常点不敏感
- KNN方法较其他方法更为适合
- 该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分
KNN的主要缺点有:
- 计算量大,尤其是特征数非常多的时候
- 样本不平衡的时候,对稀有类别的预测准确率低
- KD树,球树之类的模型建立需要大量的内存
- 使用懒散学习方法,基本上不学习,导致预测时速度比起逻辑回归之类的算法慢
- 相比决策树模型,KNN模型可解释性不强
7. 朴素贝叶斯
朴素贝叶斯和先前的感知机,k近邻,逻辑回归等等都不同,它属于贝叶斯派别,先前的那些算法属于频率派,即生成方法,而不是判别方法。对于生成和非生成李航的书中有详细解释,简单来说,对于要了解一个人,非生成则直接根据你的行为来判定你到底是什么人,而生成则是先了解的父母,然后再根据你的一些特征,判定出你到底是什么人。
对应到数学上,非生成是直接得到决策函数Y = f(X)或者条件分布P(Y|X)。而贝叶斯是根据公式P(Y|X) = P(X,Y) / P(X)得到的。
进一步解释,就是贝叶斯学派需要先根据日常经验,大胆假设一个分布,也称为先验分布,即你的父母并不是详细调查得到的数据,而是根据以往历史经验得到的,或者是样本给定时,就说明了自己是什么分布。这个分布也很常见,比如说正态分布,beta分布等等。数据也就是样本本身的特征,很好理解。然后根据先验分布和样本数据,推算得到后验数据(也就是频率派直接计算得到的结果)
问题在于,先验概率的获得是根据经验假设的,所以没有很好的数学解释如何得来,但对于一些特定的场合,贝叶斯理论非常好用。当然真正在学习的时候,先验概率也是可以通过学习得到的,一般是根据最大似然估计法得到。公式为:
7.1 数学原理
朴素贝叶斯依据的数学原理也就是概率统计中非常出名的贝叶斯概率公式,推导过程也很简单,简单归简单,但是从无到有的过程,还是让人佩服。
7.2 模型建立
根据贝叶斯公式,可以知道,想得到后验概率,首先需要得到P(Yk),然后还要计算条件概率P(X|Yk),P(Yk)可用最大似然法估计,也就是Yk在训练集中出现的频数,这个很好计算。但是由于一般面对的样本都是多个特征,所以在计算条件概率的时候,需要计算多特征的联合条件分布,这就导致计算量很大很复杂。所以贝叶斯算法,就大胆假设所有的特征之间是相互独立的,所以条件概率公式转化如下:
如果面对的特征之间不是相互独立的,那么解决办法就是…………别用朴素贝叶斯,但是对于超大数量的数据集,即是部分特征是不独立的,也可以看成是独立的,称为弱成立。即虽然这样会存在误差,但只要误差在允许范围内就行,这样大大简化了计算。
最后在预测时,计算出所有内别的贝叶斯后验概率,然后概率最大的那个就是当前待预测样本的分类。
7.3 详细计算过程
这一节主要说明,在面对具体的训练集,以及训练集所包含的不同特征的时候,详细的计算P(Yk)和P(X|Yk)的过程。P(Yk)的计算很简单,就是看出现的频率,对于条件分布,需要分以下几种情况:
-
如果的Xj是离散的值
计算公式如下,其中mk为样本类别Ck总的特征计数,而mkj(train)为类别为Ck的样本中,第j维特征Xj(train)出现的次数。也就是在条件概率下,参考样本集,由总样本集转换为条件限制下的样本集
\[P(X_j=X_j^{(train)}|Y=C_k) = \frac{m_{kj^{(train)}}}{m_k} \]此外,如果某些类别在样本中没出现,则会导致条件概率直接为0,为了避免这个问题,引入拉普拉斯平滑,公式如下:
\[P(X_j=X_j^{(train)}|Y=C_k) = \frac{m_{kj^{train}} + \lambda}{m_k + O_j\lambda}(其中λ为一个大于0的常数,常常取为1。O_j为第j个特征的取值个数) \]关于此公式,推导过程可见【进阶篇】朴素贝叶斯法:贝叶斯估计_哔哩哔哩_bilibili。推导和之前算法的过拟合问题以及正则化的处理存在联系,推导过程也很精彩。
-
Xj是非常稀疏的离散值,即各个特征出现概率很低,这时可以假设Xj符合伯努利分布,即特征Xj出现记为1,不出现记为0。这样条件概率转化为:
\[P(X_j=X_j^{(train)}|Y=C_k) = P(X_j=1|Y=C_k)X_j^{(train)} + (1 - P(X_j=1|Y=C_k))(1-X_j^{(train)}) \] -
如果Xj是连续值,通常取Xj的先验概率为正态分布,即在样本类别Ck中,Xj的值符合正态分布,这样条件概率转化为:
\[P(X_j=X_j^{(train)}|Y=C_k) = \frac{1}{\sqrt{2\pi\sigma_k^2}}exp\Bigg{(}-\frac{(X_j^{(train)} - \mu_k)^2}{2\sigma_k^2}\Bigg{)} \]
可见上述两个问题,其实就是改变了特征的先验分布,这也是贝叶斯的一大特点,对于不同的特征特点,取相对应的先验概率分布。
7.4 优缺点
朴素贝叶斯的主要优点有:
- 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。
- 对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,可以一批批的去增量训练。
- 对缺失数据不太敏感,算法也比较简单,常用于文本分类。
朴素贝叶斯的主要缺点有:
- 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。
- 需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。
- 由于是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。
- 对输入数据的表达形式很敏感。
8 最大熵模型
提到熵就想到了逻辑回归和决策树章节提到的熵相关的概念,即来自于通信原理中的信息量的定义。而最大熵模型的概念,在我看来就是熵的定义和贝叶斯概率的集合。
8.1 模型定义
首先引入特征函数的概念f(x,y),用于定义输入与输出的关系,定义公式如下:
显然,只要总样本中存在m个输入输出满足特征函数,则就有m个等式,也即存在m个等式来限制输入输出。
进一步引入\(\overline{P}(X,Y)\)和\(\overline{P}(X)\),\(\overline{P}(X,Y)\)即为训练集中X,Y同时出现的次数除以样本总数m,\(\overline{P}(X)\)即为训练集中X出现的次数除以样本总数m。
从而得到两个期望,即\(E_{\overline{P}}(f) = \sum\limits_{x,y}\overline{P}(x,y)f(x,y)\)和\(E_{P}(f) = \sum\limits_{x,y}\overline{P}(x)P(y|x)f(x,y)\),如果模型是可以从训练集中学习,则这两个期望需要相等。这就又形成了一个限制,这个等式限制的具体作用,在下一个小结详细说明。
最后如何挑选模型,就是挑出使得H(p)达到最大值的那个后验分布,公式如下,一般计算时,取\(H(P)\)的相反数,这样可以转化为凸函数,从而使用凸函数的优化算法计算,具体计算见下一小节中原始问题和对偶问题的说明:
8.2 模型优化与计算
此小结主要说明最大熵模型的优化和计算的推导,最开始在学这一章的时候,详细了看了公式的推导,了解了每一步过程,知道了最终公式是怎么来的,以及其中用到的一些技巧,和每一个限制条件和变量的意义,整个推导过程虽然有点复杂,但是不得不说很精彩,具体见《统计学习方法》哔哩哔哩_bilibili中的对应章节。
具体的推导过程如下:
首先要引出原始问题、对偶问题这几个概念,后续的实际运算就是按照如下原理:
-
原始问题

-
对偶问题

-
运用上述方法求最大熵模型的解
-
首先是计算的初始三个公式(三个公式如何来的,看上一小节),可以看到没有不等式限制,即\(C_i(x)\)不存在
\[损失函数,目标是根据函数求得后验概率P(Y|X):\underbrace{ min }_{P} -H(P) = \sum\limits_{x,y}\overline{P}(x)P(y|x)logP(y|x) \\限制条件1:E_{\overline{P}}(f_i) - E_{P}(f_i) = 0 (i=1,2,...M) \\限制条件2:\sum\limits_yP(y|x) = 1 \] -
然后根据凸优化函数原理,也即是运用拉格朗日常数法来求解,公式为:
\[L(P,w) \equiv -H(P) + w_0(1 - \sum\limits_yP(y|x)) + \sum\limits_{i=1}^{M}w_i(E_{\overline{P}}(f_i) - E_{P}(f_i)) \]后续需要用对偶问题来求解原始问题,为了使p* = d*,则要求\(f(x)\)即\(-H(P)\)是凸函数,\(h_j(x)\)即w0和wi后面的那两坨是仿射函数。
对于第一个要求,根据凸函数的定义去计算,可以知道第一个要求是绝对满足的,即熵增函数是凸函数。具体计算见最大熵模型凸函数推导
对于第二个要求就比较显而易见,因为\(h_j(x)\)中的x也就是\(P(Y|X)\),它在所有的式子里面都是一次的,所以都是一次映射关系,即是仿射函数。
-
然后\(L(x,α,β)\)对x求最小值,即\(L(P,w)\)对\(P(y|x)\)求偏导,得到一个只关于w的函数,记为:
\[\psi(w) = \underbrace{ min }_{P}L(P, w) = L(P_w, w) \]将这个对偶函数的解记为:
\[P_w = arg \underbrace{ min }_{P}L(P, w) = P_w(y|x) \]具体计算时,令偏导数为0,求\(P_w\),得到如下(具体计算用了点小技巧,具体最大熵模型凸函数推导):
\[P(y|x) = exp(\sum\limits_{i=1}^{M}w_if_i(x,y) +w_0 -1) = \frac{exp(\sum\limits_{i=1}^{M}w_if_i(x,y))}{exp(1-w_0)} \]又因为\(\sum\limits_yP(y|x) = 1\),所以对上式直接求和并等于1,得到\(式1:P_w(y|x) = \frac{1}{Z_w(x)}exp(\sum\limits_{i=1}^{M}w_if_i(x,y))\),其中\(Z_w(x) = \sum\limits_yexp(\sum\limits_{i=1}^{M}w_if_i(x,y))\),之所以 \(Z_w(x)\)取这个值是因为分式等于1,所以分子等于分母,从而把原来的分母替换掉了,很简单,不要想复杂了。
-
根据式1可以看出,得到的\(P_W(y|x)\)是一个有关\(w_i\)的函数,那么\(\psi(w)= L(P_w, w)\)中的所有的\(P_w\)都可以用\(w_i\)来替代,接下来要做的就是对\(\psi(w)\)根据\(w_i\)取最大值,即可得到最终解,即用对偶问题求得的原始问题的最终解。
-
具体的最大值求解过程方法很多,比如梯度下降、牛顿法、拟牛顿法、迭代尺度法(IIS)等等。
8.3 优缺点
最大熵模型的优点有:
- 最大熵统计模型获得的是所有满足约束条件的模型中信息熵极大的模型,作为经典的分类模型时准确率较高。
- 可以灵活地设置约束条件,通过约束条件的多少可以调节模型对未知数据的适应度和对已知数据的拟合程度
最大熵模型的缺点有:
- 由于约束函数数量和样本数目有关系,导致迭代过程计算量巨大,实际应用比较难。
9. 集成学习
9.1 概述
顾名思义,集成学习,就是将一个个子学习模块,按一定的规则结合,形成最后的总学习器。所以要解决的就两个问题,子学习器如何得到,各子学习器该如何结合。优点就在于,集成之后,可以博采众长。
9.2 个体学习器的形成
形成主要分为两种类型,即各子学习器都是同一种类,或者不完全是同一种类。一般同质种类是用的比较多的,同质种类中用的比较多的是CART决策树和神经网络。同质个体学习器按照个体学习器之间是否存在依赖关系可以分为两类,第一个是个体学习器之间存在强依赖关系,一系列个体学习器基本都需要串行生成,代表算法是boosting系列算法,第二个是个体学习器之间不存在强依赖关系,一系列个体学习器可以并行生成,代表算法是bagging和随机森林(Random Forest)系列算法。
9.2.1 boosting

即先根据初始权重训练处一个弱学习器,由于存在误差,所以更新权重,使得误差对应的样本权重增大。更新权重后,继续训练得到一个弱学习器,然后根据误差再更新权重,循环下去,得到一堆弱学习器,显然这些学习器之间是有关系的。
Boosting系列算法里最著名算法主要有AdaBoost算法和提升树(boosting tree)系列算法。提升树系列算法里面应用最广泛的是梯度提升树(Gradient Boosting Tree)。
9.2.2 bagging

显而易见,boosting中的弱学习器之间的关系没了。
图中的随机采样一般采用的是自助采样法(Bootstrap sampling),即对于m个样本的原始训练集进行有放回的抽取,得到T个采样集。
随机森林是bagging的一个特化进阶版,所谓的特化是因为随机森林的弱学习器都是决策树。所谓的进阶是随机森林在bagging的样本随机采样基础上,又加上了特征的随机选择,其基本思想没有脱离bagging的范畴。
9.3 结合策略
9.3.1 平均法
顾名思义,就是对每一个子学习器的输出结果取平均,如果有权重,则乘以权重,一般用于数值类的回归预测问题。
9.3.2 投票法
一般用于分类问题。方法即是对所有子学习器的输出做统计,然后少数服从多数,结果分类中占比最高的即为预测结果,出现平票,则随机选择。
复杂一点,则在上述基础上,再加上票数必须占一半一上。更加复杂一点,则乘以一个权重,即每一个子学习器的权重。
9.3.3 学习法
上述两种方法,虽然简单,但是误差会比较大,这就引出了学习法。即对各子学习器的输出进行学习,也就是再套一层学习器,然后将第二层的学习结果,作为最终的预测。这和现如今的web开发的那一大堆中间件有点类似,万事不决,再加一层,对于上一层的要求,封装一个模块,专门处理。
9.4 Adaboost
9.2.1小节中,对于boosting的原理做了一定的解释,但是一些细节问题没有提出和解决:
- 如何计算学习误差率e?
- 如何得到弱学习器权重系数α?
- 如何更新样本权重D?
- 使用何种结合策略?
adaboost便对此做出了处理。
9.4.1 问题解决基本思路
-
如何计算学习误差率e?
-
分类问题
多分类以二分类代替,所以只对二分类求误差,输出为{-1,1},则第k个弱学习器\(G_k(x)\)的误差为:
\[e_k = P(G_k(x_i) \neq y_i) = \sum\limits_{i=1}^{m}w_{ki}I(G_k(x_i) \neq y_i) \]其中I(x)代表的意思是,x等式满足则为1,否则为-1,\(W_{ki}\)显然就是第i个特征的权重
-
回归问题
首先计算样本中的最大可能误差\(E_k= max|y_i - G_k(x_i)|\;i=1,2...m\)
然后计算每个样本的相对误差:\(e_{ki}= \frac{|y_i - G_k(x_i)|}{E_k}\)或者\(e_{ki}= \frac{(y_i - G_k(x_i))^2}{E_k^2}\)或者\(e_{ki}= 1 - exp(\frac{-|y_i - G_k(x_i)|)}{E_k})\)
然后叠加,得到弱学习器的误差率:\(e_k = \sum\limits_{i=1}^{m}w_{ki}e_{ki}\)
-
-
如何得到弱学习器权重系数α?
-
分类问题
直接给出公式,具体为什么用这个公式,见刘博客中对应章节,涉及到前项分布算法和指数损失函数,推理也比较简单,比最大熵的推导简单不少。
\[\alpha_k = \frac{1}{2}log\frac{1-e_k}{e_k} \] -
回归问题
\[\alpha_k =\frac{e_k}{1-e_k} \]显然能看到的是误差率越大,系数越小。这样做的功能就是使得误差率高的分类器的作用小一点,尽量避免对最后的强学习器造成干扰。
-
-
如何更新样本权重D?
-
分类问题
直接给出下述公式,具体推导见刘博客。对于初始的权重,一般直接认为每个样本的权重一样,所以\(w_{1i}=\frac{1}{m}\)。
\[D(k) = (w_{k1}, w_{k2}, ...w_{km}) ;\;\; w_{1i}=\frac{1}{m};\;\; i =1,2...m \]后续需要更新权重,使得判断错误的样本的权重增大,让后续的子学习器更加重视。比如有三个样本,初始权重全是1/3。第一轮学习之后,发现有一个样本判断错误了,则需要让权重变成1/6,1/6,4/6,这样就相当于增多了误差样本的个数,从而改变权重,具体权重计算公式如下:
\[w_{k+1,i} = \frac{w_{ki}}{Z_K}exp(-\alpha_ky_iG_k(x_i)) \\规范化因子,类似于最大熵模型中的推导:Z_k = \sum\limits_{i=1}^{m}w_{ki}exp(-\alpha_ky_iG_k(x_i)) \]进一步解释,如果分类正确,那么\(G_k(x_i) = y_i\),所以\(y_iG_k(x_i)=1\)(1乘1或者-1乘-1),否则\(G_k(x_i) \neq y_i\),\(y_iG_k(x_i)=-1\)。
进一步,如果判断正确,则\(w_{k+1,i} = \frac{w_{ki}}{Z_K}exp(-\alpha_k)\),因为\(\alpha_k > 0\)所以权重减小,如果判断错误,则\(w_{k+1,i} = \frac{w_{ki}}{Z_K}exp(\alpha_k)\),权重增大。这就是错误样本更得到重视。
-
回归问题
理论类似,只是求值方式有改变,即\(w_{k+1,i} = \frac{w_{ki}}{Z_k}\alpha_k^{1-e_{ki}}\),其中\(Z_k = \sum\limits_{i=1}^{m}w_{ki}\alpha_k^{1-e_{ki}}\)。
-
-
使用何种结合策略?
-
分类问题
采用的是加权表决法,即\(f(x) = sign(\sum\limits_{k=1}^{K}\alpha_kG_k(x))\)
-
回归问题
结合策略有所不同,回归问题采用的是所有弱学习器权重的中位数对应的那个弱学习器作为强学习器。
-
9.4.2 具体算法流程
结合上一小节的原理,算法流程也很容易得到:
- 设定初始样本集权重\(D(1)=\frac{1}{m}\)
- 使用这个权重进行计算得到一个弱学习器\(G_k(x_i)\)
- 求分类器误差率\(e_k\),根据误差率更新弱学习器的权重α,这个权重是为了放大误差率低的弱学习器的作用
- 根据α和\(G_k(x_i)\),按照公式更新\(D(k)\),这个权重是为了使判断错误的样本,后续更受重视
- 判断是否退出循环,退出条件为弱学习器数量已经达到,或者弱学习器的误差率已经满足要求。最终得到强学习器\(f(x) = sign(\sum\limits_{k=1}^{K}\alpha_kG_k(x))\)
9.4.3 正则化
首先,adaboost的各弱学习器之间有串联关系,下一个学习器由上一个学习器根据前项分布算法迭代得到,即:
为了避免过拟合问题,引入一个正则化项,通常称为步长v,从而公式转化为:
步长越小,迭代次数越多,使得拟合效果更好,这很好理解。
9.4.4 优缺点
Adaboost的主要优点有:
- Adaboost作为分类器时,分类精度很高
- 在Adaboost的框架下,可以使用各种回归分类模型来构建弱学习器,非常灵活。
- 作为简单的二元分类器时,构造简单,结果可理解。
- 不容易发生过拟合
Adaboost的主要缺点有:
- 对异常样本敏感,异常样本在迭代中可能会获得较高的权重,影响最终的强学习器的预测准确性。
9.5 梯度提升树(GBDT)
9.5.1 概述
梯度提升树有很多种类,其实内核都是一个东西,以下统称为GBDT。GBDT的运用十分广泛,在机器学习中算法中的地位很高。它也属于boosting系列中的成员,和adaboost不同的是每个弱学习器都是CART回归树模型,并且弱学习器之间的迭代思路不同。
GBDT的迭代思路是一层一层的使得损失函数越来越小,即再上一层传下来的损失函数的基础上,找到一个cart回归树,使得叠加上本层弱学习器之后的损失函数尽可能的小。
问题在于损失的拟合不好度量,损失函数也有很多,到底选哪一种拟合方法使得更加通用。
以上是刘博客中的内容概括,这一小节,他的博客中是直接给的公式,并没有给出公式推导过程,并且这一章的公式推导还是要会,也不是很复杂,如果不理解公式的由来,会导致一些概念理解起来有困难,比如拟合残差这个概念,残差怎么来的,什么意思,怎么拟合都不清楚。所以这一小节内容,主要重点参考了老弓的学习日记的个人空间中GBDT相关章节的推导
9.5.2 回归树和分类树回顾
由于GBDT的弱学习器用的是决策树,所以决策树相关的知识需要了解,具体见5.3小节。一下主要对回归树和分类树简单介绍。
-
回归树
回归树的模型可以表示为\(f(x)=\sum_{m=1}^{M} c_{m} I\left(x \in R_{m}\right)\),看起来有很多符号,其实很好理解,\(M\)表示总叶子节点数,\(I(x)\)之前也有出现,就是只要括号中的条件满足则输出1,否则0,对应到决策树这个概念上,就是在一系列的判断后,当前样本被归类到了哪一个叶子结点。\(C_m\)表示确定好的叶子结点的输出,即被分类到这个叶子结点后,到底被预测为什么值。以房子的平方数和价格举例,训练的时候,某叶子节点中有三个样本(70,100),(80,110),(90,120)。那么当待预测样本为85的时候,被归类到了这个叶子结点,那么待预测值就是\(\frac{70+80+90}{3}=C_m\),此时损失最小。
具体为什么最小,推导如下:

-
分类树
分类树在5.3小节做了详细解释,包括树的构建,基尼系数的定义与计算等等,还有例子,此处不做解释。
这一小节主要为了补充决策树叶子结点输出值的定义与计算推导。
9.5.3 GBDT算法流程
简单的用文字来描述就是,先经过初始弱学习器,得到的结果肯定存在误差,那么就基于这个误差,形成一个新的样本,再构建一个决策树,从而使误差减小,然后一步步的循环,直到误差率足够的小。
但是GBDT需要运用于回归树和分类树,分类树还要分为二分类和多分类,这三个分类的误差计算方式不同,也就是损失函数不同,那么这就回到了9.5.1章节的问题,怎样找到一个统一的方法,使得无论使用什么损失函数,都可以计算呢,这就引出了后面的9.5.4负梯度拟合小节。
进一步用函数表示一下上述的过程:
在GBDT的迭代中,假设前一轮迭代得到的强学习器是\(f_{t-1}(x)\), 损失函数是\(L(y,f_{t-1}(x))\) 本轮迭代的目标是找到一个CART回归树模型的弱学习器\(h_t(x)\),让本轮的损失函数\(L(y, f_{t}(x)) =L(y, f_{t-1}(x)+ h_t(x))\)最小。也就是说,本轮迭代找到决策树,要让样本的损失尽量变得更小。
更具体的算法流程,见9.5.5和9.5.6小节的内容。
9.5.4 负梯度拟合
关于这一小节,细看了一下推导过程,再次感觉到了数学的魅力。刘博客对于负梯度拟合直接给的结论,看的有点云里雾里。
具体的推导流程如下:

9.5.5 GBDT回归算法
输入是训练集样本\(T=\{(x_,y_1),(x_2,y_2), ...(x_m,y_m)\}\), 最大迭代次数T, 损失函数L。输出是强学习器f(x)
初始化弱学习器\(f_0(x) = \underbrace{arg\; min}_{c}\sum\limits_{i=1}^{m}L(y_i, c)\)
对迭代轮数t=1,2,...T有:
- 对样本i=1,2,...m,计算负梯度\(r_{ti} = -\bigg[\frac{\partial L(y_i, f(x_i)))}{\partial f(x_i)}\bigg]_{f(x) = f_{t-1}\;\; (x)}\)
- 利用\((x_i,r_{ti})\;\; (i=1,2,..m)\)拟合一颗CART回归树,得到第t颗回归树,其对应的叶子节点区域为\(R_{tj}, j =1,2,..., J\)。其中J为回归树t的叶子节点的个数。
- 对叶子区域j =1,2,..J,计算最佳拟合值\(c_{tj} = \underbrace{arg\; min}_{c}\sum\limits_{x_i \in R_{tj}} L(y_i,f_{t-1}(x_i) +c)\),可以用偏导数计算。
- 更新强学习器\(f_{t}(x) = f_{t-1}(x) + \sum\limits_{j=1}^{J}c_{tj}I(x \in R_{tj})\)
得到强学习器f(x)的表达式\(f(x) = f_T(x) =f_0(x) + \sum\limits_{t=1}^{T}\sum\limits_{j=1}^{J}c_{tj}I(x \in R_{tj})\)
9.5.6 GBDT分类算法
GBDT的分类算法从思想上和GBDT的回归算法没有区别,但是由于样本输出不是连续的值,而是离散的类别,导致无法直接从输出类别去拟合类别输出的误差。
为了解决这个问题,主要有两个方法,一个是用指数损失函数,此时GBDT退化为Adaboost算法。也就是Adaboost中的弱学习器全部换为决策树,且权重全是1。
另一种方法是用类似于逻辑回归的对数似然损失函数的方法。也就是说,用的是类别的预测概率值和真实概率值的差来拟合损失。
9.5.6.1 二元分类
对于二元GBDT,如果用类似于逻辑回归的对数似然损失函数,则损失函数为:\(L(y, f(x)) = log(1+ exp(-yf(x)))\)
其中\(y \in\{-1, +1\}\)。则此时的负梯度误差为\(r_{ti} = -\bigg[\frac{\partial L(y, f(x_i)))}{\partial f(x_i)}\bigg]_{f(x) = f_{t-1}\;\; (x)} = y_i/(1+exp(y_if(x_i)))\)
对于生成的决策树,各个叶子节点的最佳负梯度拟合值为\(c_{tj} = \underbrace{arg\; min}_{c}\sum\limits_{x_i \in R_{tj}} log(1+exp(-y_i(f_{t-1}(x_i) +c)))\)
由于上式比较难优化,一般使用近似值代替\(c_{tj} = \sum\limits_{x_i \in R_{tj}}r_{ti}\bigg / \sum\limits_{x_i \in R_{tj}}|r_{ti}|(1-|r_{ti}|)\)
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,二元GBDT分类和GBDT回归算法过程相同。
9.5.6.2 多元分类
多元GBDT要比二元GBDT复杂一些,对应的是多元逻辑回归和二元逻辑回归的复杂度差别。假设类别数为K,则此时的对数似然损失函数为:
其中如果样本输出类别为k,则yk=1。第k类的概率pk(x)的表达式为:
集合上两式,可以计算出第t轮的第i个样本对应类别l的负梯度误差为
观察上式可以看出,其实这里的误差就是样本i对应类别l的真实概率和t−1轮预测概率的差值。
对于生成的决策树,各个叶子节点的最佳负梯度拟合值为
由于上式比较难优化,我们一般使用近似值代替
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,多元GBDT分类和二元GBDT分类以及GBDT回归算法过程相同。
9.5.7 正则化
一般是三种正则化方法,第一种是和adaboost类似,在每一个弱学习器前加一个系数,从而增多迭代次数。第二种是对弱学习器对应的决策树进行剪枝。这两种的具体前面小节有,略。
第三种正则化的方式是通过子采样比例(subsample)。取值为(0,1]。注意这里的子采样和随机森林不一样,随机森林使用的是放回抽样,而这里是不放回抽样。如果取值为1,则全部样本都使用,等于没有使用子采样。如果取值小于1,则只有一部分样本会去做GBDT的决策树拟合。选择小于1的比例可以减少方差,即防止过拟合,但是会增加样本拟合的偏差,因此取值不能太低。推荐在[0.5, 0.8]之间。
使用了子采样的GBDT有时也称作随机梯度提升树(Stochastic Gradient Boosting Tree, SGBT)。由于使用了子采样,程序可以通过采样分发到不同的任务去做boosting的迭代过程,最后形成新树,从而减少弱学习器难以并行学习的弱点。
李航的书上的提升树章节说了很多种类的树,根据对于训练集的使用策略就分为了很多种,但其实原理很简单,就是多给了几个名字,没必要详细记忆,了解就行。
9.5.8 优缺点
GBDT主要的优点有:
- 可以灵活处理各种类型的数据,包括连续值和离散值。
- 在相对少的调参时间情况下,预测的准确率也可以比较高。这个是相对SVM来说的。
- 使用一些健壮的损失函数,对异常值的鲁棒性非常强。比如 Huber损失函数和Quantile损失函数。
GBDT的主要缺点有:
- 由于弱学习器之间存在依赖关系,难以并行训练数据。不过可以通过自采样的SGBT来达到部分并行。
补充:
Huber损失,它是均方差和绝对损失的折衷产物,对于远离中心的异常点,采用绝对损失,而中心附近的点采用均方差。这个界限一般用分位数点度量。损失函数如下:
分位数损失。它对应的是分位数回归的损失函数,表达式为
对于Huber损失和分位数损失,主要用于健壮回归,也就是减少异常点对损失函数的影响。
9.6 Bagging与随机森林算法
9.6.1 Bagging算法流程
随机森林算法是可以和梯度提升树GBDT分庭抗礼的算法,尤其是它可以很方便的并行训练,在如今大数据大样本的的时代很有诱惑力。
在9.2.2 小节,花了bagging算法的流程图
从图上可以看出Bagging算法相对于GBDT简单了很多,没有什么权重计算,前项分布算法等等,唯一多出来的就一个随机采样,而这个随机采样更简单,一句话概括就是,对于样本集进行有放回的采样,得到和训练集样本个数一样的采样集,然后分别训练学习器。
由于是有放回随机抽取,那么每个样本被选中的概率是\(\frac{1}{m}\),不被选中的概率是\(1-\frac{1}{m}\)。如果m次选取都没被选中概率为\((1-\frac{1}{m})^m\)。当m区域无穷时,这就是一个经典的极限求值,极限为\(\frac{1}{e}\),大约为0.368。那么没被选中的这部分,就可以作为验证集或测试集。
bagging对于弱学习器没有限制,这和Adaboost一样。但是最常用的一般也是决策树和神经网络。
bagging的集合策略也比较简单,对于分类问题,通常使用简单投票法,得到最多票数的类别或者类别之一为最终的模型输出。对于回归问题,通常使用简单平均法,对T个弱学习器得到的回归结果进行算术平均得到最终的模型输出。
9.6.2 随机森林
随机森林是bagging的进一步进化,可以形象一点的描述:因为是森林,所以弱学习器就要像GBDT一样,用的是决策树,这样多棵树才构成森林。随机则表示,这个森林中的树每一颗都不一样,特征是随机的。
所以重点就在于这个随机是怎么随机的,其实也很简单。一般决策树在选定分类点的时候,选择是所有样本特征中最适合的那个(信息增益那一堆东西,决策树章节做了详细描述)。而随机森林这里是先从总特征中随机选取一部分特征,然后再在这部分特征中挑选出最适合的。
显然选取的那一部分数量越多,随机性越差,但是训练集拟合效果越好,选择的越少,则模型的鲁棒性更好,但是拟合效果会比较差。具体这两点怎么权衡,则采用交叉验证的方式,来选择一个较好的值。
9.6.3 随机森林推广
随机森林有很多变种算法,应对不同的问题,构建不同的森林。
9.6.3.1 extra trees
原理和随机森林几乎一样,就两个不同点:
- 没有随机采样的步骤,即每次训练都是用的全样本数据
- 在选择分类点的时候,不是按照信息增益、基尼系数那一堆东西,而是随机选择分类点。这就使模型泛化能力更强,但是拟合效果显然差,树的规模也较大。
9.6.3.2 Totally Random Trees Embedding
这是一种非监督学习的数据转化方法,重点在于,它选择将低维的数据集映射到高维,从而让映射到高维的数据更好的运用于分类回归模型。
比如有3颗决策树,每个决策树有5个叶子节点,某个数据特征x划分到第一个决策树的第2个叶子节点,第二个决策树的第3个叶子节点,第三个决策树的第5个叶子节点。则x映射后的特征编码为(0,1,0,0,0, 0,0,1,0,0, 0,0,0,0,1), 有15维的高维特征。然后映射到高维,就可以继续使用各种监督学习算法来学习了。
9.6.3.3 Isolation Forest
孤立森林主要作用适用于异常点的检测,而对于异常点的检测,不需要那么多的样本数据,也不需要很复杂的决策树。这就是他和其他随机森林的区别。具体的算法逻辑见刘博客,而且刘博客中讲的也比较简短。真正涉及到这个算法还是要深入去了解并操作一下。
9.6.4 优缺点
RF的主要优点有:
- 训练可以高度并行化,对于大数据时代的大样本训练速度有优势。个人觉得这是的最主要的优点。
- 由于可以随机选择决策树节点划分特征,这样在样本特征维度很高的时候,仍然能高效的训练模型。
- 在训练后,可以给出各个特征对于输出的重要性
- 由于采用了随机采样,训练出的模型的方差小,泛化能力强。
- 相对于Boosting系列的Adaboost和GBDT, RF实现比较简单。
- 对部分特征缺失不敏感。
RF的主要缺点有:
- 在某些噪音比较大的样本集上,RF模型容易陷入过拟合。
- 取值划分比较多的特征容易对RF的决策产生更大的影响,从而影响拟合的模型的效果。
10. XGboost
10.1 从GBDT到XGBoost
作为GBDT的高效实现,XGBoost是一个上限特别高的算法。简单来说,对比原算法GBDT,XGBoost主要从下面三个方面做了优化:
- 算法本身的优化:
- GBDT只支持决策树,XGBoost支持很多其他的弱学习器。
- 在算法的损失函数上,除了本身的损失,还加上了正则化部分。
- 在算法的优化方式上,GBDT的损失函数只对误差部分做负梯度(一阶泰勒)展开,而XGBoost损失函数对误差部分做二阶泰勒展开,更加准确。
- 算法运行效率的优化:
- 对每个弱学习器,比如决策树建立的过程做并行选择,找到合适的子树分裂特征和特征值。
- 在并行选择之前,先对所有的特征的值进行排序分组,方便前面说的并行选择。
- 对分组的特征,选择合适的分组大小,使用CPU缓存进行读取加速。
- 将各个分组保存到多个硬盘以提高IO速度。
- 算法健壮性的优化:
- 对于缺失值的特征,通过枚举所有缺失值在当前节点是进入左子树还是右子树来决定缺失值的处理方式。
- 算法本身加入了L1和L2正则化项,可以防止过拟合,泛化能力更强。
10.2 XGBoost损失函数
GBDT中在计算的到负梯度之后,进一步的计算是先找到最优的叶子结点,然后再找到叶子节点区域的最优解。而XGBoost是将这两次计算,融合成一次计算。具体的计算如下:
首先基于GBDT的损失函数\(L(y, f_{t-1}(x)+ h_t(x))\)的基础上,加入正则化:
即XGBoost的损失函数为:\(L_t=\sum\limits_{i=1}^mL(y_i, f_{t-1}(x_i)+ h_t(x_i)) + \gamma J + \frac{\lambda}{2}\sum\limits_{j=1}^Jw_{tj}^2\)
对于损失函数的求解,选择的是直接二阶泰勒级数求解:
进一步简化,将两个偏导数用符号代替,从而得到如下损失函数:
进一步简化,将\(L(y_i, f_{t-1}(x_i)\)忽略,因为是两个入参都是定值,所以函数是一个常数。且\(h_t(x)\)的最终解都是叶子结点的最优值\(w_{tj}\)
进一步化简,得到如下损失函数,也就是后续直接一步计算出叶子结点的区域最优值的对象:
10.3 优化求解
对于10.2小节的求解算法,可以分为如下两步:
-
如果我们已经求出了第t个决策树的J个最优的叶子节点区域,如何求出每个叶子节点区域的最优解\(w_{tj}\)?
很显然,直接对\(w_{tj}\)求偏导,然后让偏导数等于0即可,值如下:
\[w_{tj} = - \frac{G_{tj}}{H_{tj} + \lambda} \] -
对当前决策树做子树分裂决策时,应该如何选择哪个特征和特征值进行分裂,使最终我们的损失函数\(L_t\)最小?
GBDT中是直接拟合的CART回归树,所以树节点分裂使用的是均方误差。XGBoost使用的贪心算法,即每次分裂都期望最小化我们的损失函数的误差。进一步解释就是划分左右子树的标准是划分后损失函数的值最小。
对于如何计算划分后的损失函数大小,XGBoost选择的是左右子数分别计算出一阶偏导数和二阶偏导数\(G_L,H_L,G_R,H_L\),然后代入损失函数求值:
\[-\frac{1}{2}\frac{(G_L+G_R)^2}{H_L+H_R+ \lambda} +\gamma J -( -\frac{1}{2}\frac{G_L^2}{H_L + \lambda} -\frac{1}{2}\frac{G_{R}^2}{H_{R} + \lambda}+ \gamma (J+1) ) \]\[也就是计算公式由均方误差,换成了如下:\max \frac{1}{2}\frac{G_L^2}{H_L + \lambda} + \frac{1}{2}\frac{G_R^2}{H_R+\lambda} - \frac{1}{2}\frac{(G_L+G_R)^2}{H_L+H_R+ \lambda} - \gamma \]
10.4 运行效率的优化
10.3小节主要是针对算法本身进行优化,此一小节主要是针对计算方式进行优化,主要运用到多线程操作,和操作系统IO相关的知识。
- Boosting算法的单个弱学习器里面最耗时的是决策树的分裂过程,XGBoost针对这个分裂做了比较大的并行优化。对于不同的特征的特征划分点,XGBoost分别在不同的线程中并行选择分裂的最大增益。
- 对训练的每个特征排序并且以块的的结构存储在内存中,方便后面迭代重复使用,减少计算量。首先默认所有的样本都在右子树,然后从小到大迭代,依次放入左子树,并寻找最优的分裂点。这样做可以减少很多不必要的比较。
- 通过设置合理的分块的大小,充分利用了CPU缓存进行读取加速。使得数据读取的速度更快。另外,通过将分块进行压缩并存储到硬盘上,并且通过将分块分区到多个硬盘上实现了更大的IO。
10.5 算法健壮性的优化
健壮性的优化除去上述的加入正则化项以外,还针对特征缺失值进行了处理。
XGBoost没有假设缺失值一定进入左子树还是右子树,则是尝试通过枚举所有缺失值在当前节点是进入左子树,还是进入右子树更优来决定一个处理缺失值默认的方向,这样处理起来更加的灵活和合理。
也就是说,在针对各个特征进行左右子数拆分的步骤,需要进行两次,第一次假设特征k所有缺失值的样本都走左子树,第二次假设特征k所有缺失值的样本都走右子树。然后每次都是针对没有缺失值的特征k的样本走一遍左右子数拆分流程,而不是所有的的样本。
11. 总结
以上为李航的《统计学习方法》监督学习相关的章节的学习笔记。监督学习算是机器学习和深度学习的基础,后续的主要研究方向是推荐算法,对于无监督学习的要求可能没有那么的高,可能会用到聚类相关的知识,并且这一篇的字数确实有点多了,都快两万九千字了,无监督学习相关的准备单独写几篇,或者直接嵌在实战篇里面。
这算是我第一次真正的深入接触机器学习和深度学习相关的知识,但纵观整本书以及刘建平博客中的内容,其实感觉难度没有那么大,理论也比较好理解,可能是还没有实战操作的原因,比较佩服的是这些理论从无到有的过程,和理论的创新,以及和高等数学的紧密结合,不禁感叹现在的理工科,大学本科学的东西,最有用的还是数学,其他专业课相关的知识,确实和现在的实践相差很多,只有数学是永久通用的。

浙公网安备 33010602011771号