KNN算法、分类回归树、随机森林的优缺点及应用实例

原理
knn属于一种监督学习的分类算法,用于训练的数据集是完全正确且已分好类的。
如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。knn算法的指导思想是“近朱者赤,近墨者黑”,由邻居来推断出类别。
「计算步骤如下:」
算距离:给定测试对象,计算它与训练集中的每个对象的距离。包括闵可夫斯基距离、欧氏距离、绝对距离、切比雪夫距离、夹角余弦距离;
找邻居:圈定距离最近的k个训练对象,作为测试对象的近邻;
做分类:根据这k个近邻归属的主要类别,来对测试对象分类
「k的含义」:来了一个样本x,要给它分类,即求出它的y,就从数据集中,在x附近找离它最近的k个数据点,这k个数据点,类别c占的个数最多,就把x的label设为c。k-近邻法中的邻近个数,即k的确定,是该方法的关键。
「优点:」
简单,易于理解,易于实现,无需估计参数,无需训练;
特别适合于多分类问题(对象具有多个类别标签)。
「缺点:」
主要的不足:当样本不平衡时,如一个类的 样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的k个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。
计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的k个最近邻点。
可理解性差,无法给出像决策树那样的规则。
r 进行 knn 的实例
# 简单示范,以iris数据集为例train <- iris[sample(nrow(iris), 145),] # 训练数据test <- iris[sample(nrow(iris), 5),] # 测试数据head(test)library(class)aa  head(test) sepal.length sepal.width petal.length petal.width species117 6.5 3.0 5.5 1.8 virginica135 6.1 2.6 5.6 1.4 virginica44 5.0 3.5 1.6 0.6 setosa18 5.1 3.5 1.4 0.3 setosa43 4.4 3.2 1.3 0.2 setosa> table(test[,5], aa) aa setosa versicolor virginica setosa 3 0 0 versicolor 0 0 0 virginica 0 0 2
「随机数据进行knn分类:」
# dataset.seed(12345)x1 <- runif(60,-1,1)x2 <- runif(60,-1,1)  y <- sample(c(0,1),size=60,replace=true,prob=c(0.3,0.7))   data <- data.frame(fx1=x1,fx2=x2,fy=y)  sampleid <- sample(x=1:60,size=18)  datatest <- data[sampleid,]   # 测试集datatrain <- data[-sampleid,]  # 训练集par(mfrow=c(2,2),mar=c(4,6,4,4))plot(data[,1:2],pch=data[,3]+1,cex=0.8,xlab=x1,ylab=x2,main=全部样本)plot(datatrain[,1:2],pch=datatrain[,3]+1,cex=0.8,xlab=x1,ylab=x2,main=训练样本和测试样本)points(datatest[,1:2],pch=datatest[,3]+16,col=2,cex=0.8)# knn 分类library(class)# 循环计算不同k时的错误率## 测试集与训练集均为data时,会出现过拟合,错误率会很低errratio <- vector()  # 全部观测的错判率向量for(i in 1:30){  knnfit=knn(train=data[,1:2],test=data[,1:2],cl=data[,3],k=i)  ct=table(data[,3],knnfit)  # 计算混淆矩阵  errratio=c(errratio,(1-sum(diag(ct))/sum(ct))*100)  # 计算错判率(百分比)}plot(errratio,type=l,xlab=邻近个数k,ylab=错判率(%),main=errorratio,ylim=c(0,80))# 训练集与测试集单独分开errratio1 <- vector()   # 测试样本错判率向量(旁置法)for(i in 1:30){ knnfit=knn(train=datatrain[,1:2],test=datatest[,1:2],cl=datatrain[,3],k=i)  ct=table(datatest[,3],knnfit)  errratio1=c(errratio1,(1-sum(diag(ct))/sum(ct))*100)    }lines(1:30,errratio1,lty=2,col=2)  # 随着样本数增加,错误率趋于稳定# 使用另一个函数 knn.cv(),在不指定测试集的情况下默认使用训练集# 该函数使用留一法交叉验证方法,与 knn 有区别,适用于样本量少的情况errratio2<-vector()   # 留一法错判率向量for(i in 1:30){    knnfit<-knn.cv(train=data[,1:2],cl=data[,3],k=i)  ct<-table(data[,3],knnfit)   errratio2<-c(errratio2,(1-sum(diag(ct))/sum(ct))*100)     }lines(1:30,errratio2,col=2)# knn 回归set.seed(12345)x1 <- runif(60,-1,1) x2 <- runif(60,-1,1) y <- runif(60,10,20)   data <- data.frame(fx1=x1,fx2=x2,fy=y)sampleid <- sample(x=1:60,size=18)  datatest <- data[sampleid,]  datatrain <- data[-sampleid,]  msevector <- vector()    for(i in 1:30){ knnfit<-knn(train=datatrain[,1:2],test=datatest[,1:2],cl=datatrain[,3],k=i,prob=false)  # 回归结果为因子向量,需转换成数值型向量 knnfit<-as.double(as.vector(knnfit))    mse<-sum((datatest[,3]-knnfit)^2)/length(datatest[,3])    msevector<-c(msevector,mse)}plot(msevector,type=l,xlab=近邻个数 k,ylab=均方误差,main=近邻数k与均方误差,ylim=c(0,80))
上图中,第一幅图为观测全体在特征空间中的分布,三角和圈分别表示输出变量的类别值分别为0和1;第二幅图是训练样本集和测试样本集的观测分布,其中有填充色的点属于测试样本集;
第三幅图黑线为全部观测进入训练样本集时的错判概率线,k=1时预测错误率一般为0;红色虚线为旁置法的错判概率曲线,k=9时达到最小;红色实线为留一法错判概率曲线,k=7时达到最小。「留一法的曲线基本在旁置法下方,应是较为客观的预测错误估计」。第四幅图是回归预测时测试样本集的均方误差随参数k变化的曲线。
knn应用——天猫数据集
library(class) tmall_train<-read.table(file=天猫_train_1.txt,header=true,sep=,)head(tmall_train)#   buyornot buydnactdn actdntotaldn buybbrand buyhit# 1        1       6.38        51.09      2.83   1.57# 2        1       8.93        60.87      3.20   2.17# 3        1      16.13        33.70     11.63   6.36# 4        1      16.22        40.22     11.29   6.25# 5        1       3.85        56.52      1.89   1.45# 6        1       4.00        54.35      2.13   1.28tmall_train$buyornot<-as.factor(tmall_train$buyornot)tmall_test<-read.table(file=天猫_test_1.txt,header=true,sep=,)head(tmall_test)#   buyornot buydnactdn actdntotaldn buybbrand buyhit# 1        0       0.00        54.84      0.00   0.00# 2        1       7.69        83.87      2.36   0.83# 3        1      14.29        90.32      4.76   3.89# 4        1      10.00        32.26      7.69   4.00# 5        1      15.38        41.94      8.70   6.98# 6        0       0.00        19.35      0.00   0.00tmall_test$buyornot<-as.factor(tmall_test$buyornot)
模型方法同上:
# 天猫成交顾客的分类预测set.seed(123456)errratio<-vector()   for(i in 1:30){ knnfit<-knn(train=tmall_train[,-1],test=tmall_test[,-1],cl=tmall_train[,1],k=i,prob=false)  ct<-table(tmall_test[,1],knnfit) errratio<-c(errratio,(1-sum(diag(ct))/sum(ct))*100)}errorration# [1] 1.707317 2.195122 2.804878 3.170732 3.292683 4.146341 3.292683 4.878049 5.975610 4.756098 5.365854 6.097561 6.341463 6.341463 6.341463 6.829268 8.048780# [18] 8.048780 8.048780 8.048780 8.048780 6.951220 6.829268 6.707317 8.048780 7.439024 8.048780 8.048780 8.048780 8.048780plot(errratio,type=b,xlab=近邻个数 k,ylab=错判率(%),main=天猫成交顾客的分类预测)
结合上图并兼顾knn分析的稳健性等考虑,采用k=7的分析结论,错判率为3.3%。
基于变量重要性的加权knn
knn默认各输入变量在距离测度中有“同等重要”的贡献,但情况并不总是如此。因此需要采用基于变量重要性的加权knn,计算加权距离,给重要变量赋予较高的权重,不需要的变量赋予较低的权重是必要的。
天猫数据knn分类讨论变量的重要性
library(class)par(mfrow=c(2,2))set.seed(123456)errratio<-vector()   for(i in 1:30){ knnfit<-knn(train=tmall_train[,-1],test=tmall_test[,-1],cl=tmall_train[,1],k=i,prob=false)  ct<-table(tmall_test[,1],knnfit)  errratio<-c(errratio,(1-sum(diag(ct))/sum(ct))*100)    }plot(errratio,type=l,xlab=近邻个数 k,ylab=错判率(%),main=邻近数 k 与错判率)# 选择一个错判率相对较低的 kerrdeltex<-errratio[7]# 剔除变量for(i in -2:-5){ fit<-knn(train=tmall_train[,c(-1,i)],test=tmall_test[,c(-1,i)],cl=tmall_train[,1],k=7) ct<-table(tmall_test[,1],fit) errdeltex<-c(errdeltex,(1-sum(diag(ct))/sum(ct))*100)}plot(errdeltex,type=l,xlab=剔除变量,ylab=剔除错判率(%),main=剔除变量与错判率(k=7),cex.main=0.8)xtitle=c(1:全体变量,2:消费活跃度,3:活跃度,4:成交有效度,5:活动有效度)legend(topright,legend=xtitle,title=变量说明,lty=1,cex=0.6)fi<-errdeltex[-1]+1/4wi<-fi/sum(fi)glabs<-paste(c(消费活跃度,活跃度,成交有效度,活动有效度),round(wi,2),sep=:)pie(wi,labels=glabs,clockwise=true,main=输入变量权重,cex.main=0.8)colpch=as.integer(as.vector(tmall_test[,1]))+1plot(tmall_test[,c(2,4)],pch=colpch,cex=0.7,xlim=c(0,50),ylim=c(0,50),col=colpch,     xlab=消费活跃度,ylab=成交有效度,main=二维特征空间中的观测,cex.main=0.8)
上图中第一幅图为普通knn方法;
第二幅图为确定k=7后,逐个剔除变量,剔除后的错判率曲线(1:全体变量,2:消费活跃度,3:活跃度,4:成交有效度,5:活动有效度),可见剔除消费活跃度后错判概率显著增加,说明消费活跃度对预测的影响巨大;剔除活跃度后错判概率大幅下降,说明该变量包含较强噪声,对预测性能有负面影响;剔除成交有效性后错判率也大幅上升,说明该变量对预测贡献较大;
根据fi定义计算各个输入变量的重要性,确定的权重如第三幅图;第四幅图是消费活跃度和成交有效度特征空间中观测点的分布情况,黑色圆圈表示无成交,红色三角表示有成交,可见所有无交易点均在消费活跃度和成交有效度等于0处,消费活跃度和成交有效度大于0则均为有成交。

