AdaBoost算法分析与实现
Email:chentravelling@163.com
年前年后已经把AdaBoost看了两三遍,昨天花了两个小时用python实现了一下。因为对python不太熟,跟网上的的代码一比较就发现自己的代码是多么粗糙了。不过没关系了,慢慢来。
Boosting方法是一种常用的统计学习方法,其基于这样的一个思想:对于一个复杂任务来说,将多个专家的判断进行适当的综合所得出的判断,要比其中任何一个专家单独的判断要好——三个臭皮匠顶个诸葛亮。
Boosting涉及到两个概念:弱学习和强学习。弱学习:就是指一个学习算法对一组概念的识别率只比随机识别好一点,所谓强学习,就是指一个学习算法对一组概率的识别率很高。Kearns和Valiant提出了弱学习和强学习等价的问题 ,并证明了只要有足够的数据,弱学习算法就能通过集成的方式生成任意高精度的强学习方法。
对于我这个小菜鸟来说,看看这么一大段的流程还是有些晕,于是拿着李航的例子算了一笔:
对于python不熟悉,代码极其粗糙,见谅咯。
# -*- coding:utf-8 -*- # Author:code 陈 # Date:2016.02.21 from math import log,exp # 数据集 def createDataSet(): dataSet=[[0,1],[1,1],[2,1],[3,-1],[4,-1],[5,-1],[6,1],[7,1],[8,1],[9,-1]] weightSet=[0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1] return dataSet,weightSet # 选择最佳阈值 # return 误差率 阈值 def chooseBsetThreshold(dataSet,weightSet): length = len(dataSet) minError = 1 bestThreshold = 0 for i in range(0,length): error = [0,0] for j in range(0,length): if j<i: if dataSet[j][1]!=1:##0:阈值左侧为1,右侧为-1;1:阈值左侧为-1,右侧为1 error[0] = error[0] + weightSet[j] if dataSet[j][1]!=-1: error[1] = error[1] + weightSet[j] else: if dataSet[j][1]!=-1: error[0] = error[0] + weightSet[j] if dataSet[j][1]!=1: error[1] = error[1] + weightSet[j] if error[0]>error[1]: mer = error[1] index = 1; else: mer = error[0] index = 0 if minError > mer: minError = mer bestThreshold = dataSet[i][0] return minError,bestThreshold,index # 弱分类器 # param:数据、阈值、左侧为1?右侧为1? def weakClassifier(data,bestThreshold,index): if index ==0: if data<bestThreshold: return 1 else: return -1 else: if data<bestThreshold: return -1 else: return 1 # 更新权值 def updateWeightSet(minError,dataSet,weightSet,bestThreshold,index): alpha =float( 0.5*log((1-minError)/max(minError,1e-16))) print alpha newWeightSet = [] Z = 0 for i in range(0,len(dataSet)): Z = Z + weightSet[i]*exp(-alpha*dataSet[i][1]*weakClassifier(dataSet[i][0],bestThreshold,index)) for j in range(0,len(dataSet)): newWeightSet.append(weightSet[j]/Z*exp(-alpha*dataSet[j][1]*weakClassifier(dataSet[j][0],bestThreshold,index))) return newWeightSet,alpha # 验证错误分类点个数 def countErr(weakClassifierArr,dataSet): n = 0 for i in range(0,len(dataSet)): G = 0 for j in range(0,len(weakClassifierArr)): G = G + weakClassifierArr[j]['alpha']*weakClassifier(dataSet[i][0],weakClassifierArr[j]['threshold'],weakClassifierArr[j]['index']) if G * dataSet[i][1] <0:#异号就可以了,没有用sign函数 n = n + 1 return n # AdaBoost def AdaBoost(dataSet,weightSet,M): weakClassifierArr = []#存弱分类器 G = 0 for i in range(0,M): weakClassE = {} minError,bestThreshold,index = chooseBsetThreshold(dataSet,weightSet) print minError,\ bestThreshold,\ index weightSet,alpha = updateWeightSet(minError,dataSet,weightSet,bestThreshold,index) weakClassE['threshold']=bestThreshold weakClassE['index']= index weakClassE['alpha'] = alpha weakClassifierArr.append(weakClassE) print countErr(weakClassifierArr,dataSet) print weightSet if countErr(weakClassifierArr,dataSet) ==0: #print weakClassifierArr break return weakClassifierArr if __name__=='__main__': dataSet,weightSet = createDataSet() weakClassifierArr = AdaBoost(dataSet,weightSet,6)
最终得到的分类器:
[{'threshold': 3, 'index': 0, 'alpha': 0.4236489301936017}, {'threshold': 9, 'index': 0, 'alpha': 0.6496414920651304}, {'threshold': 6, 'index': 1, 'alpha': 0.752038698388137}]
关于弱分类器G,一开始我也没懂,到底改怎么去选择,后来查了一下网上的资料,大部人提到了CART、SVM、回归等等都可以作为弱分类。
例子中的训练数据是一维的,如果是多维的呢?查了一下资料,结果为:每次在多维中选择带权分类误差值最小的一维,然后在该维度下选择带权分类误差最小的阈值,绕了半天,这一点自己倒还没去实现过。
代码可能还有问题,原理上可能也还存在认知问题,后面再慢慢调整理解。