目录
什么是集成学习
什么时候集成的效果就会好于单个分类器
基于数据集多重抽样的分类器
训练算法:基于错误提升分类器的性能
算法推导
基于单层决策树构建弱分类器
完整AdaBoost算法的实现
参考文献
集成学习就是将多个弱的学习器结合起来组成一个强的学习器。这就涉及到先产生一组“个体学习器”,在用一个策略将它们结合起来。 个体学习器可以选择:决策树,神经网络。 集成时可以所有个体学习器属于同一类算法:全是决策树或全是神经网络,也可以来自不同的算法。结合的策略:分类问题采用投票法,少数服从多数。回归取平均值。
集成并不是不管怎么选择学习器,怎么组合都一定会获得更好地结果,最好的情况是,每个学习器都不是特别差,并且要有一定的多样性,否则可能集成后的会没有效果,或者起负作用。那么如何生成准确性又不差,并且还能保证多样性的个体学习器呢。目前主要有两种方式:
Boostring: 个体学习器存在强依赖关系,必须串行生成
Bagging: 随机森林,个体之间不存在强依赖关系
Bagging: 从原始数据集选择S次后得到S个新数据集的一种技术。新数据集和原数据集的大小相等。每个数据集都是通过在原始数据集中随机选择一个样本来进行替换而得到的。这一性质就允许新数据集中可以有重复的值,而原式数据集中的某些值在新集合中则不再出现。
在s个数据集建好之后,将某个学习算法分别作用于每个数据集就得到了s个分类器。当对新数据进行分类时,就可以应用这s个分类器进行分类。与此同时,选择分类器投票结果中最多的类别作为最后的分类结果。还有一些更先进的bagging方法,比如随机森林。
Boosting:不论boosting还是bagging所使用的分类器的类型都是一致的。但是在前者当中,不同的分类器通过并行训练而获得,每个分类器都根据已训练出的分类器的性能来进行训练。boosting是通过集中关注被已有分类器错分的那些数据来获得新的分类器。
由于boosting分类的结果是基于所有分类器的加权求和结果,因此boosting与bagging不太一样。bagging中的分类器权重是相等的,而boosting中的分类器权重并不相等,每个权重代表的是其对应分类器在上一轮迭代中的成功度。
我们可以将不同的分类器组合起来,而这种组合结果被称为集成方法或者元算法。使用集成方法会有多种形式:可以是不同算法的集成,也可以是同一算法在不同设置下的集成,还可以是数据集不同部分分配给不同分类器之后的集成。接下来将介绍基于同一种分类器多个不同实例的两种计算方法。在这些方法中,数据集也会不断变化,而后应用于不同的实力分类器上。
AdaBoost
优点:泛化错误率低,易编码,可以应用在大部分分类器上,无参数调整。
缺点:对离群点敏感。
使用数据类型:数值型和标称型数据
adaboosting运行过程如下: 训练数据中的每个样本,并赋予其一个权重,这些权重构成了向量D。一开始,这些权重都初始化成相等值。首先在训练数据上训练出一个弱分类器并计算该分类器的错误率,然后在同一数据集上在此训练弱分类器。在分类器的第二次训练中,将会重新调整每个样本的权重,其中第一次分对的样本的权重会降低,而第一次分错的样本的权重将会提高。为了从所有弱分类器中得到最终的分类结果,adaboost为每个分类器都分配了一个权重值alpha,这些alpha值是基于每个弱分类器的错误率进行计算的。其中,错误率的定义如下:
则alpha的计算公式如下
计算出alpha值之后,可以对权重向量D进行更新,以使得那些正确分类的样本的权重降低而错分样本的权重升高。D的计算方法如下。
如果某个样本被正确分类,那么该样本的权重更改为:
如果某个样本被错分,那么该样本的权重更改为:
在计算出D之后, adaboost又开始进入下一轮迭代。adaboost算法会不断地重复训练和调整权重的过程,直到训练错误率为0或者弱分类器的数目达到用户的指定值为止。
最后学习出来的预测数据的模型为H:
即强学习器是基学习器的线性组合形式。
目标函数用指数损失函数:
使导数为0后得到
首先载入数据
def loadSimpData():
dataMat = np.matrix([[1., 2.1],
[2., 1.1],
[1.3, 1.],
[1., 1.],
[1.5, 1.6]])
classLabels = [1.0, 1.0, 0, 0, 1.0]
return dataMat, classLabels
构建单层决策树的伪代码:
将最小错误率minError设为+∞
对数据集中的每一个特征(第一层循环):
对每个步长(第二层循环):
对每个不等号(第三层循环):
建立一棵单层决策树并利用加权数据集对它进行测试
如果错误率低于minError, 则将当前单层决策树设为最佳单层决策树
返回最佳单层决策树
单层决策树生成算法:
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
retArray = np.ones((np.shape(dataMatrix)[0], 1))
if threshIneq == 'lt':
retArray[dataMatrix[:, dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:, dimen] > threshVal] = -1.0
return retArray
def buildStump(dataArr, classLabels, D):
dataMatrix = np.mat(dataArr); labelMat = np.mat(classLabels).T
m, n = np.shape(dataMatrix)
numSteps = 10.0; bestStump = {}; bestClassEst = np.mat(np.zeros((m, 1)))
minError = np.inf
for i in range(n): # 对于每个特征
rangeMin = dataMatrix[:, i].min(); rangeMax = dataMatrix[:, i].max()
stepSize = (rangeMax-rangeMin)/numSteps
for j in range(-1, int(numSteps)+1):
for inequal in ['lt', 'gt']:
threshVal = (rangeMin + float(j) * stepSize)
predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)
errArr = np.mat(np.ones((m, 1)))
errArr[predictedVals == labelMat] = 0
weightedError = D.T * errArr
print("split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f"\
%(i, threshVal, inequal, weightedError))
if weightedError < minError:
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = i
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump, minError, bestClasEst
buildStump()会遍历stumpClassify()函数所有的可能输入值,并找到数据集上最佳的单层决策树。这里的最佳是基于数据的权重向量D来定义的。
伪代码:
对每次迭代:
利用buildStump()函数找到最佳的单层决策树
将最佳单层决策树加入到单层决策树数组
计算alpha
计算新的权重向量D
更新累计类别估计值
如果错误率等于0.0,则退出循环
代码实现:
def adaBoostTrainDS(dataArr, classLabels, numIt=40):
weakClassArr = []
m = np.shape(dataArr)[0]
D = np.mat(np.ones((m, 1)) / m)
aggClassEst = np.mat(np.zeros((m, 1)))
for i in range(numIt):
bestStump, error, classEst = buildStump(dataArr, classLabels, D)
alpha = float(0.5*(np.log(1.0 - error)/np.max(error, 1e-16)))
bestStump['alpha'] = alpha
weakClassArr.append(bestStump)
expon = np.multiply(-1*alpha*np.mat(classLabels).T, classEst)
D = np.multiply(D, np.exp(expon))
D = D / D.sum()
aggClassEst += alpha * classEst
aggErrors = np.multiply(np.sign(aggClassEst) != np.mat(classLabels).T, np.ones((m, 1)))
errorRate = aggErrors.sum() / m
if errorRate == 0.0:
break
return weakClassArr
利用adaboost来进行分类
def adaClassify(datToClass, classifierArr):
dataMatrix = np.mat(datToClass)
m = np.shape(datToClass)[0]
aggClassEst = np.mat(np.zeros((m, 1)))
for i in range(len(classifierArr)):
classEst = stumpClassify(dataMatrix, classifierArr[i]['dim'], classifierArr[i]['thresh'],
classifierArr[i]['ineq'])
aggClassEst += classifierArr[i]['alpha'] * classEst
return np.sign(aggClassEst)
https://www.jianshu.com/p/389d28f853c0
《机器学习实战》第7章