综上,结论如下:
①在近邻数k=7时,普通knn方法对测试样本集的错判率仅为3.3%,效果较好;
②大部分成交顾客处于消费活跃度和成交有效性取值水平较低的位置,在消费活跃度和成交有效性上取值较高处的成交顾客数量很少,可作为日后顾客营销策略的参考依据

基于观测相似性的加权knn
# devtools::install_github(klausvigo/kknn)library(kknn)# kknn(formula = r公式, train = 训练样本集, test = 测试样本集, na.action = na.omit(), k = 邻近个数k, distance = k, kernel = 核名称)par(mfrow=c(2,1))tmall_train<-read.table(file=天猫_train_1.txt,header=true,sep=,)tmall_train$buyornot<-as.factor(tmall_train$buyornot)fit<-train.kknn(formula=buyornot~.,data=tmall_train,kmax=11,distance=2,kernel=c(rectangular,triangular,gaussian),na.action=na.omit())plot(fit$misclass[,1]*100,type=l,     main=不同核函数和近邻个数k下的错判率曲线图,cex.main=0.8,xlab=近邻个数 k,ylab=错判率(%))lines(fit$misclass[,2]*100,lty=2,col=1)lines(fit$misclass[,3]*100,lty=3,col=2)legend(topleft,legend=c(rectangular,triangular,gaussian),lty=c(1,2,3),col=c(1,1,2),cex=0.7)# 利用加权 k 近邻分类tmall_test<-read.table(file=天猫_test_1.txt,header=true,sep=,)tmall_test$buyornot<-as.factor(tmall_test$buyornot)fit<-kknn(formula=buyornot~.,train=tmall_train,test=tmall_test,k=7,distance=2,kernel=gaussian,na.action=na.omit())ct<-table(tmall_test[,1],fit$fitted.values)errratio<-(1-sum(diag(ct))/sum(ct))*100# 利用 k 近邻分类library(class)fit<-knn(train=tmall_train,test=tmall_test,cl=tmall_train$buyornot,k=7)ct<-table(tmall_test[,1],fit)errratio<-c(errratio,(1-sum(diag(ct))/sum(ct))*100)errgraph<-barplot(errratio,main=加权k近邻法与k近邻法的错判率比对图(k=7),                  cex.main=0.8,xlab=分类方法,ylab=错判率(%),axes=false)axis(side=1,at=c(0,errgraph,3),labels=c(,加权 k- 近邻法,k-近邻法,),tcl=0.25)axis(side=2,tcl=0.25)
决策树&随机森林
原理
决策树的目标是建立分类预测模型或回归预测模型。决策树(decision tree)也称判定树,它是由对象的若干属性、属性值和有关决策组成的一棵树。其中的节点为属性(一般为语言变量),分枝为相应的属性值(一般为语言值)。从同一节点出发的各个分枝之间是逻辑“或”关系;根节点为对象的某一个属性;从根节点到每一个叶子节点的所有节点和边,按顺序串连成一条分枝路径,位于同一条分枝路径上的各个“属性-值”对之间是逻辑“与”关系,叶子节点为这个与关系的对应结果,即决策属性。
「根节点」:决策树最上层的点,一棵决策树只有一个根节点;
「叶节点」:没有下层的节点称为叶节点;
「中间节点」:位于根节点下且自身有下层的节点。中间节点可分布在多个层中,同层节点称为兄弟节点。上层节点是下层节点的父节点,下层节点是上层节点的子节点。根节点没有父节点,叶节点没有子节点。
**2 叉树和多叉树 **:若树中每个节点最多只能长出两个分枝,即父节点只能有两个子节点,这样的决策树称为2叉树。若能长出不止两个分枝,即父节点有两个以上的子节点,这样的决策树称为多叉树。

