AdaBoost算法及其应用
1.集成方法
集成方法是将不同的分类器组合在一起将测试数据集进行分类的方法,可以是不同算法的集成或是同一算法在不同设置下的集成,也可以将数据集不同部分分配给不同分类器的集成。集成方法主要包括bagging和boosting两种方法,而AdaBoost算法是基于boosting思想的机器学习算法。
2.boosting介绍
boosting所使用的多个分类器类型都是一致的,根据被已有1分类器错分的那些数据来获得新的分类器。boosting分类的结果是基于所有分类器的加权求和结果的,所以分类器的权重并不相等,每个权重代表的是其对应分类器在上一轮迭代中的成功度。
3.AdaBoost介绍
AdaBoost的流程如下:
首先需要给训练数据中的每个样本都要赋予一个权重,这些权重构成了向量D,在算法的最开始,D向量中每个值都是相等的。再通过训练数据训练出分类器,但此时的分类器是弱分类器,不会满足我们的需求,这里可以得到每个分类器的错误率。根据第一次得到的错误率,我们可以更新每一个样本的权重,第一次分对的样本的权重会降低,分错的样本的权重会提高。Adaboost算法也给了每个分类器分配了权重alpha,alpha值的更新也是根据错误率进行计算。
错误率:
分类器权重alpha:
正确分类的样本权重:
错误分类的样本权重:
其中i代表第i个样本,t代表第t次的分类。
Adaboost算法流程如下:
将输出结果代入下一次迭代,直到训练错误率为0或者分类器的个数达到了用户的规定,Adaboost算法结束。
4.Adaboost具体实现(python3)
我们选择单层决策树作为Adaboost的弱分类器:
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):#just classify the data
retArray = ones((shape(dataMatrix)[0],1))
if threshIneq == 'lt':
retArray[dataMatrix[:,dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:,dimen] > threshVal] = -1.0
return retArray
def buildStump(dataArr,classLabels,D):
dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
m,n = shape(dataMatrix)
numSteps = 10.0; bestStump = {}; bestClasEst = mat(zeros((m,1)))
minError = inf #init error sum, to +infinity
for i in range(n):#loop over all dimensions
rangeMin = dataMatrix[:,i].min(); rangeMax = dataMatrix[:,i].max();
stepSize = (rangeMax-rangeMin)/numSteps
for j in range(-1,int(numSteps)+1):#loop over all range in current dimension
for inequal in ['lt', 'gt']: #go over less than and greater than
threshVal = (rangeMin + float(j) * stepSize)
predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)#call stump classify with i, j, lessThan
errArr = mat(ones((m,1)))
errArr[predictedVals == labelMat] = 0
weightedError = D.T*errArr #calc total error multiplied by D
#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
函数stumpClassify是通过阈值比较对数据进行分类,分为-1和+1。
函数buildStump会返回一个错误率最小的单层决策树,在这里是用字典来进行存储。
Adaboost训练过程:
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
weakClassArr = []
m = shape(dataArr)[0]
D = mat(ones((m,1))/m) #init D to all equal
aggClassEst = mat(zeros((m,1)))
for i in range(numIt):
bestStump,error,classEst = buildStump(dataArr,classLabels,D)#build Stump
#print "D:",D.T
alpha = float(0.5*log((1.0-error)/max(error,1e-16)))#calc alpha, throw in max(error,eps) to account for error=0
bestStump['alpha'] = alpha
weakClassArr.append(bestStump) #store Stump Params in Array
#print "classEst: ",classEst.T
expon = multiply(-1*alpha*mat(classLabels).T,classEst) #exponent for D calc, getting messy
D = multiply(D,exp(expon)) #Calc New D for next iteration
D = D/D.sum()
#calc training error of all classifiers, if this is 0 quit for loop early (use break)
aggClassEst += alpha*classEst
#print "aggClassEst: ",aggClassEst.T
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
errorRate = aggErrors.sum()/m
print "total error: ",errorRate
if errorRate == 0.0: break
return weakClassArr
weakClassArr返回的就是满足要求的分类器。
基于Adaboost分类器进行分类:
def adaClassify(datToClass,classifierArr):
dataMatrix = mat(datToClass)#do stuff similar to last aggClassEst in adaBoostTrainDS
m = shape(dataMatrix)[0]
aggClassEst = mat(zeros((m,1)))
for i in range(len(classifierArr)):
classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],\
classifierArr[i]['thresh'],\
classifierArr[i]['ineq'])#call stump classify
aggClassEst += classifierArr[i]['alpha']*classEst
print aggClassEst
return sign(aggClassEst)
返回分类结果
5.用Adaboost算法来预测森林火灾的发生
数据来源:http://archive.ics.uci.edu/ml/machine-learning-databases/forest-fires/
1.问题与数据阐述
根据数据集,来预测森立火灾的发生与否。
数据类型:标称型和数值型
数据样本:
X:代表森林区域的横坐标,范围是1-9
Y:代表森林区域的纵坐标,范围是1-9
month:代表月份
day:代表一星期中的周几
FFMC:FWI系统中的一项数据(具体是啥我也不知道...应该是跟火灾密切相关的数据。),范围是18.7-96.2
DMC:FWI系统中的一项数据,范围是1.1-291.3
DC:FWI系统中的一项数据,范围是7.9-860.6
ISI:FWI系统中的一项数据,范围是0.0-56.1
temp:摄氏度,范围是2.2-33.3
RH:相对湿度,范围是15%-100%
wind:风速,单位:km/h,范围是0.4-9.4
rain:单位面积降水量,单位:mm/平方米,范围是0-6.4
area:森林火灾区域面积,单位:ha,范围是0-1090.84
2.数据预处理
数据集中每个样本特征并不是都影响到最后的分类结果,首先认为判断month与day这两项与火灾发生没有关联,将这2项特征排除。在审查数据集,发现rain这一项的值只有极少数样本不为0,可以判断这一项对分类也没有影响。
最关键的一点是,area的数据不是只有两种值(当然该数据集应该是用来判断火灾面积= =!,我这里为了使用Adaboost算法,只好改成分类问题),应该人为处理将area的值变成有且只有两种值。在这里,我们将area等于0的样本,area赋值为1,其余样本的area,赋值为-1。这样就能判断火灾是否发生。
数据集没有缺失项。
3.Adaboost训练及预测
读取数据集的代码如下:
def loadDataSet(fileName): #general function to parse tab -delimited floats
num = len(open(fileName).readlines()) #get number of dataset
#print("DataSet Num: ",num)
dataMat = []; labelMat = []
fr = open(fileName)
for line in fr.readlines():
lineArr =[]
curLine = line.strip().split('\t')
curLine.pop(2)
curLine.pop(2)
curLine.pop(-2)
if(curLine[-1]=='0'):
curLine[-1]='1';#no fires
else:
curLine[-1]='-1';#fires
numFeat=len(curLine)
for i in range(numFeat-1):
lineArr.append(float(curLine[i]))
dataMat.append(lineArr)
labelMat.append(float(curLine[-1]))
return dataMat,labelMat
计算预测错误率的代码如下:
def errArr(pre,testLabelArr):
errArr=mat(ones((253,1)))
err=errArr[pre!=mat(testLabelArr).T].sum()
#print(err/253)
return err/253
ROC曲线绘图代码如下:
def plotROC(predStrengths, classLabels):
import matplotlib.pyplot as plt
cur = (1.0,1.0) #cursor
ySum = 0.0 #variable to calculate AUC
numPosClas = sum(array(classLabels)==1.0)
yStep = 1/float(numPosClas); xStep = 1/float(len(classLabels)-numPosClas)
sortedIndicies = predStrengths.argsort()#get sorted index, it's reverse
fig = plt.figure()
fig.clf()
ax = plt.subplot(111)
#loop through all the values, drawing a line segment at each point
for index in sortedIndicies.tolist()[0]:
if classLabels[index] == 1.0:
delX = 0; delY = yStep;
else:
delX = xStep; delY = 0;
ySum += cur[1]
#draw line from cur to (cur[0]-delX,cur[1]-delY)
ax.plot([cur[0],cur[0]-delX],[cur[1],cur[1]-delY], c='b')
cur = (cur[0]-delX,cur[1]-delY)
ax.plot([0,1],[0,1],'b--')
plt.xlabel('False positive rate'); plt.ylabel('True positive rate')
plt.title('ROC curve for AdaBoost forestfires')
ax.axis([0,1,0,1])
plt.show()
print("the Area Under the Curve is: ",ySum*xStep)\
训练数据集样本数量:264
预测数据集样本数量:253
第一次设置分类器的数量为20:
训练好的分类器的错误率:
预测时得到的错误率:
ROC曲线:
可以看出,预测的错误率很高,需要更改分类器数量。
第二次设置分类器数量为30:
训练好的分类器的错误率:
预测时得到的错误率:
ROC曲线:
结果还是不理想...
为了找出最小的错误率,编写代码,循环代入不同的分类器数量来寻找:
def Circuit(fileName1,fileName2,num1,num2):
datArr,labelArr=loadDataSet(fileName1)
for i in range(num1,num2,10):
classifierArray,aggClassEst=adaBoostTrainDS(datArr,labelArr,i)
testArr,testLabelArr=loadDataSet(fileName2)
pre=adaClassify(testArr,classifierArray)
print("i=%d ,errRate=%f" %(i,errArr(pre,testLabelArr)))
其中,fileName1是训练数据集的名称,fileName2是预测数据集的名称,分类器数量下界为num1,上界为num2,每次取值的间隔为10。
可以看到当分类器数目为750时,得到的错误率最小。
ROC曲线如下:
6.总结
在进行森林火灾预测时,正确率不高,还在查找原因。
参考文献:《机器学习实战》
上一篇: 恶搞 关于毒校服的神回答
下一篇: KMP算法及其应用