鲍鱼性别分类——SVM&RF

中央财经大学 王思雨

2018-01-01

一、SVM与RF所使用的工具包加载

library(e1071)
library(klaR)           # 导入支持向量机包
library(randomForest)   # 导入随机森林包
library(gbm) 
library(RODBC)          # 导入gbm包
library(AppliedPredictiveModeling)

二、鲍鱼数据读取与预处理

#数据预处理
#数据说明
data(abalone)
head(abalone)              # 获取并载入UCL鲍鱼数据
##   Type LongestShell Diameter Height WholeWeight ShuckedWeight
## 1    M        0.455    0.365  0.095      0.5140        0.2245
## 2    M        0.350    0.265  0.090      0.2255        0.0995
## 3    F        0.530    0.420  0.135      0.6770        0.2565
## 4    M        0.440    0.365  0.125      0.5160        0.2155
## 5    I        0.330    0.255  0.080      0.2050        0.0895
## 6    I        0.425    0.300  0.095      0.3515        0.1410
##   VisceraWeight ShellWeight Rings
## 1        0.1010       0.150    15
## 2        0.0485       0.070     7
## 3        0.1415       0.210     9
## 4        0.1140       0.155    10
## 5        0.0395       0.055     7
## 6        0.0775       0.120     8
str(abalone)  
## 'data.frame':    4177 obs. of  9 variables:
##  $ Type         : Factor w/ 3 levels "F","I","M": 3 3 1 3 2 2 1 1 3 1 ...
##  $ LongestShell : num  0.455 0.35 0.53 0.44 0.33 0.425 0.53 0.545 0.475 0.55 ...
##  $ Diameter     : num  0.365 0.265 0.42 0.365 0.255 0.3 0.415 0.425 0.37 0.44 ...
##  $ Height       : num  0.095 0.09 0.135 0.125 0.08 0.095 0.15 0.125 0.125 0.15 ...
##  $ WholeWeight  : num  0.514 0.226 0.677 0.516 0.205 ...
##  $ ShuckedWeight: num  0.2245 0.0995 0.2565 0.2155 0.0895 ...
##  $ VisceraWeight: num  0.101 0.0485 0.1415 0.114 0.0395 ...
##  $ ShellWeight  : num  0.15 0.07 0.21 0.155 0.055 0.12 0.33 0.26 0.165 0.32 ...
##  $ Rings        : int  15 7 9 10 7 8 20 16 9 19 ...
abalone=na.omit(abalone)   # 去除所有缺失值

三、鲍鱼性别分类——支持向量机SVM

3.1 支持向量机模型建立

###第一种格式建立模型
summary(abalone)        # 查看鲍鱼数据总括
##  Type      LongestShell      Diameter          Height      
##  F:1307   Min.   :0.075   Min.   :0.0550   Min.   :0.0000  
##  I:1342   1st Qu.:0.450   1st Qu.:0.3500   1st Qu.:0.1150  
##  M:1528   Median :0.545   Median :0.4250   Median :0.1400  
##           Mean   :0.524   Mean   :0.4079   Mean   :0.1395  
##           3rd Qu.:0.615   3rd Qu.:0.4800   3rd Qu.:0.1650  
##           Max.   :0.815   Max.   :0.6500   Max.   :1.1300  
##   WholeWeight     ShuckedWeight    VisceraWeight     ShellWeight    
##  Min.   :0.0020   Min.   :0.0010   Min.   :0.0005   Min.   :0.0015  
##  1st Qu.:0.4415   1st Qu.:0.1860   1st Qu.:0.0935   1st Qu.:0.1300  
##  Median :0.7995   Median :0.3360   Median :0.1710   Median :0.2340  
##  Mean   :0.8287   Mean   :0.3594   Mean   :0.1806   Mean   :0.2388  
##  3rd Qu.:1.1530   3rd Qu.:0.5020   3rd Qu.:0.2530   3rd Qu.:0.3290  
##  Max.   :2.8255   Max.   :1.4880   Max.   :0.7600   Max.   :1.0050  
##      Rings       
##  Min.   : 1.000  
##  1st Qu.: 8.000  
##  Median : 9.000  
##  Mean   : 9.934  
##  3rd Qu.:11.000  
##  Max.   :29.000
model=svm(Type~.,data=abalone)  # 利用第一种形式建模
###第二种格式建立模型
x=abalone[,-1]  # 提取abalone数据中除第1列以外的数据作为特征变量
y=abalone[,1]     # 提取abalone数据中的第1列数据作为监督的分类变量
model=svm(x,y,kernel ="radial",gamma =if(is.vector(x)) 1 else 1/ncol(x))  # 利用高斯核函数进行建模
summary(model)
## 
## Call:
## svm.default(x = x, y = y, kernel = "radial", gamma = if (is.vector(x)) 1 else 1/ncol(x))
## 
## 
## Parameters:
##    SVM-Type:  C-classification 
##  SVM-Kernel:  radial 
##        cost:  1 
##       gamma:  0.125 
## 
## Number of Support Vectors:  3400
## 
##  ( 1451 1285 664 )
## 
## 
## Number of Classes:  3 
## 
## Levels: 
##  F I M