决策树分为分类树和回归树,分别对应分类预测模型和回归预测模型,分别用于对分类型和数值型输出变量值的预测。

决策树主要围绕两个核心问题展开:
「决策树的生长」。即利用训练样本集完成决策树的建立过程。决策树一般不建立在全部观测样本上,通常需首先利用旁置法,将全部观测样本随机划分训练样本集和测试样本集。在训练样本集上建立决策树,利用测试样本集估计决策树模型的预测误差;
「决策树的剪枝」。即利用测试样本集对所形成的决策树进行精简。
分类回归树的r实现
rpart(输出变量 ~ 输入变量, data = 数据框名, method = 方法名, parms = list(split = 异质性测度指标), control = 参数对象名)# 数据事先组织在 data 参数指定的数据框中;# 输出变量~输入变量 是r公式的写法,若建立分类树,输出变量应为因子,若有多个输入变量,需用加号连接;# 参数 method 用于指定方法,可取值:“class”表示建立分类树,“position”和“anova”分别输出变量为计数变量和其他数值型变量,此时建立回归树;# 参数 parms 用于指定分类树的异质性测度指标,可取值:“gini”表示采用gini系数,“information”表示采用信息熵;# 参数 control 用于设定预修剪参数、后修剪中的复杂度参数cp值
设置预修剪等参数的 r 函数:
rpart.control(minsplit=20, maxcompete=4,xval=10,maxdepth=30,cp=0.01)# minsplit:指定节点最小样本量,默认为20# maxcompete:指定按变量重要性降序,输出当前最佳分组变量的前若干个候选变量,默认为4# xval:指定进行交叉验证剪枝时的交叉折数,默认为10# maxdepth:指定最大树深度,默认为30# cp:指定最小代价复杂度剪枝中的复杂度cp参数值,默认为0.01

