AdaBoost算法理解与提升树原理及实现
从机器学习三要素理解AdaBoost算法
AdaBoost
- 算法模型:加法模型 f(x)=∑m=1MalphamGm(x)f(x)=∑m=1MalphamGm(x) , 最终模型:最终模型:G(x) = sign(f(x))$$
- 损失函数:指数函数 基分类器分类错误或正确时 对数据集权值的调整 更为关注误分类 wm+1,i=WmiZmexp−αmyiGm(xi)wm+1,i=WmiZmexp−αmyiGm(xi),Zm=∑i=1NWmiexp−αmyiGm(xi)Zm=∑i=1NWmiexp−αmyiGm(xi)
- 算法:前向分步算法
前向分步算法
什么是前向分步算法
原理: 由于模型是加法模型, 如果从前向后, 每一步只学习上个基函数及其系数, 逐步逼近损失函数最小化函数,就可以简化优化的复杂度
从局部最优到全局最优
- 模型: f(x)=∑m=1Mβmb(x;rm)f(x)=∑m=1Mβmb(x;rm)
其中:b(x;rm)是基函数,弱分类器,rm是基函数的参数b(x;rm)是基函数,弱分类器,rm是基函数的参数 - 损失函数: L(y,f(x))L(y,f(x))
结合损失函数及算法模型: 学习加法模型f(x)
经验风险极小化即损失函数极小化问题
极小化损失函数模型为: minβm,rm∑i=1NL(yi,∑m=1Mβmb(x;,rm)minβm,rm∑i=1NL(yi,∑m=1Mβmb(x;,rm)
根据前向分布算法将损失函数简化–求每步的损失函数的最小化 那么最终的损失函数就是最小
即:minβ,r∑i=1NL(yi,βb(x;r))minβ,r∑i=1NL(yi,βb(x;r))
前向分步算法实现步骤
Input: dataSetT=(x1,y1),(x2,y2),....,(xN,yN)dataSetT=(x1,y1),(x2,y2),....,(xN,yN) 损失函数L(y_i, f(x)) 基函数集合{b(x;, r)}
Output:加法模型f(x)加法模型f(x)
前向分步算法将: 将同时求解m=1,…,M的所有参数βm,rmβm,rm简化为求解各个参数βm,rmβm,rm的最优解
具体步骤:
- step1: 初始化f_0(x) = 0
step2: 对M个弱分类器 有m=1,2,…,M轮迭代
(a) 极小化损失函数
(\beta_m, r_m) = \arg\min\limits_{\beta, r}\sum\limits_{i=1}^{N}L(y_i, f_{m-1}(x_i) + \beta b(x_i;r))得到参数得到参数\beta_m, r_m分别表示基函数系数以及基函数参数(b)更新:分别表示基函数系数以及基函数参数(b)更新:f(x) = f_{m-1}(x) + \beta_m b(x;r_m)$step3: 得出最终模型
f(x)=fm(x)=∑m=1M=1βmb(x;rm)f(x)=fm(x)=∑m=1M=1βmb(x;rm)
前向分布算法与AdaBoost
定理: AdaBoost算法是前向分布加法算法的特例, 模型是由基本分类器组成的加法模型
损失函数为指数函数
前向分布算法学习的是加法模型 当基函数为基本分类器时, 该加法模型等价于AdaBoost的最终分类器
f(x)=∑m=1MαmGm(x)f(x)=∑m=1MαmGm(x)
损失函数:L(y,f(x))=exp[−yf(x)]L(y,f(x))=exp[−yf(x)]
扩展: 证明前向分布算法损失函数是指数损失函数
假设: m-1迭代,前向分布算法已经得到了fm−1(x)fm−1(x)
fm−1(x)=f(m−2)f(x)+αm−1Gm−1(x)=alpha1G1(x)+...+αm−1Gm−1f(x)fm−1(x)=f(m−2)f(x)+αm−1Gm−1(x)=alpha1G1(x)+...+αm−1Gm−1f(x)
即: fm(x)=f(m−1)(x)+αmGm(x)fm(x)=f(m−1)(x)+αmGm(x)
目标函数: (αm,Gm(x)=argminα,G∑i=1Nexp[−y(fm−1(xi)+αG(xi)](αm,Gm(x)=argminα,G∑i=1Nexp[−y(fm−1(xi)+αG(xi)]
即为:(alpham,Gm(x))=argminα,G∑i=1NWmiexp[−yiαG(xi)]即为:(alpham,Gm(x))=argminα,G∑i=1NWmiexp[−yiαG(xi)]
其中Wmi=exp[−yifm−1(xi)]Wmi=exp[−yifm−1(xi)], Wmi即不依赖α,也不依赖G,但是与fm−1(x)有关Wmi即不依赖α,也不依赖G,但是与fm−1(x)有关
接下来证明公式中达到的最小αm∗和G∗m(x)就是AdaBoost算法所得到的αm和Gmxαm∗和Gm∗(x)就是AdaBoost算法所得到的αm和Gmx
- 1.先求:G_m^*(x),对任意\alpha>0
G∗m(x)=argminα,G∑i=1NWmiI(yi≠G(xi))Gm∗(x)=argminα,G∑i=1NWmiI(yi≠G(xi))
其中: Wmi=exp[−yifm−1(xi)]Wmi=exp[−yifm−1(xi)] - 2.求αm∗,∑i=1NWmiexp[−yiαG(xi)]=∑yi=Gm(xi)Wmiexp−α+∑yi≠Gm(xi)Wmiexpα(expα−exp−α)∑i=1NWmiI(yi≠G(xi))+exp−α∑i=1NWmiαm∗,∑i=1NWmiexp[−yiαG(xi)]=∑yi=Gm(xi)Wmiexp−α+∑yi≠Gm(xi)Wmiexpα(expα−exp−α)∑i=1NWmiI(yi≠G(xi))+exp−α∑i=1NWmi
将Gmx代入,对α求导:α=12log1−ememGmx代入,对α求导:α=12log1−emem
em是误分类率,em=∑i=1NWmiI(yi≠Gm(xi))em是误分类率,em=∑i=1NWmiI(yi≠Gm(xi))
权值更新为: Wmi+1,i=Wmiexp[−yiαmGm(xi)]Wmi+1,i=Wmiexp[−yiαmGm(xi)]
提升树原理及实现
提升树原理及实现
提升树是以分类数或回归数为基本分类器的提升方法.提升树被认为是统计学习中性能最好的方法之一
提升树模型
提升数模型实际上采用加法模型(即基函数的线性组合)与前向分步算法,以决策树为基函数的提升方法称为提升树
该基函数模型仅仅略优于随机猜测,因此是使用单层决策树
单层决策树的原理及实现:
单层决策树:decision stump 决策树桩
原理: 仅仅基于单个特征来说决策 实质上只有一次分裂过程 就是个树桩
伪代码实现
将最小错误率minError设置为 正无穷大
对数据集中每一个特征(第一层循环):
对每个步长(第二层循环):
对每个不等号(第三层循环):
建立一颗单层决策树并利用加权数据对它进行测试(错误率)
如果错误率低于minError,则将当前单层决策树设置为最佳单层决策树
返回最佳单层决策树
import numpy as np
def loadSimpData():
""" 测试数据
Returns:
dataArr feature对应的数据集
labelArr feature对应的分类标签
"""
dataSet = np.array([[1., 2.1], [2., 1.1], [1.3, 1.], [1., 1.], [2., 1.]])
labelMat = [1.0, 1.0, -1.0, -1.0, 1.0]
return dataSet, labelMat
# 建立单层决策树
def stumpTree(dataSet, labelMat, D):
"""
建立单层决策树
:param dataSet: 训练数据集 特征值
:param labelMat: 训练数据集 类别标签
:param D: 权重值
:return
bestStumpTree 最佳单层决策树
"""
dataMat = np.mat(dataSet)
labelMat = np.mat(labelMat).T
m, n = np.shape(dataMat)
# print('m, n', m, n)
# print('dataMat:', dataMat)
# print('labelMat:', labelMat)
# step1 设置最小误差
minError = np.inf # 最小误差率设置为正无穷
numSteps = 10.0
bestStump = dict()
bestClasEst = np.mat(np.zeros((m, 1)))
# step2 对每一个特征进行循环 计算步长
# print('训练数据集特征', featureNums)
for index in range(n):
# 连续性数据 分类 需要计算步长
rangeMin = dataMat[:, index].min()
rangeMax = dataMat[:, index].max()
delta = (rangeMax - rangeMin) / numSteps
# step3 第二层循环
for j in range(-1, int(numSteps)+1):
# step4 第三层循环 建立一颗单层决策树并利用加权数据对它进行测试(错误率)
for inequal in ['lt', 'gt']:
threshVal = (rangeMin + j * delta)
predictedVals = stumpClassify(dataMat, index, threshVal, inequal)
# print('predictedVals 结果集', predictedVals) # matrix 形式的结果集
# 计算加权错误率 weightedError
errorMat = np.mat(np.ones((m, 1)))
errorMat[predictedVals == labelMat] = 0
weightedError = D.T * errorMat
# print('index', index)
if weightedError < minError:
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = index
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump, minError, bestClasEst
def stumpClassify(dataMat, index, threshVal, threshIneq):
"""
单层决策树分类
在阈值一边的数据会分到类别-1
另一边的阈值分到类别1
首先将全部数组元素设置为1 然后将不满足不等式要求的元素设置为-1
:param dataMat: 训练数据集 输入空间
:param index: 训练数据集 特征index
:param threshVal: 阈值
:param threshIneq: 小于或大于
:return
retArray: 结果集
"""
# print('try', (np.shape(dataMat))[0])
dimen = (np.shape(dataMat))[0]
retArray = np.ones((((np.shape(dataMat))[0]), 1)) # 5x1
if threshIneq == 'lt':
retArray[dataMat[:, index] <= threshVal] = -1.0
else:
retArray[dataMat[:, index] > threshVal] = -1.0
return retArray
基于单层决策树的AdaBoost算法实现
伪代码
对每次迭代:
利用stumpTree()函数找到最佳的单层决策树
将最佳的单层决策树加入到决策树组
计算alpha
计算新的权重向量D
更新累计类别估计值
如果错误率==0, 退出循环
def adaBoostTrainDT(dataMat, labelMat, maxCycle):
"""
基于单层决策树的AdaBoost算法实现
:param dataMat: 训练数据集 输入空间
:param labelMat: 训练数据集 输出空间
:param maxCycle: 最大迭代次数
:return
strongDtree 决策数组
"""
strongDtree = list()
m, n = np.shape(dataMat)
# 初始化权重向量D
D = np.ones((m, 1)) / m
# print('初始化权重向量D', D)
upClassEst = np.mat(np.zeros((m, 1)))
for cycle in range(maxCycle):
bestStump, minError, bestClasEst = stumpTree(dataMat, labelMat, D)
# print('predictedVals 结果', bestClasEst) # 结果
# 计算 alpha 系数
alpha = float(0.5 * np.log((1-minError)/max(minError, 0.001)))
bestStump['alpha'] = alpha
strongDtree.append(bestStump)
# 更新D 权重向量
# 错误分类的加重权重 正确分类的减少权重
expon = np.multiply(-1*alpha*np.mat(labelMat).T, bestClasEst)
D = np.multiply(D, np.exp(expon))
D = D/D.sum()
# 更新累计类别估计值
upClassEst += alpha * bestClasEst
aggError = np.multiply(np.sign(upClassEst) != np.mat(labelMat).T, np.ones((m, 1)))
errorRate = aggError.sum() / m
print('errorRate', errorRate)
if errorRate == 0.0:
break
return strongDtree
测试算法及效果
# 测试算法: 基于AdaBoost的分类
def adaClassify(dataToClass, classifierArr):
"""
基于AdaBoost的强分类器的分类
:param dataToClass: 输入变量
:param classifierArr: 强分类器
:return
np.sign(aggClassEst) 分类结果
"""
# do stuff similar to last aggClassEst in adaBoostTrainDS
dataMat = np.mat(dataToClass)
m = np.shape(dataMat)[0]
aggClassEst = np.mat(np.zeros((m, 1)))
# 循环 多个分类器
for i in range(len(classifierArr)):
# 前提: 我们已经知道了最佳的分类器的实例
# 通过分类器来核算每一次的分类结果,然后通过alpha*每一次的结果 得到最后的权重加和的值。
classEst = stumpClassify(dataMat, classifierArr[i]['dim'], classifierArr[i]['thresh'],
classifierArr[i]['ineq'])
aggClassEst += classifierArr[i]['alpha'] * classEst
print(aggClassEst)
return np.sign(aggClassEst)
def main():
dataSet, labelMat = loadSimpData()
strongDtree = adaBoostTrainDT(dataSet, labelMat, maxCycle=40)
print('最终分类器:', strongDtree)
result = adaClassify([[5, 5], [0, 0]], strongDtree)
print('测试结果:', result)
if __name__ == '__main__':
main()
提升树-疝气病马预测
def loadDataSet(filename):
dataSet = list()
labelMat = list()
with open(filename, 'r') as f:
for lines in f.readlines():
lis = lines.split('\t')
lineArr = []
for i in lis[:-1]:
lineArr.append(float(i))
# print(lineArr)
# print(len(lineArr))
dataSet.append(lineArr)
labelMat.append(float(lis[-1]))
print(np.shape(dataSet), type(dataSet[0][0])) # (299, 21) <class 'float'>
print(np.shape(labelMat), type(dataSet[0][0])) # (299, ) <class 'float'>
return dataSet, labelMat
def main():
filename = 'horseColicTraining2.txt'
dataSet, labelMat = loadDataSet(filename)
strongDtree, aggClassEst = adaBoostTrainDT(dataSet, labelMat, maxCycle=10)
print('strongDtree', strongDtree)
print('aggClassEst', aggClassEst)
plotROC(aggClassEst.T, labelMat)
filename = 'horseColicTest2.txt'
testSet, testlabel = loadDataSet(filename)
predictList = adaClassify(testSet, strongDtree)
# 测试:计算总样本数,错误样本数,错误率
m = np.shape(testSet)[0]
error = np.mat(np.ones((m, 1)))
print('测试样本个数%s 错误个数%s 错误率%.2f%%' % (m, error[predictList != np.mat(testlabel).T].sum(), error[predictList != np.mat(testlabel).T].sum()/m *100))
参考文献
《统计学习方法》,李航著
《机器学习实战》
本文深入解析AdaBoost算法及提升树原理,介绍其核心概念包括加法模型、前向分步算法,并给出详细的实现步骤及应用案例。
1219

被折叠的 条评论
为什么被折叠?



