俗话说“三个臭皮匠顶个诸葛亮”,集合算法(提升算法)就是将若干个算法集成,输出投票表决的结果。
AdaBoost与Bagging两者的区别是:
- Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的。
- Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。而权值是根据上一轮的分类结果进行调整。
- Bagging:使用均匀取样,每个样例的权重相等。
- Boosting:根据错误率不断调整样例的权值,错误率越大则权重越大。
- Bagging:所有预测函数的权重相等。
- Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重。
- Bagging:各个预测函数可以并行生成。
- Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果。
而随机森林()是Bagging的延展。
算法-AdaBoost
- 输入:
- 训练数据集,其中;
- 弱学习算法
- 输出:最终分类器G(x)
- (1) 初始化训练样本的权值分布为 即各个训练样本的权重均等
- (2) 对m=1,2,…,M, m表示训练轮数(亦即第m个基分类器,因为每一轮产生一个基分类器):
- 使用具有权值分布的训练数据集学习,得到基本分类器
- 计算在训练数据集上的分类错误率: 即(分类错误的样本该样本的权重)之和
- 计算最终基分类器在组合分类器中的权重值 由式可知,当时,,并且随着的减小而增大,所以分类误差率越小的基本分类器在最终分类器中的作用越大。
- 更新训练数据集的权值分布 如果那么 否则
如果将权重更新简化表示就是(因为,根据其异同可以决定指数部分的符号)
其中 是规范化因子,用来使权重分布成为一个概率分布(这里就可以看到错分样本的权重被调大)
- (3) 构建基本分类器的线性组合 得到最终分类器
python实现:
def loadSimpData():
"""
加载简单数据集
:return:
"""
datMat = matrix([[1., 2.1],
[2., 1.1],
[1.3, 1.],
[1., 1.],
[2., 1.]])
classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
return datMat, classLabels
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq): # just classify the data
"""
用只有一层的树桩决策树对数据进行分类
:param dataMatrix: 数据
:param dimen: 特征的下标
:param threshVal: 阈值
:param threshIneq: 大于或小于
:return: 分类结果
"""
retArray = ones((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):
"""
构建决策树(一个树桩)
:param dataArr: 数据特征矩阵
:param classLabels: 标签向量
:param D: 训练数据的权重向量
:return: 最佳决策树,最小的错误率加权和,最优预测结果
"""
dataMatrix = mat(dataArr)
labelMat = mat(classLabels).T
m, n = shape(dataMatrix)
numSteps = 10.0
bestStump = {}
bestClasEst = mat(zeros((m, 1)))
minError = 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) # 使用参数 i, j, lessThan 调用树桩决策树分类
errArr = mat(ones((m, 1)))
errArr[predictedVals == labelMat] = 0 # 预测正确的样本对应的错误率为0,否则为1
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
def adaBoostTrainDS(dataArr, classLabels, numIt=40):
"""
基于单层决策树的ada训练
:param dataArr: 样本特征矩阵
:param classLabels: 样本分类向量
:param numIt: 迭代次数
:return: 一系列弱分类器及其权重,样本分类结果
"""
weakClassArr = []
m = shape(dataArr)[0]
D = mat(ones((m, 1)) / m) # 将每个样本的权重初始化为均等
aggClassEst = mat(zeros((m, 1)))
for i in range(numIt):
bestStump, error, classEst = buildStump(dataArr, classLabels, D) # 构建树桩决策树,这是一个若分类器,只能利用一个维度做决策
# print "D:",D.T
alpha = float(
0.5 * log((1.0 - error) / max(error, 1e-16))) # 计算 alpha, 防止发生除零错误
bestStump['alpha'] = alpha
weakClassArr.append(bestStump) # 保存树桩决策树
# print "classEst: ",classEst.T
expon = multiply(-1 * alpha * mat(classLabels).T, classEst) # 每个样本对应的指数,当预测值等于y的时候,恰好为-alpha,否则为alpha
D = multiply(D, exp(expon)) # 计算下一个迭代的D向量
D = D / D.sum() # 归一化
# 计算所有分类器的误差,如果为0则终止训练
aggClassEst += alpha * classEst
# print "aggClassEst: ",aggClassEst.T
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m, 1))) # aggClassEst每个元素的符号代表分类结果,如果与y不等则表示错误
errorRate = aggErrors.sum() / m
print "total error: ", errorRate
if errorRate == 0.0: break
return weakClassArr, aggClassEst
def adaClassify(datToClass, classifierArr):
dataMatrix = mat(datToClass)
m = shape(dataMatrix)[0]
aggClassEst = mat(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
print aggClassEst
return sign(aggClassEst)
http://izhaoyi.top/2017/06/29/boosting/