当参数 cp 采用默认值 0.01 且 r 给出的决策树过小时(由于0.01过大的结果),可适当减小 cp 参数值。如可指定参数 cp 为 0,此时的决策树是满足预修剪参数下的未经后修剪的最大树,实际应用中这棵树可能过于茂盛。再次基础上,r 将依次给出 cp 值从 0 开始并逐渐增大过程中经过若干次修剪后的决策树。

可视化决策树的 r 函数:
rpart.plot(决策树结果对象名, type = 编号, branch = 外形编号, extra = 1)# 决策树对象名:rpart 函数返回对象;# type:决策树展示方式。可取值:0~4;# branch:指定决策树外形,可取 0(斜线连接)和 1(垂线连接);# extra:指定在节点中显示哪些数据。可取1~9
复杂参数 cp 对预测误差的影响:
# 复杂度参数 cp 是决策树剪枝的关键参数,其设置是否合理直接决定决策树是否过于复杂而出现过拟合,或是否过于简单而无法得到理想的预测精度。可通过函数 printcp 和 plotcp 浏览与可视化 cp 值:printcp(决策树结果对象名)plotcp(决策树结果对象名)
分类回归树的应用:提炼不同消费行为顾客的主要特征
1.初建分类树
# install.packages(rpart)# install.packages(rpart.plot)library(rpart)library(rpart.plot)buyornot<-read.table(file=消费决策数据.txt,header=true)buyornot$income<-as.factor(buyornot$income) #指定收入为因子buyornot$gender<-as.factor(buyornot$gender) # 指定性别为因子# 指定预修剪等参数,复杂度参数cp为 0ctl <- rpart.control(minsplit=2,maxcompete=4,xval=10,maxdepth=10,cp=0)set.seed(12345)treefit1 <- rpart(purchase~.,data=buyornot,method=class,                parms=list(split=gini),control=ctl)rpart.plot(treefit1,type=4,branch=0,extra=2)printcp(treefit1) # 可视化cp值plotcp(treefit1)
结果显示,根节点包括全部 431 个观测样本,其中 「162 个输出变量值为1的观测被误判为0,错判率为 38%」。左图中,(不含序号)第1列为cp值,第2列 nsplit 为样本数据共经过的分组次数,第3列 rel error 是预测误差相对值的估计,第4列 xerror 是交叉验证的预测误差相对值,第 5 列 xstd 为预测误差的标准误。
需要注意的是,这里的第 3~4 列给出的是以根节点预测误差为单位1的相对值。例如:本例中根节点的预测错误率162/431为单位1,经2次分组得到3个叶节点的分类树,因错误相对值为0.944,所以该树总的预测错误率为153/431。
当复杂度参数 cp 取指定值 0 时,此时的分类树是经过51次分组的结果,包含52个叶节点,与右图对应。此时分类树的预测误差估计值为0.667。经过交叉验证,在cp参数增加至0.002过程中进行了若干次剪枝,此时决策树是36次分组后的结果,包含37个节点,预测误差相对值为0.698,增加了0.031个单位。
右图纵坐标为根节点的交叉验证预测误差为单位 1 时,当前决策树的交叉验证预测误差的单位数;横坐标从右往左是 cp 列表中 8 个 cp 值的典型代表值 β,上方对应的是当前决策树所包含的叶节点个数。可以看出,「包含 12 个叶节点的决策树有最低的交叉验证预测误差」。
2.再建分类树
set.seed(12345)# 默认参数(treefit2<-rpart(purchase~.,data=buyornot,method=class,parms=list(split=gini)))treefit2rpart.plot(treefit2,type=4,branch=0,extra=2)  # 可视化决策树printcp(treefit2)  # 显示复杂度cp参数列表# 指定 cp=0.008,建立前述包含12个叶节点的决策树treefit3<-prune(treefit1,cp=0.008) rpart.plot(treefit3,type=4,branch=0,extra=2)printcp(treefit3)plotcp(treefit3)
上图是按系统默认参数构建决策树,cp 参数为默认初始值 0.01,异质性指标采用 gini 系数。节点2后的星号*标记表示为叶节点,其中所有观测的 income 取 1 或 2,样本量为 276,其中 88 个输出变量为 1 的观测点被误判为 0,置信度为0.68,错判率 0.32。其余同理。

