目录
一、前言:
样本选择上:
样例权重:
预测函数:
并行计算:
数据显示
弱分类器
五、总结
参考资料:
这部分的学习对我来说比较吃力,查了挺多资料,有一个模糊的概念。
当做重要决定时,大家可能都会考虑西区多个专家而不只是一个人的意见。假期血虚处理问题时又何尝不是呢?这就是原算法(meta-algorithm)背后的思路。
组合结果则被成为集成方法(ensemble method)或者元算法(meta-algorithm)
二、Bagging、Boosting二者之间的区别样本选择上:
- Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的。
- Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。而权值是根据上一轮的分类结果进行调整。
样例权重:
- Bagging:使用均匀取样,每个样例的权重相等。
- Boosting:根据错误率不断调整样例的权值,错误率越大则权重越大。
预测函数:
- Bagging:所有预测函数的权重相等。
- Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重。
并行计算:
- Bagging:各个预测函数可以并行生成。
- Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果。
这两种方法都是把若干个分类器整合为一个分类器的方法,只是整合的方式不一样,最终得到不一样的效果,将不同的分类算法套入到此类算法框架中一定程度上会提高了原单一分类器的分类效果,但是也增大了计算量。
AdaBoost算法是基于Boosting思想的 算法,AdaBoost是adaptive boosting(自适应boosting)的缩写,其运行过程如下:
三、理论难点:AdaBoost算法的特点是通过迭代每次学习一个基本分类器。每次迭代中,提高那些被前一轮分类器错误分类数据的权值,而降低那些被正确分类的数据的权值。最后,AdaBoost将基本分类器的线性组合作为强分类器,其中给分类误差率小的基本分类器以大的权值,给分类误差率大的基本分类器以小的权值。
AdaBoost
AdaBoost是AdaptiveBoost的缩写,表明该算法是具有适应性的提升算法。
算法的步骤如下:
1)给每个训练样本分配权重,初始权重均为1/N。
2)针对带有权值的样本进行训练,得到模型(初始模型为G1)。
3)计算模型????????的误分率
4)计算模型????????的系数
5)根据误分率e和当前权重向量更新权重向量。
6)计算组合模型的误分率。
7)当组合模型的误分率或迭代次数低于一定阈值,停止迭代;否则,回到步骤2)
1、计算样本权重
每个样本的权重都是相等的,即1/n
2、计算错误率
利用第一个弱学习算法h1对其进行学习,学习完成后进行错误率ε的统计:
3、计算弱学习算法权重
4、更新样本权重
重新调整样本的权重
ht(xi) = yi表示对第i个样本训练正确,不等于则表示分类错误。Zt是一个归一化因子
公式我们可以继续化简,将两个公式进行合并,化简如下:
5、AdaBoost算法
重复进行学习,这样经过t轮的学习后,就会得到t个弱学习算法、权重、弱分类器的输出以及最终的AdaBoost算法的输出,分别如下:
sign(x)是符号函数。具体过程如下所示
四、基于单层决策树构建弱分类器建立AdaBoost算法之前,我们必须先建立弱分类器,并保存样本的权重。弱分类器使用单层决策树(decision stump),也称决策树桩,它是一种简单的决策树,通过给定的阈值,进行分类。
单层决策树难以处理的一个著名问题:如果想要试着从某个坐标轴上选择一个值(即选择一条与坐标轴平行的直线)来将所有的蓝色圆点和橘色圆点分开,这显然是不可能的
数据可视化:
我们先采用一个普通的单层决策树来实现:
就是通过遍历,改变不同的阈值,计算最终的分类误差,找到分类误差最小的分类方式,即为我们要找的最佳单层决策树。这里lt表示less than,表示分类方式,对于小于阈值的样本点赋值为-1,gt表示greater than,也是表示分类方式,对于大于阈值的样本点赋值为-1。经过遍历,我们找到,训练好的最佳单层决策树的最小分类误差为0.2,就是对于该数据集,无论用什么样的单层决策树,分类误差最小就是0.2。这就是我们训练好的弱分类器。接下来,使用AdaBoost算法提升分类器性能,将分类误差缩短到0,看下AdaBoost算法是如何实现的。
数据显示
import numpy as np
import matplotlib.pyplot as plt
def loadSimData():
"""
创建单层决策树的数据集
Parameters:
无
Returns:
dataMat - 数据矩阵
classLabels - 数据标签
"""
datMat = np.matrix([[ 1. , 2.1],
[ 1.5, 1.6],
[ 1.3, 1. ],
[ 1. , 1. ],
[ 2. , 1. ]])
classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
return datMat,classLabels
def showDataSet(dataMat, labelMat):
"""
数据可视化
Parameters:
dataMat - 数据矩阵
labelMat - 数据标签
Returns:
无
"""
data_plus = [] #正样本
data_minus = [] #负样本
for i in range(len(dataMat)):
if labelMat[i] > 0:
data_plus.append(dataMat[i])
else:
data_minus.append(dataMat[i])
data_plus_np = np.array(data_plus) #转换为numpy矩阵
data_minus_np = np.array(data_minus) #转换为numpy矩阵
plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1]) #正样本散点图
plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1]) #负样本散点图
plt.show()
dataArr,classLabels = loadSimpData()
showDataSet(dataArr,classLabels)
数据显示
弱分类器
使用单决策树 一个弱的分类器
"""
单层决策树分类函数
Parameters:
dataMatrix - 数据矩阵
dimen - 第dimen列,也就是第几个特征
threshVal - 阈值
threshIneq - 标志
Returns:
retArray - 分类结果
"""
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
#初始化retArray为1
retArray = np.ones((np.shape(dataMatrix)[0],1))
if threshIneq == 'lt':
#如果小于阈值,则赋值为-1
retArray[dataMatrix[:,dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:,dimen] > threshVal] = -1.0 #如果大于阈值,则赋值为-1
return retArray
"""
找到数据集上最佳的单层决策树
Parameters:
dataArr - 数据矩阵
classLabels - 数据标签
D - 样本权重
Returns:
bestStump - 最佳单层决策树信息
minError - 最小误差
bestClasEst - 最佳的分类结果
"""
def buildStump(dataArr,classLabels,D):
dataMatrix = np.mat(dataArr); labelMat = np.mat(classLabels).T
m,n = np.shape(dataMatrix)
numSteps = 10.0; bestStump = {}; bestClasEst = np.mat(np.zeros((m,1)))
#最小误差初始化为正无穷大
minError = float('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):
#大于和小于的情况,均遍历。lt:less than,gt:greater than
for inequal in ['lt', 'gt']:
#计算阈值
threshVal = (rangeMin + float(j) * stepSize)
#计算分类结果
predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)
#初始化误差矩阵
errArr = np.mat(np.ones((m,1)))
#分类正确的,赋值为0
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
dataArr,classLabels = loadSimpData()
D = np.mat(np.ones((5, 1)) / 5)
print(D)
bestStump,minError,bestClasEst = buildStump(dataArr,classLabels,D)
print('bestStump:\n', bestStump)
print('minError:\n', minError)
print('bestClasEst:\n', bestClasEst)
通过遍历,改变不同的阈值,计算最终的分类误差,找到分类误差最小的分类方式,即为我们要找的最佳单层决策树。这里lt表示less than,表示分类方式,对于小于阈值的样本点赋值为-1,gt表示greater than,也是表示分类方式,对于大于阈值的样本点赋值为-1。经过遍历,我们找到,训练好的最佳单层决策树的最小分类误差为0.2,就是对于该数据集,无论用什么样的单层决策树,分类误差最小就是0.2。这就是我们训练好的弱分类器。接下来,使用AdaBoost算法提升分类器性能,将分类误差缩短到0,看下AdaBoost算法是如何实现的。
使用AdaBoost提升分类器性能
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)
print("D:",D.T)
#计算弱学习算法权重alpha,使error不等于0,因为分母不能为0
alpha = float(0.5 * np.log((1.0 - error) / max(error, 1e-16)))
#存储弱学习算法权重
bestStump['alpha'] = alpha
#存储单层决策树
weakClassArr.append(bestStump)
print("classEst: ", classEst.T)
#计算e的指数项
expon = np.multiply(-1 * alpha * np.mat(classLabels).T, classEst)
D = np.multiply(D, np.exp(expon))
#根据样本权重公式,更新样本权重
D = D / D.sum()
#计算AdaBoost误差,当误差为0的时候,退出循环
aggClassEst += alpha * classEst
print("aggClassEst: ", aggClassEst.T)
#计算误差
aggErrors = np.multiply(np.sign(aggClassEst) != np.mat(classLabels).T, np.ones((m,1)))
errorRate = aggErrors.sum() / m
#误差为0,退出循环
print("total error: ", errorRate)
if errorRate == 0.0: break
return weakClassArr, aggClassEst
def adaClassify(datToClass,classifierArr):
"""
AdaBoost分类函数
Parameters:
datToClass - 待分类样例
classifierArr - 训练好的分类器
Returns:
分类结果
"""
dataMatrix = np.mat(datToClass)
m = np.shape(dataMatrix)[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
print(aggClassEst)
dataArr, classLabels =loadSimData()
weakClassArr, aggClassEst = adaBoostTrainDS(dataArr, classLabels)
print(adaClassify([[0,0],[5,5]], weakClassArr))
在第一轮迭代中,D中的所有值都相等。于是,只有第一个数据点被错分了。因此在第二轮迭代中,D向量给第一个数据点0.5的权重。这就可以通过变量aggClassEst的符号来了解总的类别。第二次迭代之后,我们就会发现第一个数据点已经正确分类了,但此时最后一个数据点却是错分了。D向量中的最后一个元素变为0.5,而D向量中的其他值都变得非常小。最后,第三次迭代之后aggClassEst所有值的符号和真是类别标签都完全吻合,那么训练错误率为0,程序终止运行。
最后训练结果包含了三个弱分类器,其中包含了分类所需要的所有信息。一共迭代了3次,所以训练了3个弱分类器构成一个使用AdaBoost算法优化过的分类器,分类器的错误率为0。一旦拥有了多个弱分类器以及其对应的alpha值,就可以进行测试、
五、总结AdaBoost的优缺点:
- 优点:泛化错误率低,易编码,可以应用在大部分分类器上,无参数调整。
- 缺点:对离群点敏感。
最近听了一个讲座关于知识图谱的,王教授提及到了这个算法~ 感觉在现在的实际应用上,这个算法还是很普遍的,但具体原理学的有些模糊