欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

分类模型的再考以及随机森林的应用

程序员文章站 2022-03-22 20:17:53
...

一、进行分类建模前的准备

在上一篇博客里我们应用了逻辑回归和LDA方法来判别|预测一个对象的分类,其中逻辑回归多应用于只有两种类型(Yes或者No)的分类,LDA可用于2种类型及2种以上类型的分类。但是不论逻辑回归还是LDA,最后在验证数据集上的预测效果都很糟糕,甚至不如随机分配的正确率来的高。那么为什么会这样呢?
我们再来看看购买了年卡(YesPass)和没有购买年卡(NoPass)的消费者在两个预测变量Channel和Promo所构成的空间中的分布情况。

library(ggplot2)
ggplot(pass_fact,aes(Channel,Promo))+
  geom_jitter(aes(color=Pass),alpha=0.5)+geom_point(color="blue",size=4)
#geom_jitter让数据分离看来,其实原来数据应该集中在六个蓝点所在的位置上。

输出:
分类模型的再考以及随机森林的应用

可以看到,除了在(NoBundle|Email)的位置,NoPass占了绝大多数之外,其他位置YesPass和NoPass很好地混合在一起,在这样的情况下,希望通过一个判别模型将Nopass和YesPass很好地区分开来是很不容易的。这就好比,我们很难将蜂蜜从一杯蜂蜜水中分离出来一样,因为蜂蜜和水完美地混合在了一起。为了方便起见,在下文中我会把这种问题称为“蜂蜜水问题”
另外一个影响分类效果的要素是数据的不对称性。如果不同类别的数据在数量上差别很大的话,同样也会影响到模型的预测效果。下面我们先来看一下NoPass和YesPass这两类消费者的数量。

table(pass_fact$Pass)

输出:

  NoPass YesPass 
   1567    1589   

可以看到NoPass和YesPass的数量差不多,这样可以说用来建模的数据是对称的或平衡的。当数据不平衡的时候就要格外注意了。
下面我们将带着上面的思考来进行数据的分类。

二、数据的准备

用于分类的数据来自于mlbench包中的BrestCancer,其中包含了包括肿瘤细胞大小、形状在内的多个变量,以及患者的重量的性状(良性或恶性)。我们将通过几种分类算法来判断患者肿瘤的性状,在此之前,我们可以通过clustr包中clusplot对不同类型的肿瘤在预测变量空间的分布状况进行探查。

library(mlbench)
library(tidyr)
data("BreastCancer")
data.Breastcancer<-drop_na(BreastCancer[,-1])#去掉患者ID
#View(data.Breastcancer)

library(cluster)
clusplot(data.Breastcancer[,-10],data.Breastcancer$Class,shade = T,color = T,labels=4,lines = 2,main = "Distribution of two breast cancer type")

输出:
分类模型的再考以及随机森林的应用

clusplot通过了PCA算法把数据映射到了由两个主成分构成的平面上。底部显示了,两个主成分对原始数据地还原状况,可以看到,主成分1和主成分2还原原数据了74%的方差。所以该图较好地反映了数据在真实预测空间地分布状况。
可以看到,良性肿瘤(benign)和恶性肿瘤(malignant)虽然出现了很大部分的重叠,但是如果仔细查看的话,良性肿瘤(空心圆)和恶性肿瘤(三角形)还是很好地区分开来了,除了两个大圈相交的地方。所以在这个例子中,“蜂蜜水”问题并不严重。
下面,在使用决策树方法之前,做为对比我们将尝试使用朴素贝叶斯(NaiveBayes)分类方法。

三、朴素贝叶斯(NaiveBayes)分类法的应用

在应用朴素贝叶斯方法建立模型之前,依照惯例,我们将把数据分成训练集和验证集。

set.seed(828)
train.prob<-0.65

train<-sample(nrow(data.Breastcancer),nrow(data.Breastcancer)*train.prob,replace = F)

BC_train<-data.Breastcancer[train,]
BC_test<-data.Breastcancer[-train,]

应用naiveBayes函数