「分类回归树只能建立 2 叉树」

建立分类回归树的组合预测模型:给出稳健预测
分类回归树具有不稳定性,模型会随训练样本的变化而剧烈变动。组合预测模型是提高模型预测精度和稳健性的有效途径,其首要工作是基于样本数据建立一组模型而非单一模型;其次,预测时由这组模型同时提供各自的预测结果,通过类似“投票表决”的形式决定最终的预测结果。
组合预测中的单个模型称为「基础学习器(base learner)」,通常有相同的模型形式,如决策树或其他预测模型等。多个预测模型是建立在多个样本集合上的。
如何获得多个样本集合,以及如何将多个模型组合起来实现更合理的“投票表决”,是组合模型预测中的两个重要方面。对此,常见的技术有「袋装(bagging)技术」和「推进(boosting)技术」。
1.袋装技术的 r 实现
# ipred 包中的 bagging 函数bagging(输出变量名~输出变量名, data = 数据框名, nbagg = k, coob = true, control = 参数对象名)# 输出变量名~输入变量名为 r 公式的写法,有多个输入变量时应用加号连接;# coob = true 表示基于袋装观测(oob)计算预测误差# control:指定袋装过程所建模型的参数。bagging函数的内嵌模型,即基础学习器为分类回归树,control参数应为rpart函数的参数# nbagg:指定自举次数为 k,默认重复 25 次自举过程,生成 25颗分类回归树# adabag 包中的 bagging 函数bagging(输出变量名~输出变量名, data = 数据框名, mfinal = 重复次数, control = 参数对象名)# mfinal:指定重复几次自举过程,默认为100。bagging函数的基础学习器为分类树,control参数应为rpart函数的参数# bagging函数返回值是列表。tree成分中存储k颗分类树的结果;votes中存储k个模型的投票情况;prob中存储预测类别的概率值;class为预测类别;importance为输入变量对输出变量预测重要性的得分# 对新样本集进行预测:predict.bagging 函数predict.bagging(bagging 结果对象名, 新样本集名)# predict.bagging 将返回名为 votes,prob,class的列表成分,含义同bagging函数。此外,还返回名为confusion和error的列表成分,分别存储混淆矩阵和错判率
2.袋装技术的应用:稳健定位目标客户
library(rpart)mailshot<-read.table(file='邮件营销数据.txt',header = t)mailshot<-mailshot[,-1]  # 剔除idctl <- rpart.control(minsplit=20,maxcompete=4,maxdepth=30,                     cp=0.01,xval=10) # rpart的默认参数set.seed(12345)treefit <- rpart(mailshot~.,data=mailshot,                 method=class, parms=list(split=gini))  # 建立单一分类树rpart.plot(treefit,type=4,branch=0,extra=1)cfit1<-predict(treefit,mailshot,type=class)  # 利用单个分类树对全部观测进行预测# cfit1<-predict(treefit,mailshot)  confm1<-table(mailshot$mailshot,cfit1)  # 计算单个分类树的混淆矩阵#      cfit1#        no yes#   no  119  46#   yes  39  96(e1 <-(sum(confm1)-sum(diag(confm1)))/sum(confm1)) # 计算单个分类树的错判率# 0.2833333
首先建立单个分类树,并利用单个分类树对全部观测做预测,错判率为 0.28。
## 利用ipred包中的bagging建立组合分类树library(ipred)set.seed(12345)mailshot$mailshot <- as.factor(mailshot$mailshot)  # 不转换数据类型一直报错(bagm1<-bagging(mailshot~.,data=mailshot,nbagg=25,                coob=true,control=ctl))  # bagging建立分类组合树cfit2<-predict(bagm1,mailshot,type=class)  # 利用组合分类树对全部观测进行预测confm2<-table(mailshot$mailshot,cfit2)  # 计算组合分类树的混淆矩阵(e2<-(sum(confm2)-sum(diag(confm2)))/sum(confm2))  # 计算组合分类树的错判率# 0.196667
利用 ipred 包中的 bagging 函数建立组合分类树,袋装过程默认进行28次重抽样自举,生成25颗分类树。基于袋外观测(oob)的预测误差为0.457。利用组合分类树并对全部观测做预测,错判率为 0.197。「预测精度较单一分类树有一定提高」
predict 函数 type 指定为 class 时,给出的预测结果时分类值。不指定参数,默认给出的预测结果是各类别的概率值(预测置信度)。
## 利用adabag包中的bagging函数detach(package:ipred)library(adabag)mailshot<-read.table(file=邮件营销数据.txt,header=true)mailshot<-mailshot[,-1]ctl<-rpart.control(minsplit=20,maxcompete=4,maxdepth=30,cp=0.01,xval=10)set.seed(12345)bagm2<-bagging(mailshot~.,data=mailshot,control=ctl,mfinal = 25)bagm2$importance#       age       car    gender    income   married  mortgage    region      save # 17.761337  3.202805  6.126779 49.217348  7.539829  5.398284  8.425630  2.327989 cfit3<-predict.bagging(bagm2,mailshot)  # 利用组合分类树对全部观测进行预测cfit3$confusioncfit3$error
adabag 包中的 bagging 函数建立组合分类树,参数设置同前。函数自动计算了输入变量重要性的测度结果,并进行了归一化处理。输出变量重要性为归一化后的百分比。本例中较为重要的两个输入变量依次为收入(income)和年龄(age)。
用组合分类树对全部观测做预测的错判率为 ,预测精度较单一分类树有一定提高。
3.推进技术的 r 实现
袋装技术中,自举样本的生成完全是随机的。多个模型在预测投票中的地位也都相同,未考虑不同模型预测精度的差异性。推进技术在这两方面进行了调整,其中的 adaboost(adaptive boosting)策略已有较为广泛的应用。
与袋装技术不同的是,adaboost 采用的是加权投票方式,不同的模型具有不同的权重,权重大小与模型的预测误差成反比。预测误差较小的模型有较高的投票权重,预测误差较大的模型投票权重较低。可见,「权重越高的模型,对决策结果的影响越大」。
# adabag 包中的 boosting 函数boosting(输出变量名~输入变量名, data=数据框, mfinal=重复次数,        boos=true, coeflearn=模型权重调整方法, control=参数对象名)# 指定重复自举次数,默认100# boos = true 表示每次自举过程均调整各观测进入训练样本集的权重# coeflearn:指定预测时各模型的权重设置方法。可取值 breiman 或 freund 或 zhu# boosting 函数的基础学习器为分类树,control 参数应为 rpart 的默认参数
bagging函数返回值是列表。tree成分中存储k颗分类树的结果;votes中存储k个模型的投票情况;prob中存储预测类别的概率值;class为预测类别;importance为输入变量对输出变量预测重要性的得分;weight为各个模型的预测权重。
4.推进技术的应用:文件定位目标客户
library(adabag)mailshot <- read.table(file=邮件营销数据.txt,header = t)mailshot<-mailshot[,-1]mailshot$mailshot <- as.factor(mailshot$mailshot)ctl<-rpart.control(minsplit=20,maxcompete=4,maxdepth=30,cp=0.01,xval=10)set.seed(12345)boostm<-boosting(mailshot~.,data=mailshot,boos=true,mfinal=25,                 coeflearn=breiman,control=ctl)boostm$importance#       age       car    gender    income   married  mortgage    region      save # 23.666103  3.821141  3.597499 43.118805  5.424618  4.782976 11.057369  4.531490confm4<-table(mailshot$mailshot,boostm$class)e4 <- (sum(confm4)-sum(diag(confm4)))/sum(confm4)e4# 0.02666667
本例中,较为重要的两个输入变量依次为收入和年龄。用组合分类树对全部观测做预测的错判率为 0.027,较单一分类树有显著提高。

