Adaboost算法简单实现

#encoding=utf-8
__author__ = 'freedom'

from numpy import *

def LoadData():
    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 StumnpClassify(dataMatrix,dimen,threshVal,threshIneq):
    '''
    本函数用于进行最简单分类
    :param dataMatrix: 数据集,要求是矩阵形式
    :param dimen: 选中的特征,以此特征进行划分
    :param threshVal: 选取划分的阈值
    :param threshIneq: 选取划分的不等式符号
    :return:分类的结果,数组形式
    '''
    retArray = ones((shape(dataMatrix)[0],1)) #生成返回数组,维度为(样例数*1)
    if threshIneq == 'lt':  #选取的不等式为小于等于
        retArray[dataMatrix[:,dimen] <= threshVal] = -1.0 #将所有小于等于阈值的值全部表位-1.0
    else:
        retArray[dataMatrix[:,dimen] > threshVal] = -1.0
    return retArray

def BuildStump(dataArr,labels,D):
    '''
    本函数用于产生一个简单的树桩分类器
    :param dataArr: 数据集。要求不一定为矩阵形式
    :param labels: 标签集,要求不一定为矩阵形式
    :param D: 权重
    :return:最优分类器,字典形式,包含最佳分类特征、阈值和不等式形式,最小误差和最优分类结果
    '''
    dataMat = mat(dataArr)
    labelMat = mat(labels).T #本函数中所有数据均要矩阵化,方便之后的比较工作
    m,n = shape(dataMat)
    numSteps = 10.0 #迭代次数
    bestStump = {}
    bestClassEst = mat(zeros((m,1)))
    minError = inf
    for i in range(n):    #本层循环是遍历所有的特征,选取误差最小的作为分类器
        rangeMin = dataMat[:,i].min()
        rangeMax = dataMat[:,i].max()
        stepSize = (rangeMax - rangeMin)/numSteps #迭代的阈值初始化
        for j in range(-1,int(numSteps)+1): #遍历所有离散的阈值
            for inequal in ['lt','gt']: #遍历两种不等式形式
                threshVal = rangeMin+float(j)*stepSize
                predictVal = StumnpClassify(dataMat,i,threshVal,inequal) #获得分类结果
                errArr = mat(ones((m,1)))
                errArr[predictVal == labelMat] = 0 #获得分类误差列向量,如果与标签不同,该项值为1
                weightError = D.T*errArr   #加权计算误差,获得的值是一个数,分类正确的数据权重减小,分类错误的数据权重增加,但是在某次寻找最优单分类器时D是保持不变的
                if weightError <= minError:
                    minError = weightError #更新误差
                    bestClassEst = predictVal.copy() #复制分类结果
                    bestStump['dim'] = i     #记录下最佳分类器的三个参数
                    bestStump['threshVal'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump,minError,bestClassEst

def AdaBoostTrainDS(dataArr,labels,numIt = 40):
    '''
    本函数用于AdaBoost学习
    :param dataArr: 数据集,不要求为矩阵形式
    :param labels: 标签集,不要求为矩阵形式
    :param numIt: 迭代次数,可自由设定,默认为40
    :return:所有弱分类器,列表形式,嵌套有所有弱分类器,字典形式,包含有有划分特征、阈值、不等式形式和alpha值四个参数
    '''
    weakClassArr = []
    m = shape(dataArr)[0]
    D = mat(ones((m,1))/m) # 初始化权重,平均分为m份,m为样例数,目的是对分类错误的样例加大权重,详见BuildStump函数
    aggClasssEst = mat(zeros((m,1)))
    for i in range(numIt): #迭代
        bestStump,error,classEst = BuildStump(dataArr,labels,D) # 获得弱分类器、分类误差和分类结果
        alpha = float(0.5*log((1.0-error)/max(error,1e-16))) # 计算alpha,这里1e-16是为了保证不会出现除零错误
        bestStump['alpha'] = alpha   # 这里的alpha值就是该弱分类器的权重
        weakClassArr.append(bestStump) # 将弱分类器加入列表
        expon = (multiply(-1*alpha*mat(labels).T,classEst))  # 更新权重,对于分类错误的要加大权重,分类正确的减小权重#注意,这里multiply应该是列向量的元素对应相乘
        #print D
        D = multiply(D,exp(expon))
        D = D/D.sum()
        aggClasssEst += alpha*classEst #计算叠加了当前弱分类器后的分类结果
        aggError = multiply(sign(aggClasssEst)!= mat(labels).T,ones((m,1))) #计算叠加当前分类器后的误差
        errorRate = aggError.sum()/m #计算误差率
        #print 'Error is ',errorRate,'\n'
        if errorRate == 0.0:break #如果误差率为0,则提前结束迭代循环
    return weakClassArr

def AdaClassify(dataSet,classifer):
    '''
    本函数用于分类
    :param dataSet: 数据集,不要求为矩阵形式
    :param classifer: 分类器,字典形式,应该是多个弱分类器的组合
    :return:类型
    '''
    dataMat = mat(dataSet) #数据集矩阵化
    m = shape(dataMat)[0]
    aggClassEst = mat(zeros((m,1)))
    for i in range(len(classifer)): #遍历所有的分类器
        ClassEst = StumnpClassify(dataMat,classifer[i]['dim'],classifer[i]['threshVal'],classifer[i]['ineq'])
        #应用每一个弱分类器分类
        aggClassEst += classifer[i]['alpha']*ClassEst#对每个弱分类器的结果加权求和
        #print aggClassEst
    return sign(aggClassEst)

def LoadBigData(filename):
    '''
    本函数用于加载大量数据
    :param filename: 数据文件名
    :return:数据集和标签集,均为列表形式
    '''
    numFeat = len(open(filename).readline().split('\t')) #获得特征数目
    dataSet = []
    labels = []
    fr = open(filename)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t') #去首尾空格,按制表符分割成字符串
        for i in range(numFeat-1):
            lineArr.append(float(curLine[i])) #读出的是字符串,要转换为浮点型
        dataSet.append(lineArr)
        labels.append(float(curLine[-1]))
    return dataSet,labels



trainData,trainLabels =LoadBigData('train.txt')
testData,testLabels = LoadBigData('test.txt')
classifer =  AdaBoostTrainDS(trainData,trainLabels,60)# 用数据集进行训练
predictValue = AdaClassify(testData,classifer) # 用测试数据观察分类
numTest = len(testLabels) # 获取测试数据数目
for i in range(len(predictValue)): # 比对预测数值和真实数值
    if predictValue[i] == testLabels[i]:
        print 'YES!'
    else:
        print 'No!'
errArr = mat(ones((numTest,1)))
errRate = errArr[predictValue != mat(testLabels).T].sum()/numTest #求误差率
print errRate
'''
d,l = LoadData()
AdaBoostTrainDS(d,l,numIt=40)
'''

你可能感兴趣的:(Adaboost算法简单实现)