library(e1071)
BC_nb<-naiveBayes(Class~.,data=BC_train)

使用朴素贝叶斯模型进行预测

BC_nb_class<-predict(BC_nb,newdata=BC_test)

mean(BC_nb_class==BC_test$Class)
#97.1%

prop.table(table(BC_nb_class,BC_test$Class),1)

输出:

[1] 0.9708333

BC_nb_class     benign  malignant
  benign    1.00000000 0.00000000
  malignant 0.07608696 0.92391304

可以看到模型地误差只有97.1%表现还是非常好的。

四、随机森林

随机森林是决策树的一种演进算法。原理很简单,我们以切蛋糕的为例:比如一个蛋糕里随机混合了三种小点心,分别为巧克力、曲奇饼、坚果,怎样切才能使每一块蛋糕仅能地只含有较少种类的小点心呢(当然又一个前提是,每款蛋糕至少要包含一定数量的点心,不然的话切成每一块蛋糕只含有一个小点心的方法就行了)?这个场景就是分类型决策树(classification tree)的一个应用。最后达到的目的就是使每一块蛋糕(对应决策树的node或这leaf)含有类型尽可能少的点心。在实际的应用中,可以把数据看成这个蛋糕,无非是要把多维度的数据沿着各个维度上的具体的值进行切割,比如按照性别,或者按照收入的高低。
在此基础上,随机森林只选取了部分变量,在分类的场合,只选取选取sqrt{p}(p为变量数),以此减少模型实际预测时产生的误差。特别是当变量之间存在着较强的相关性时(上诉的BreastCancer数据便是如此),然后结合bootstrap方法(也就是bagging),可以得到一个随机森林模型。关于决策树和随机森林低介绍,可以参考《An introdunction to statistical learning》的第八章。以下将是它在r中的应用。

library(randomForest)

set.seed(831)
BC_rf<-randomForest(Class~.,data=BC_train,importance=T)

把BC_rf应用在testdata上:

BC_rf_class<-predict(BC_rf,newdata = BC_test)

mean(BC_rf_class==BC_test$Class)

输出结果:

[1] 0.9666667

和朴素贝叶斯方法的正确率相当。如果我们想要知道变量的相对重要性该怎么办?由于我们在建立BC_rf模型时,设立了importance=T参数,所以BC_rf带有一个显示变量相对重要性的数据表。我么可以将此结果可视化。

BC_rf_im<-as.data.frame(BC_rf$importance)
BC_rf_im$Var<-rownames(BC_rf_im)


library(ggplot2)
library(dplyr)
BC_rf_im%>%
  select(Var,MeanDecreaseGini)%>%
  ggplot(.,aes(MeanDecreaseGini,reorder(Var,MeanDecreaseGini)))+geom_point()+labs(y="Variables")

输出结果:
分类模型的再考以及随机森林的应用
可以看到Cell.size、Cell.shape以及Bare.nucle三个变量的相对重要性最大。

五、小结

结合上一篇的分类模型的预测表现,我们探讨了“蜂蜜水问题”对分类模型的影响。为了快速辨别一个数据表是不是存在着“蜂蜜水问题”,我们通常可以使用clustr包中的clusplot进行判别。如果出现了这样的问题的话,我们应该可以预想到最后的模型,特别是逻辑回归和LDA这一类线性判定模型可能在预测的表现不会太好。首先,我们需要反思在数据变量的选取时是不是应该增加新的变量?因为现在的变量对区分不同类别没有很好的帮助。另外也可以选用一些kmeans、朴素贝叶斯、决策树之类的灵活性更好的模型进行预测,但是这一类模型的一个重要问题是结果不太好解释(相较于逻辑回归)。
最后我们结合了mlbench包中的一个关于乳房肿瘤类型的判断,应用并且比较了朴素贝叶斯和随机森林的预测表现。因为原始数据数据没有“蜂蜜水问题”,所以模型预测的准确率都很高。其中在对随机森林模型的重要性进行分析之后,发现Cell.size、Cell.shape以及Bare.nucle三个变量的相对重要性最大。