3.2 鲍鱼数据SVM模型模式选择

attach(abalone)     # 将数据abalone按列单独确认为向量
x=subset(abalone,select=-Type) # 确定特征变量为abalone中除去Type的其他项
y=Type      # 确定结果变量为数据iris中的Species项
type=c("C-classification","nu-classification")  # 分类方式
kernel=c("linear","polynomial","radial","sigmoid") 
pred=array(0,dim=c(4177,2,4)) #初始化预测结果矩阵的三维长度150,2,4
err=matrix(0,2,4)   #初始化模型错误矩阵的两维分别为2,4
yy=as.integer(y)    #为方便模型精度计算,将结果变量数量化为1,2,3

\(~~~~~~~\)可以从模型比较结果中看到,利用测试数据集在模型中使用高斯核radial以及利用nu-classification分类的测试集的分类泛化误差最小,所以在鲍鱼数据集中的SVM模型建立中使用这种模型进行分析。

for(i in 1:2)           #确认i影响的维度代表分类方式
{
  for(j in 1:4) #确认j影响的维度代表核函数
  {
    pred[,i,j]=predict(svm(x,y,type=type[i],kernel=kernel[j]),x) 
    err[i,j]=sum(pred[,i,j]!=yy)
  }
}
dimnames(err)=list(type,kernel)#确定模型精度变量的列名和行名 
err                   # 在此模型中利用高斯核和nu-classification分类效果最好,查询分类名称
##                   linear polynomial radial sigmoid
## C-classification    1845       1998   1768    2203
## nu-classification   1933       1841   1598    2062
table(pred[,2,3],y)     # 模型预测精度展示,改正行名
##    y
##        F    I    M
##   1  718  107  390
##   2  213 1067  344
##   3  376  168  794
                      # 展示混淆矩阵。进行可视化
                      # 计算错误分类率

3.3 鲍鱼数据SVM模型可视化结果

###模型可视化
plot(cmdscale(dist(abalone[1:200,-1])),col=c("red","black", "blue")[as.integer(abalone[,1])],pch= c("o","+")[1:200 %in% model$index + 1])  
# 绘制模型分类散点图,利用dist函数计算前200个样本的样本间欧氏距离(euclidean),利用多维标度法将高维数据降低到2维方便可视化
legend("bottomright",-0.5,c("F","I","M"),col=c("red","black","blue"),
       cex=0.75,lty=1)  

data(abalone)   
model=svm(Type~., data = abalone)
plot(model,abalone,LongestShell~Height,fill=FALSE,symbolPalette=c("red","black","blue"),svSymbol="+",xlim=c(0,0.3))
# 绘制支持向量机模型类别关于LongestShell长度和Height重量的分类情况,利用两个向量分类效果并不怎么好
legend("bottomright",c("F","I","M"), col=c("red","black","blue"), lty=1)  # 标签类型选择直线        

3.4 鲍鱼数据SVM模型变量权重优化

\(~~~~~~~\)从SVM模型的混淆矩阵建立和可视化结果来看,向量机模型对鲍鱼测试集的泛化结果并不好,正确预测率只有可怜的不到50%,比随机预估33%只好了一点,尤其是在对F和M的判别上改观比较小,所以考虑进行模型的优化,加大模型的F,M的比重,使分错F,M的惩罚加大。

###模型进一步优化,设置权重比重
wts=c(1,1,1)        # 确定模型各个类别的比重为1:1:1
names(wts)=c("F","I","M")   #确定各个比重对应的类别
model1=svm(x,y,class.weights=wts)
pred1=predict(model1,x) 
table(pred1,y)      #显示混淆矩阵
##      y
## pred1    F    I    M
##     F  354   34  240
##     I  180 1075  308
##     M  773  233  980
                  #展示混淆矩阵图形
                  #计算每一类别的错分率

