不同的分类器进行集成组合被称为集成方法或者元方法,可以是不同算法的集成,也可以是同一种算法的集成,也可以是数据集的不同部分分给不同分类器的集成

Bagging方式:

自举汇聚法(bootstrap aggregating),也称为bagging方法,N个训练集中随机选N次构成一个新的N个训练集,这样就可以基于一份训练数据随机造出任意多份的新的训练集,当然每份训练集中都很大概率有重复数据。然后基于新的训练集训练出的结果,进行民主投票,票高者当选。

随机森林(random forest),是bagging方法的进化版,

用随机的方式建立一个森林,森林里面有很多的决策树组成,随机森林的每一棵决策树之间是没有关联的。在得到森林之后,当有一个新的输入样本进入的时候,就让森林中的每一棵决策树分别进行一下判断,看看这个样本应该属于哪一类(对于分类算法),然后看看哪一类被选择最多,就预测这个样本为那一类

随机森林在生成训练集时除了对样本行进行随机回放外,还会随机选择特性,换句话说每片森林对特性的侧重点又是不同的。

Boosting方式:

与bagging很类似的技术。不论是在boosting还是bagging当中,所使用的多个分类器的类型都是一致的。但是Boosting中不同的分类器是通过串行训练而获得的,每个新分类器都根据已训练出的分类器的性能来进行训练。最终的选择也不是基于投票,而是基于权重结果累加。

AdaBoost:每个训练集初始赋值一个平等的权重,随着每个弱分类器的迭代,被分错的样本的权重会增高,被分对的样本的权重会降低,经过不断迭代最终训练出100%正确的权重或者达到阈值终止。

迭代过程如下:

错误率:

参数α:

正确的权重调整:

错误的权重调整:

对比:

再回头对比下Bagging方式和Boosting方式,前者的优点是相对简单而且支持并发;后者的优点是训练集稳定结果可信度更高。最终又变成了一个性能与准确度的平衡择取问题。

单层决策树(decision stump,也称决策树桩)是一种简单的决策树,它仅基于单个特征来做决策。例如训练集有N个特性,只取其中一个特性来作为所有特性的拆分规则。

单层决策树python代码:

#构造简单训练集
def loadSimpleData() :dataMat = matrix([[1.0,2.1],[2.0,1.1],[1.3,1.0],[1.0,1.0],[2.0,1.0]])classLabel = [1.0,1.0,-1.0,-1.0,1.0]return dataMat,classLabel#根据第dimen个特性对threshVal做比较给出的预测结果
def stumpClassify(dataMat,dimen,threshVal, threshIneq) :retArray = ones((shape(dataMat)[0],1))if threshIneq == 'lt':retArray[dataMat[:,dimen] <= threshVal] = -1.0else :retArray[dataMat[:, dimen] > threshVal] = -1.0return retArray#D为初始权重
#dataArr为训练集
#classLabels为结果集
#该函数是按照单一特性某个值去判断,如何得到最小错误率
def buildStump(dataArr, classLabels,D):dataMat = mat(dataArr)labelMat = mat(classLabels).transpose()m,n = shape(dataMat)numSteps = 10.0bestStump = {}bestClasEst = mat(zeros((m,1)))#最小错误率初始化为无穷大minError = inf#第一个循环,遍历特性for i in range(n) :#取每列的最大和最小值rangeMin = dataMat[:,i].min()rangeMax = dataMat[:,i].max()#拆分成10块stepSize = (rangeMax-rangeMin)/numSteps#第二个循环,遍历特性的值for j in range(-1,int(numSteps)+1) :#第三个循环,遍历大小for inequal in ['lt','gt'] :threshVal = (rangeMin+float(j)*stepSize)predictedVals = stumpClassify(dataMat,i,threshVal,inequal)errArr = mat(ones((m,1)))#相等的被清零,剩下的都是预测错误的,默认值为1errArr[predictedVals==labelMat] = 0weightedError = 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 = weightedErrorbestClasEst = predictedVals.copy()bestStump['dim'] = ibestStump['thresh'] = threshValbestStump['ineq'] =  inequalreturn bestStump, minError, bestClasEst

现在有了单决策树这个弱学习器,试下学习效果:

D = mat(ones((5,1))/5)
dataMat,classLabel = loadSimpleData()
bestStump, minError, bestClasEst = buildStump(dataMat,classLabel,D)
print(bestStump)
print(minError)
print(bestClasEst)

结果是:

{'dim': 0, 'thresh': 1.3, 'ineq': 'lt'}
[[ 0.2]]
[[-1.][ 1.][-1.][-1.][ 1.]]