袋装技术与推进技术有类似的研究目标,但两者训练样本集的生成方式不同,组合预测方式也不同。两者均可有效地提高预测准确性。「在大多数数据集中,推进技术的准确性一般高于袋装技术,但也可能导致过拟合问题。」

随机森林:具有随机性的组合预测
random forest 也是一种组合预测模型,是用随机方式建立一片森林,森林中包含众多有较高预测精度且弱相关甚至不相关的决策树,并形成组合预测模型;后续,众多预测模型将共同参与对新观测输出变量取值的预测。
随机森林的内嵌模型,即基础学习器是分类回归树,其特色在于随机,表现在两个方面:
训练样本是对原始样本的重抽样自举,训练样本具有随机性;
在每颗决策树的建立过程中,称为当前最佳分组变量的输入变量,是输出变量全体的一个随机候选变量子集中的竞争获胜者。分组变量具有随机性
「bagging方法的主要过程:」
训练分类器。从整体样本集合中,抽样n* < n个样本 针对抽样的集合训练分类器ci
分类器进行投票,最终的结果是分类器投票的优胜结果
随机森林是以决策树为基本分类器的一个集成学习模型,它包含多个由bagging集成学习技术训练得到的决策树。前面描述了原始的树的bagging算法。random forests不同的是:在bagging的基础上,他们使用一种改进的树学习算法,这种树学习算法在每个候选分裂的学习过程中,选择特征值的一个随机子集。这个过程有时被称为“「feature bagging」”。
以决策树为基本模型的bagging在每次bootstrap放回抽样之后,产生一棵决策树,抽多少样本就生成多少棵树,在生成这些树的时候没有进行更多的干预。而随机森林也是进行bootstrap抽样,但它与bagging的区别是在生成每棵树的时候,每个节点变量都仅仅在随机选出的少数变量中产生。因此,不但样本是随机的,连每个节点变量(features)的产生都是随机的。
「随机森林分类性能的主要因素:」
森林中单颗树的分类强度(strength):每颗树的分类强度越大,则随机森林的分类性能越好。
森林中树之间的相关度(correlation):树之间的相关度越大,则随机森林的分类性能越差。
「随机森林的几个理论要点:」
收敛定理。它度量了随机森林对给定样本集的分类错误率。
泛化误差界。单个决策树的分类强度越大,相关性越小,则泛化误差界越小,随机森林分类准确度越高。
袋外估计。breiman在论文中指出袋外估计是无偏估计,袋外估计与用同训练集一样大小的测试集进行估计的精度是一样的。
「随机森林的优点:」
对于很多种资料,它可以产生高准确度的分类器。
它可以处理大量的输入变量。
它可以在决定类别时,评估变量的重要性。
在建造随机森林时,它可以在内部对于一般化后的误差产生无偏差的估计。
它包含一个好方法可以估计遗失的资料,并且,如果有很大一部分的资料遗失,仍可以维持准确度。
它提供一个实验方法,可以去侦测 variable interactions 。
对于不平衡的分类资料集来说,它可以平衡误差。
它计算各例中的亲近度,对于数据挖掘、侦测偏离者(outlier)和将资料视觉化非常有用。
使用上述。它可被延伸应用在未标记的资料上,这类资料通常是使用非监督式聚类。也可侦测偏离者和观看资料。
学习过程是很快速的。
可以实现并行运行
「随机森林的缺点:」
随机森林已经被证明在某些噪音较大的分类或回归问题上会过拟
对于有不同级别的属性的数据,级别划分较多的属性会对随机森林产生更大的影响,所以随机森林在这种数据上产出的属性权值是不可信的。
由于随机选择属性,得单棵决策树的的预测效果很差
投票机制中,并不是所有的树都能够准确地标记出所有的对象。
「随机森林的应用:」
随机森林是现在研究较多一种数据挖掘算法,由于其良好的性能表现,在现实生活中也获得了广泛的应用。随机森林主要应用于回归和分类。
随机森林的 r 实现
# randomforest 包中的 randomforst 函数randomforest(输出变量名~输入变量名, data=数据框名, mtyr=k, ntree=m, importance=true)# mtry:指定决策树各节点的输入变量个数 k。若输出变量为因子,随机森林中的基础学习器为分类树;若为数值型变量,则基础学习器为回归树;# ntree:指定随机森林包含 m 颗决策树,默认为 500;# importance = true:表示计算输入变量对输出变量重要性的测度值
randomforets 函数的返回值为列表,包含以下成分:
predicted:基于袋外观测 oob 的预测类别或预测值;confusion:基于袋外观测 oob 的混淆矩阵;votes:适用于分类树。给出各预测类别的概率值,即随机森林中有多少臂力的分类树投票给第 i 个类别;oob.times:各个观测值作为 oob 的次数,即在重抽样自举中有多少次未进入自举样本,其会影响基于袋外观测 oob 的预测误差结果;err.rate:随机森林中各个决策树基于 oob 的整体预测错误率,以及对各个类别的预测错误率;importance:输入变量重要性测度矩阵。
随机森林的应用:文件定位客户目标
library(randomforest)mailshot<-read.table(file=邮件营销数据.txt, header = t)mailshot<-mailshot[,-1]set.seed(12345)(rfm<-randomforest(mailshot~.,data=mailshot,importance=true,proximity=true))head(rfm$votes)  # 各观测的各类别预测概率head(rfm$oob.times)  # 各观测作为 oob 的次数
随机森林共建了500颗决策树,每个节点的候选输入变量个数为2。基于袋外观测 oob 的预测错判率为 45%。从袋外观测的混淆矩阵看,模型对两个类别的预测精度均不理想。对no类的预测错误率为36.4%,对yes类的预测错误率为55.6%。
以第一个观测为例:有62.8%的决策树投票给no,37.2%的决策树投票给yes。有183次作为oob未进入训练样本集。
drawl<-par(mfrow=c(2,1),mar=c(5,5,3,1))plot(rfm,main=随机森林的oob错判率和决策树颗数)plot(margin(rfm),type=h,main=边界点探测,     xlab=观测序列,ylab=比率差) # 探测边界点par(drawl)fit<-predict(rfm,mailshot)  # 随机森林对全部观测做预测confm5<-table(mailshot$mailshot,fit)  # 随机森林对全部观测做预测的混淆矩阵(e5<-(sum(confm5)-sum(diag(confm5)))/sum(confm5))  # 随机森林的整体错判率# 0.03
对oob错判率随随机森林中决策树数量的变化特点进行可视化,plot的绘图数据为err.rate。图中黑色线为整体错判率,红色线为对no类预测的错判率,绿色线为对yes类预测的错判率。可见,模型对no类的预测效果好于对整体和yes类的。当决策树达到380以后,各类错判率基本保持稳定。所以本例中参数 ntree 可设置为380。
下面的图为使用 margin 函数考察处于分类边界附近的点的错判情况。该函数以差的升序返回所有观测的比率差。其中,比率差近似等于 0 的观测红色类(no类)居多,多蓝类(yes类)的预测错误较多。
head(treesize(rfm))  # 浏览各个树的叶节点个数head(gettree(rfobj=rfm,k=1,labelvar=true))  # 提取第1颗树的部分信息
treesize函数可用于显示随机森林中各决策树的大小。treesize(随机森林结果对象名, terminal = true/false),参数 terminal 取 true 时仅统计决策树的叶节点个数,取 false 表示统计所有节点的个数。
本例中,第 1 颗决策树包含 88 个叶节点。可利用 gettree 函数抽取随机森林中的某颗树并浏览其结构。
barplot(rfm$importance[,3],                main=输入变量重要性测度(预测精度变化)指标柱形图)box()
可调用randomforest包中的importance函数,importance(随机森林结果对象名, type=类型编号)。
importance(rfm, type = 1)
varimpplot(x=rfm, sort=true, n.var=nrow(rfm$importance), main=输入变量重要性测度散点图)
由上图可知,从对输出变量预测精度影响的角度看,收入、是否有债务、婚姻状况较为重要;从对输出变量异质性下降程度看,收入、年龄和居住地较为重要,即收入不同,年龄不同,居住地不同的人群对快递邮件的反应有较大差异。
练习
将上述数据分成70%训练集,训练随机森林模型,并对剩下30%预测,计算预测准确率。并且评价变量重要性。
library(randomforest)mailshot<-read.table(file=邮件营销数据.txt, header = t)mailshot<-mailshot[,-1]mailshot$mailshot <- as.factor(mailshot$mailshot)nrow(mailshot)n <- sample(c(1:300), 300*0.70, replace = f)mailshot_train <- mailshot[n,]mailshot_test <- mailshot[-n,]set.seed(12345)(rfm<-randomforest(mailshot~.,data=mailshot_train,importance=true,proximity=true))head(rfm$votes)  # 各观测的各类别预测概率head(rfm$oob.times)  # 各观测作为 oob 的次数drawl<-par(mfrow=c(2,1),mar=c(5,5,3,1))plot(rfm,main=随机森林的oob错判率和决策树颗数)plot(margin(rfm),type=h,main=边界点探测,     xlab=观测序列,ylab=比率差) # 探测边界点par(drawl)fit<-predict(rfm,mailshot_test)  # 随机森林对测试数据做预测confm<-table(mailshot_test$mailshot,fit)  # 随机森林对测试数据做预测的混淆矩阵(e<-(sum(confm)-sum(diag(confm)))/sum(confm))  # 随机森林的整体错判率# 0.4222222


SiC MOSFET和SiC IGBT的区别
看行业大咖畅谈无人驾驶
电流探头在电机调试中的具体测试方法和操作步骤
详解关于5G网络的方方面面
hx711称重程序
KNN算法、分类回归树、随机森林的优缺点及应用实例
关于远程抄表系统的设计与应用的详细介绍
中国在光子学材料领域获突破 可用于激光防护
冷水机排气压力不正常故障分析
百识电子总投资30亿元建立第三代半导体外延片+器件专业代工
华为与四方伟业联合发布了政务大数据解决方案
智能互联·数领未来|第五届全球人工智能创业者大会圆满举办!
8051单片机串口通信中的检错方法
法国松尼克蓄电池(中国)有限公司【销售总部】
红外雨量计(光学雨量传感器)在流动气象站中的应用
苹果13 真实图片曝光
Intel着急:软银收购之后发力 阿里将大量采用ARM处理器
NVIDIAGTX1650评测 售价略高整体表现来说是网吧绝配
机械手视觉引导相机和伺服电机算法
自启动可能很难实现 - 了解稳压器和带隙中的上电复位要求