wts=c(5,1,5)  # 由于F和M的错分比重较大,所以将模型各个类别的比重更改为5:1:5,
names(wts)=c("F","I","M")   #确定各个比重对应的类别
model2=svm(x,y,class.weights=wts)   
pred2=predict(model2,x) 
table(pred2,y)      #显示混淆矩阵,错分更大
##      y
## pred2    F    I    M
##     F  421   63  266
##     I   13  528   43
##     M  873  751 1219
                  #可视化混淆矩阵
                  #计算每一个类别的错分率

wts=c(5,3,5)    # 进行再次进行优化,三种比重都进行调整,使不易分错的M的权重减小
names(wts)=c("F","I","M")       
model3=svm(x,y,class.weights=wts)           
pred3=predict(model3,x)             
table(pred3,y)  
##      y
## pred3    F    I    M
##     F  421   61  266
##     I   88  940  169
##     M  798  341 1093

\(~~~~~~~\)从上述的鲍鱼SVM模型的优化过程中可以看出,无论怎样进行向量机各类型变量的优化,都无法使得基于测试集所生成的SVM模型,在测试集上的泛华效果表现更好。又因为支持向量机从机器学习算法的本质上讲,其实是隐层为1的神经网络模型,也就是所谓的感知机模型。所以在接下来的部分将在python中进行神经网络的构建。判断实际的鲍鱼性别预测效果。

四、鲍鱼性别分类——随机森林RF

4.1 鲍鱼数据展示与预处理

\(~~~~~~~\)将鲍鱼数据进行查看,并将Type性别分类数据进行因子化,使得随机森林模型可以识别,并且划分以70%和30%的比例形成测试集和训练集。

head(abalone)                             #查看鲍鱼数据变量
##   Type LongestShell Diameter Height WholeWeight ShuckedWeight
## 1    M        0.455    0.365  0.095      0.5140        0.2245
## 2    M        0.350    0.265  0.090      0.2255        0.0995
## 3    F        0.530    0.420  0.135      0.6770        0.2565
## 4    M        0.440    0.365  0.125      0.5160        0.2155
## 5    I        0.330    0.255  0.080      0.2050        0.0895
## 6    I        0.425    0.300  0.095      0.3515        0.1410
##   VisceraWeight ShellWeight Rings
## 1        0.1010       0.150    15
## 2        0.0485       0.070     7
## 3        0.1415       0.210     9
## 4        0.1140       0.155    10
## 5        0.0395       0.055     7
## 6        0.0775       0.120     8
dim(abalone)                              #观察维度
## [1] 4177    9
#将变量Type性别转化为因子型变量,以便进行随机森林的构建
abalone$Type=as.factor(abalone$Type)
#将数据分为训练集和测试集,按照数据集的70%划分为训练数据,30%为测试数据作为样本划分标准
set.seed(100)
train=abalone[sample(1:dim(abalone)[1],ceiling(dim(abalone)[1]*0.7)),]
test=abalone[-sample(1:dim(abalone)[1],ceiling(dim(abalone)[1]*0.7)),]

4.2 构建随机森林模型评价函数

#定义随机森林模型测试集结果评价函数,
#包含Accuracy,recall,precision,F_measure四个评价指标
#Accuracy总正确率,recall后验准确率,precision先验准确率
index2=function(table) {
  Accuracy=table[1,1]+table[2,2]+table[3,3]
  precision=table[2,2]/sum(table[,2])
  recall=table[2,2]/sum(table[2,])
  F_measure=2*precision*recall/(precision+recall)#计算Recall,Precision和F-measure
  results=data.frame(Accuracy=Accuracy,recall=recall,precision=precision,F_measure=F_measure)
  return(results)
}

4.3 随机森林模型的选择

\(~~~~~~~\)通过模型的三维比较来选取对于鲍鱼数据最为适合的随机森林模型。随机森林的决策树的构建所使用的变量以及所形成的树的棵数,分别如下述代码所示。最终的选取结果为每棵树的所使用的变量为4棵,总共生成100棵树。

#随机森林建模
summary(abalone$Type)   #查看abalone数据集的性别分布
##    F    I    M 
## 1307 1342 1528
var=c(3,4,5)            #基本弱分类器决策树的变量选择方式分别为选取3,4,5变量
tree=c(80,100,120)      #随机森林中的树的棵数分别为80,100,120棵数
acc=matrix(0,3,3)         #初始化模型错误矩阵的两维分别为3,3