有80%的成功率,貌似还不错,下面我们用集成方式把它改造成一个AdaBoosting强学习器,添加一个集成函数:

#整个函数体有2个动态变化的参数,D和alpha。
#D代表每轮测评时每条数据的权重
#alpha代表每轮测评时当前轮次对最终结果影响的权重
def adaBoostTrainDs(dataArr, classLabels, numIt=40) :weakClassArr = []m = shape(dataArr)[0]#动态的权重D = mat(ones((m,1))/m)#累计估计值,对结果集多次累计估算的结果aggClassEst = mat(zeros((m,1)))for i in range(numIt) :bestStump, error, classEst = buildStump(dataArr, classLabels, D)print('D: ',D.T)#套公式,1e-16是为了防止除0alpha = float(0.5*log((1.0-error)/max(error,1e-16)))print('Alpha: ', alpha)bestStump['alpha'] = alphaweakClassArr.append(bestStump)print('classEst: ',classEst)#套公式expon = multiply(-1*alpha*mat(classLabels).T, classEst)D = multiply(D,exp(expon))D = D/D.sum()#更新累计估计值,alpha影响本次测评aggClassEst +=alpha*classEstprint('aggClassEst: ',aggClassEst.T)aggErrors = multiply(sign(aggClassEst)!=mat(classLabels).T,ones((m,1)))errorRate = aggErrors.sum()/mprint('total error is :',errorRate)if errorRate==0.0 : breakreturn weakClassArr

这里会产出一个weakClassArr,这个就是集成的产出,里面包含了每轮的弱学习器已经结果占据的权重。

我们给出强学习器的预测函数:

#对测试数据进行评估
def adaClassify(datToClass, classifierArr):dataMat = mat(datToClass)m = shape(dataMat)[0]#累计预计结果aggClassEst = mat(zeros((m,1)))for i in range(len(classifierArr)) :classEst = stumpClassify(dataMat,classifierArr[i]['dim'],classifierArr[i]['thresh'],classifierArr[i]['ineq'])aggClassEst += classifierArr[i]['alpha']*classEstreturn sign(aggClassEst)

预测函数使用如下:

dataMat,classLabel = loadSimpleData()
weakClassArr = adaBoostTrainDs(dataMat,classLabel,10)
print(weakClassArr)
print(adaClassify([[0,1],[3,4]],weakClassArr))

前面《Logistic回归(2)》预测过疝气马死亡的概率,当时用的是Logistic回归方法,现在用AdaBoosting强分类器再试下:

代码:

#加载训练集和结果集
def loadDataSetByfile(fineName) :numFeat = len(open(fineName).readline().split('\t'))dataMat = []labelMat = []fr = open(fineName)for line in fr.readlines():lineArray = []curline = line.strip().split('\t')for i in range(numFeat-1) :lineArray.append(float(curline[i]))dataMat.append(lineArray)labelMat.append(float(curline[-1]))return dataMat,labelMatdataMat,labelMat = loadDataSetByfile('C:\\2017\\提高\\机器学习\\训练样本\\horseColicTraining2.txt')
weakClassArr=adaBoostTrainDs(dataMat,labelMat,10)
dataMat,labelMat = loadDataSetByfile('C:\\2017\\提高\\机器学习\\训练样本\\horseColicTest2.txt')
predict=adaClassify(dataMat,weakClassArr)
errArr = mat(ones((67,1)))
errRate = errArr[predict!=mat(labelMat).T].sum()/67
print(errRate)
adaBoostTrainDs中的numInt代表了弱学习器的数目,numInt的不同测试结果也不同,结果如下:

现测试错误率在达到了一个小值之后又开始上升了。这类现象称之为过拟合(overfitting,也称过度学习)

可以看到这里的最高的正确率达到了80%,比前面评估的63%好些。

非均衡分类器:

是不是错误率越低,实际效果就越好?非也,因为我们没有考虑错误引起的代价,换句话说没有考虑到结果的权重。例如大数据分析一个人是否是死刑,一旦预判错了,错放了坏人还好说,如果错杀了好人真心无法挽回。

有什么办法可以再进行一下干预或者优化么?

1 利用正确率、召回率、ROC曲线等其它参数:

混淆矩阵(confusion matrix),描述了样例如何被分错的事实,帮助人们更好地了解分类中的错误。

三类问题混淆矩阵案例:

红框的意思是有4次把鼠预测称狗,整体看来这个预测结果还算靠谱,大部分都可以预测的对,完美的结果是非对角元素都为0.

二类问题混淆矩阵:

TP;又叫真阳;FN又叫假阴;FP又叫假阳;TN又叫真阴

假如还是大数据分析罪犯的问题,上面+1代表有罪,-1代表无罪,给出两个概念:

正确率=TP/(TP+FP), 判处有罪的样本中真正有罪的概率。1-正确率就是你刀下魂误杀的概率。

召回率=TP/(TP+FN),真正有罪的人被我们预测出来的概率。1-召回率也就是在你刀下漏网的概率。

能否给出一种分类器让正确率和召回率都趋于完美呢?结果是不可能的。

你判的严了,宁可错杀100也不放跑一人,召回率会变得非常高趋于100%,因为漏网之鱼少了么,真正犯法的都被你弄死了,但是很可能就会造成冤假错案多死几个鬼,导致正确率下降。

你判的松了,你好我好大家好,好人不再被冤枉了,正确率变高,但是漏网之鱼就会变多,召回率就会下降。

另一个度量非均衡分类器的曲线是ROC曲线

Y向量代表真阳率=TP/(TP+FN)

X左标代表假阳率=FP/(FP+TN)

下面给出ROC图的代码:

def plotROC(predStrengths, classLabels) :import matplotlib.pyplot as plt#绘图光标的位置cur = (1.0,1.0)ySum = 0.0numPosClas = sum(array(classLabels)==1.0)#y为真阳,yStep为y轴步长yStep = 1/float(numPosClas)# x为假阳,xStep为x轴步长xStep = 1/float(len(classLabels)-numPosClas)#从小到大排序classLabels的索引sortedIndicies = predStrengths.argsort()fig = plt.figure()fig.clf()ax = plt.subplot(111)l=len(sortedIndicies.tolist()[0])#注意由于cur光标初始在右上角,所以下面绘画是从右上往左下画for index in sortedIndicies.tolist()[0] :if classLabels[index]==1.0 :delX = 0#下降一步真阳率,why?#因为在起笔的时候绘图标在(1,1)delY = yStepelse :#下降一步假阴率,why?delX = xStepdelY=0ySum +=cur[1]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')plt.ylabel('True positive')plt.title('ROC')ax.axis([0,1,0,1])plt.show()#面积本质上是个概率print('面积为:',ySum*xStep)

代码注释留下两个why,我当时也想了很久,终于想明白了答案:

起笔阶段绘图光标在(1,1),代表真阳率和假阳率都是100%,设想什么情况下这俩值都是100%?对了,就是我们将所有结果都判断为真,这样FN和TN都等于0.后面判断的代码就好理解了,if classLabel==1说明我们判断正确了,属于TP,所以真阳率就提高一点。什么?代码里命名是减号为什么这里说是提高?因为我们最终判断效果是通过AUC,x*y的面积,假设没有任何算法瞎猜,那么面积基本就是0.5,也就是图中中间的虚线成功率50%。最然上面情况x在缩减,但是x先左方向位移代表的是最终面积增大的趋势!。最理想的结果是x最终移动到(0,1)左标,x从1降为0,但是面试变成了1,成功率100%!同理,if classLabel==-1说明我们判断错误了,属于FP,y的下降就天经地义了,因为要减少面积。极端情况x一点都没有往右移,y降到了底,说明我们全预测错了嘛,面积为0,概率也变成了0.

numInt输入10,AUC为0.8582969635063604

numInt输入40,AUC为0.8953941870182941

2 引入代价函数

还是利用上面法官断案的案例,引入一个代价矩阵:

如果一个犯人漏网了,代价是1;如果一个好人被放了,代价是0;如果一个犯人被绳之以法了,大快人心,-5标识对算法的奖励;如果一个好人被冤枉了,这个是万万不行的,所以代价最高为50.通过不同的代价,给算法掺杂了“情感干预”,让某些情况的权重发生变化,就可以选择“最小代价分类器”了。

在很多方法中,例如AdaBoost中调整错误权重的D,朴素贝叶斯中最终的返回结果采用最小代价而不是最大概率,SVM中根据代价参数对不同类别选择不同的松弛度C,K-近邻中最终返回的投票改成最小代价,这些做法都可以给算法夹杂人类的干预进去使其变得更有“感情”

