写在开头
最近在学习一些关于机器学习的基础算法,结合学习Peter Harrington的《机器学习实战》和李航老师的《统计学习方法》两本书以及网上前辈的笔记,写下了以下的学习过程。
代码环境:Pytharm/Python3.7
内容有参考也有自己的想法,由于自己的理解不足,文章肯定存在很多错误,还恳请各位批评指正。
1. 个人对算法的理解
这张图片清晰的给出了AdaBoost算法的思想,首先构建弱分类器,并且计算出该分类器的错误率。然后再在同一数据集上再次训练弱分类器,在分类器的第二次训练当中,将会重新调整每个样本的权重,其中第一次分对的样本的权重将会降低,而第一次分错的样本的权重将会提高,这样分类结果会逐步提高。然后AdaBoost为每一个分类器都分配一个权重值alpha,就是图中三角框中的值,这些alpha值是基于每个弱分类器的错误率进行计算的。越大说明错误率越低,分类结果越可信。最后就根据这些弱分类器的分类结果及所占权重得到最后的分类结果。
2. AdaBoost算法实现源码(简单数据测试)
import numpy
import math
# -----整个就是在构建一个单层决策树,构建弱分类器---------
def loadSimpData():
datMat = numpy.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
# --------函数将用于测试是否有某个值小于或者大于我们正在测试的阈值-----
# 四个参数分别是(输入矩阵,第几列,阈值,lt或gt)threshIneq决定了不等号是大于还是小于
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
predictedVals = numpy.ones((numpy.shape(dataMatrix)[0], 1))
if threshIneq == "lt":
predictedVals[dataMatrix[:, dimen] <= threshVal] = -1.0 # 注意比较元素大小,符合不等式条件则赋值
else:
predictedVals[dataMatrix[:, dimen] > threshVal] = -1.0
return predictedVals
def buildStump(dataArr, classLabels, D):
dataMatrix = numpy.mat(dataArr)
labelMat = numpy.mat(classLabels).T
row, column = numpy.shape(dataMatrix)
numSteps = 10.0 # 变量numSteps用于在特征的所有可能值上进行遍历
bestStump = {} # 字典用于存储给定权重向量D时所得到的最佳单层决策树的相关信息
bestClasEst = numpy.mat(numpy.zeros((row, 1)))
minError = math.inf # 一开始就初始化成正无穷大,之后用于寻找可能的最小错误率
for i in range(column): # 在数据集的所有特征上遍历1/2
# 通过计算最小值和最大值来了解应该需要多大的步长
rangeMin = dataMatrix[:, i].min() # 第i列全部元素最小值
rangeMax = dataMatrix[:, i].max() # 第i列全部元素最大值
stepSize = (rangeMax - rangeMin) / numSteps # 步长
for j in range(-1, int(numSteps) + 1): # J:-1-10?
for inequal in ['lt', 'gt']:
threshVal = (rangeMin + float(j) * stepSize) # 阈值
predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)
errArr = numpy.mat(numpy.ones((row, 1))) # 列向量
errArr[predictedVals == labelMat] = 0 # 难道真的能够通过这种方式比较数组内部元素嘛?是的!
weightedError = D.T * errArr # calc total error multiplied by D
if weightedError < minError:
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = i # 选择最好的特征
bestStump['thresh'] = threshVal # 最好的阈值?
bestStump['ineq'] = inequal # 最好的不等方式?
# 返回最佳单层决策树,最小错误率,类别估计值
return bestStump, minError, bestClasEst
# --------------------------利用AdaBoost算法提高分类性能---------------------
def adaBoostTrainDS(dataArr, classLabels, numIt=40):
weakClassArr = []
row = numpy.shape(dataArr)[0]
D = numpy.mat(numpy.ones((row, 1)) / row)
aggClassEst = numpy.mat(numpy.zeros((row, 1)))
for i in range(numIt):
bestStump, error, classEst = buildStump(dataArr, classLabels, D)
print("D:{}".format(D.T))
alpha = float(0.5 * numpy.log((1 - error) / max(error, 1e-16))) # alpha的计算公式,《机器学习实战》136页
bestStump['alpha'] = alpha
weakClassArr.append(bestStump)
print("classEst:{}".format(classEst.T))
# 《机器学习实战》137页公式不是直接用alpha吗?
# 为下一次迭代,计算D
expon = numpy.multiply(-1 * alpha * numpy.mat(classLabels).T, classEst)
# 正常相乘都是没有问题的,问题在于进行exp()操作时,必须使用vectorize矢量化
# 因为指数,不能直接对矩阵进行指数操作,我们想当然的认为是对每个矩阵,但是其实不是
# 所以,必须vectorize矢量化,才能认为对每个元素进行指数操作
# 但是刚刚试了直接exp居然成功了
D = numpy.multiply(D, numpy.exp(expon))
D = D / D.sum()
aggClassEst += alpha * classEst
print("aggClassEst:{}".format(aggClassEst.T))
aggErrors = numpy.multiply(numpy.sign(aggClassEst) != numpy.mat(classLabels).T, numpy.ones((row, 1)))
errorRate = aggErrors.sum() / row
print("total error:{}".format(errorRate))
if errorRate == 0.0:
break
return weakClassArr
# AdaBoost分类函数
def adaClassify(datToClass, classiferArr):
dataMatrix = numpy.mat(datToClass)
row = numpy.shape(dataMatrix)[0]
aggClassEst = numpy.mat(numpy.zeros((row, 1)))
for i in range(len(classiferArr)):
classEst = stumpClassify(dataMatrix, classiferArr[i]["dim"], classiferArr[i]["thresh"], classiferArr[i]["ineq"])
aggClassEst += classiferArr[i]['alpha'] * classEst
print(aggClassEst)
return numpy.sign(aggClassEst)
def main():
datMat, classLabels = loadSimpData()
weakClassArr = adaBoostTrainDS(datMat, classLabels, numIt=40)
print(weakClassArr)
#输入[0,0]测试数据,输出分类结果
print(adaClassify([0, 0], weakClassArr))
if __name__ == '__main__':
main()
参考文档:
[1]《机器学习实战》第七章
[2]《统计学习方法》李航