for(i in 1:3)           #确认i影响的是每次生成决策树所选取的变量数量
{
  for(j in 1:3)     #确认j影响的是随机森林所含有的树的棵数
  {
    rf.abalone=randomForest(Type~.,data=train,mtry=var[i],importance=TRUE,ntree=tree[j]) 
    rf.pred= predict(rf.abalone,newdata=test[,-1]) ####利用随机森林进行测试集的预测
    rf.real=test$Type
    table_RF=table(rf.real,rf.pred)/nrow(test)
    a=index2(table_RF)      #总准确率Accuracy都高达86%以上,说明集成算法对鲍鱼的分类效果较好
    acc[i,j]<-a$Accuracy
  }
}

dimnames(acc)=list(as.factor(var),as.factor(tree))#确定模型精度变量的列名和行名 
acc                   # 在此模型中利用4个变量100棵数的分类效果最好,总正确率高达87.629%
##          80       100       120
## 3 0.8739026 0.8675180 0.8762969
## 4 0.8715084 0.8762969 0.8723065
## 5 0.8754988 0.8794892 0.8754988

4.4 鲍鱼性别分类随机森林模型构建

rf.abalone=randomForest(Type~.,data=train,mtry=4,importance=TRUE,ntree=100) 
rf.pred= predict(rf.abalone,newdata=test[,-1]) ####利用随机森林进行测试集的预测
rf.real=test$Type
table_RF=table(rf.real,rf.pred)/nrow(test)

4.5 随机森林模型结果分析

\(~~~~~~~\)通过a,b,c,d四个模型输出结果比较,a为总的预测结果,b为混淆数量矩阵,c为判断各成分所占比例,d为各个性别的判断正确率。从a的总预测结果看出总的判别正确率为87.015%,混淆矩阵和各成分所占百分比也可以看出,在测试集中的泛化误差并不大。在变量重要性图中可以看出rings环数和VisceraWeight内脏重量两个变量在构架随机森林的过程中发挥的效果比较高。对于该随机森林来说,对幼年的鲍鱼性别判断较为精准,达到93.38%。

a=index2(table_RF)         #详细模型结果
a
##    Accuracy    recall precision F_measure
## 1 0.8762969 0.9387255 0.9364303 0.9375765
b<-table(rf.pred,rf.real)    #混淆数量矩阵
b
##        rf.real
## rf.pred   F   I   M
##       F 328   9  46
##       I   7 383  19
##       M  58  16 387
row.names(b)<-c("雌性","幼体","雄性")
colnames(b)<-c("雌性","幼体","雄性")
c<-b/dim(test)[1]          #各判断成分所占比例
c
##        rf.real
## rf.pred        雌性        幼体        雄性
##    雌性 0.261771748 0.007182761 0.036711891
##    幼体 0.005586592 0.305666401 0.015163607
##    雄性 0.046288907 0.012769354 0.308858739
plot(rf.abalone)           #查看随机森林各统计量误差图

round(importance(rf.abalone), 2)  
##                   F     I     M MeanDecreaseAccuracy MeanDecreaseGini
## LongestShell   0.32  6.86  3.50                 9.25           186.82
## Diameter       5.28  5.47  0.68                 8.72           178.61
## Height        -3.86  9.23  1.75                 8.72           145.23
## WholeWeight    5.22 12.77  1.58                14.87           325.82
## ShuckedWeight -2.77  6.21  6.93                 9.50           254.63
## VisceraWeight  2.46 15.31 -0.18                17.46           381.50
## ShellWeight    2.50 10.00 -2.02                 9.51           292.48
## Rings         -4.19 29.80  0.61                26.70           178.54
varImpPlot(rf.abalone)     #生成变量重要性比较图    

#从变量重要性图中可以看出,rings鲍鱼鲍鱼环数的重要性很高,
#这可能是由于rings环数与年龄有关,而年龄自然能够区别成年与幼年。
d<-data.frame(matrix(NA,3,3))
d[1,]<-b[1,]/(summary(test$Type)[1])    #判断雌性正确率:82.70%
d[2,]<-b[2,]/(summary(test$Type)[2])    #判断幼年正确率:93.38%
d[3,]<-b[3,]/(summary(test$Type)[3])    #判断雄性正确率:85.39%
row.names(d)<-c("雌性","幼体","雄性")
colnames(d)<-c("雌性","幼体","雄性")
d
##            雌性       幼体       雄性
## 雌性 0.83460560 0.02290076 0.11704835
## 幼体 0.01715686 0.93872549 0.04656863
## 雄性 0.12831858 0.03539823 0.85619469