分类器集成和非均衡分类相关推荐

  1. 随机森林-集成学习方法(分类)

    随机森林-集成学习方法(分类) 1 集成学习方法 集成学习通过建立几个模型组合的来解决单一预测问题.它的工作原理是生成多个分类器/模型,各自独立地学习和作出预测.这些预测最后结合成单预测,因此优于任何 ...

  2. 机器学习中的非均衡分类问题

    非均衡分类问题是指在分类器训练时,正例数目和反例数目不相等(相差很大),或者错分正反例导致的代价不同(可从代价矩阵观测)时存在的问题. 而大多数情况下,不同类别的分类代价并不相等,而诸如信用卡欺诈等场 ...

  3. R语言基于Bagging算法(融合多个决策树)构建集成学习Bagging分类模型、并评估模型在测试集和训练集上的分类效果(accuray、F1、偏差Deviance):Bagging算法与随机森林对比

    R语言基于Bagging算法(融合多个决策树)构建集成学习Bagging分类模型.并评估模型在测试集和训练集上的分类效果(accuray.F1.偏差Deviance):Bagging算法与随机森林对比 ...

  4. KNN分类器、最近邻分类、KD树、KNN分类的最佳K值、基于半径的最近邻分类器、KNN多分类、KNN多标签分类、KNN多输出分类、KNN分类的优缺点

    KNN分类器.最近邻分类.KD树.KNN分类的最佳K值.基于半径的最近邻分类器.KNN多分类.KNN多标签分类.KNN多输出分类.KNN分类的优缺点 目录

  5. ML之分类预测之ElasticNet:利用ElasticNet回归对二分类数据集构建二分类器(DIY交叉验证+分类的两种度量PK)

    ML之分类预测之ElasticNet:利用ElasticNet回归对二分类数据集构建二分类器(DIY交叉验证+分类的两种度量PK) 目录 输出结果 设计思路 核心代码 输出结果 设计思路 核心代码 # ...

  6. 分类器MNIST交叉验证准确率、混淆矩阵、精度和召回率(PR曲线)、ROC曲线、多类别分类器、多标签分类、多输出分类

    本博客是在Jupyter Notebook下进行的编译. 目录 MNIST 训练一个二分类器 使用交叉验证测量精度 混淆矩阵 精度和召回率 精度/召回率权衡 ROC曲线 多类别分类器 错误分析 多标签 ...

  7. 集成学习——Adaboost分类

    https://www.toutiao.com/a6674839167580504587/ 上一期分享了集成学习之Bagging分类的方法,这一期分享它的另外一种方法,Adaboost分类方. Ada ...

  8. python训练opencb分类器_垃圾邮件分类.ipynb

    { "cells": [ { "cell_type": "markdown", "metadata": {}, &quo ...

  9. python朴素贝叶斯的文本分类_自给自足,完全手写一个朴素贝叶斯分类器,完成文本分类...

    Part 1: 本文解决的问题: 我在有这样的一个数据集,里面存放了人们对近期播放电影的评价,当然评价也就分成两部分,好评和差评.我们想利用这些数据训练一个模型,然后可以自动的对影评做出判断,到底是好 ...

  10. 听霍强老师讲模式分类器设计的最小分类误差训练(MCE)

    我们非常荣幸请到微软亚洲研究院的霍强老师来为我们MSRA-USTC联合培养班带来第三场前沿讲座.首先简单介绍下霍老师,霍强老师是科大826的大牛级人物,87年本科毕业获得郭沫若奖学金,此后两年在浙大读 ...

最新文章

  1. Project evaluation failed including an error in afterEvaluate {}. Run with --stacktrace for details
  2. Django DTL模板语法中的循环
  3. git之工作区、版本区、远程仓库之间相互操作
  4. Linux学习之遇到的小问题---查看系统版本,虚拟机创建共享文件夹,用到的命令记录。
  5. 这么奇葩搞笑的代码注释你见过吗
  6. DOM相关(主要是var和let的区别用法)
  7. nagios监控mysql服务_nagios监控mysql及邮件报警
  8. 【Python成长之路】机器学习:10+分类算法汇总学习
  9. jquery modile 笔记
  10. POJ3982 序列【大数】
  11. c语言英文单词倒着,C语言实现英文单词助手
  12. HDU3746 Cyclic Nacklace KMP求循环节
  13. dockerfile制作docker镜像
  14. 音响发烧友---HiFi音频功放
  15. LOJ-10102(求A到B之间的割点)
  16. 字典的添加、更新、修改
  17. coreldraw2023安装教程及新功能讲解
  18. Control-Freec:检测拷贝数变异的神器
  19. 多重for循环优化,提升运行效率
  20. LTE Phich 分析

热门文章

  1. python利用公式计算_python利用公式计算π的方法
  2. 删除word文档中的空白页
  3. Java实现微信公众号授权登录
  4. python处理pdf实例_详解Python使用PDFMiner解析PDF实例
  5. 三极管单级放大器输入输出阻抗
  6. linux 循环while,linux命令:while循环
  7. Unity中的Compute Shader
  8. SuperMap iObject入门开发系列七管线横断面分析
  9. 谷歌Google搜索及谷歌Google学术搜索镜像网站汇总
  10. 如何查询电脑最大可扩展内存