星期三, 十一月 28, 2012

决策树之三国争霸


决策树是一种简洁实用的数据挖掘方法。在R中通常可以用rpart包和party包来实现两种算法的决策树。最近著名的C4.5决策树算法的升级版本C5.0已经可以在官网下载到。对于这三种决策树算法,本文来做一个预测效果的简单对比。

对比用的数据集是C50包中自带的churn数据,它是用来预测顾客流失的数据集,其中样本量为3333个,变量数为20个。为不平衡数据,没有缺失值存在。对比基本步骤是用10重交叉检验,将数据随机分为10份,用9份训练决策树,用1份来检验结果。循环后求出10个预测准确度的均值。然后在外面再套一个100次大循环,产生三个决策树算法各100个准确率。最后绘制为提琴图,从图中可以观察到C5.0的表现最好,而party次之,rpart的效果最差。在本例实验中最大的差距虽然不过0.02,但如果放在kaggle的数据挖掘比赛中,就相当于是一百位名次的差距了。

生成代码如下:
library(C50)
library(rpart)
library(party)
library(reshape2)
library(ggplot2)
data(churn)
rate.c <- rate.r <-rate.p<-  rep(0,100)
for (j in 1:100) {
    num <- sample(1:10,nrow(churnTrain),replace=T)
    res.c <- res.r  <-res.p<- array(0,dim=c(2,2,10))
    for ( i in 1:10) {
        train <- churnTrain[num!=i, ]
        test <- churnTrain[num==i, ]
 
        model.c <- C5.0(churn~.,data=train)
        pre <- predict(model.c,test[,-20])
        res.c[,,i] <- as.matrix(table(pre,test[ ,20]))
 
        model.p <-ctree(churn~.,data=train)
        pre <- predict(model.p,test[,-20])
        res.p[,,i] <- as.matrix(table(pre,test[ ,20]))
 
        model.r <- rpart(churn~.,data=train)
        pre <- predict(model.r,test[,-20],type='class')
        res.r[,,i] <- as.matrix(table(pre,test[ ,20]))
    }
    table.c <- apply(res.c,MARGIN=c(1,2),sum)
    rate.c[j] <- sum(diag(table.c))/sum(table.c)
 
    table.p <- apply(res.p,MARGIN=c(1,2),sum)
    rate.p[j] <- sum(diag(table.p))/sum(table.p)
 
    table.r <- apply(res.r,MARGIN=c(1,2),sum)
    rate.r[j] <- sum(diag(table.r))/sum(table.r)
}
data <- data.frame(c50=rate.c,rpart=rate.r,party=rate.p)
data.melt <- melt(data)
 
p <- ggplot(data.melt,aes(variable,value,color=variable))
p + geom_point(position='jitter')+
    geom_violin(alpha=0.4)

C5.0算法相对于C4.5有如下几点改进:
  • 速度显著加快
  • 内存使用减少
  • 生成树模型更为简洁
  • 支持boosting方法
  • 支持加权和成本矩阵
  • 支持变量筛选
此外C50包中也有丰富的设置参数:包括设置boost次数、全局剪枝和模糊阀值设置。有兴趣的朋友不妨一试。

15 条评论:

  1. 决策树和随机森林也可以用来做预测模型?能推荐本基础的书吗?谢谢博主!

    回复删除
    回复
    1. 人民邮电出的数据挖掘导论入门很好

      删除
  2. C5.0为什么不能用plot作图呢?谢谢博主指教!(要求填的资料我都没有啊,只好匿名了)

    回复删除
    回复
    1. 它这个包没提供画图函数

      删除
    2. 也没有别的办法可视化了吗

      删除
    3. 或许可以自己编写个函数,估计有点困难的

      删除
    4. 原来这样,既然你都没有比较直接的了,那我只能试试我通常的笨办法,看draw.tree之类函数的输入参数,改写C5.0的结果变成一个符合draw.tree的输入参数。

      删除
  3. 博主,您的这个‘预测准确度’是怎么计算的?为什么不用NMSE呢?谢谢!

    回复删除
    回复
    1. 分类方法不用NMSE,回归才会用到。分类方法就是用混淆矩阵

      删除
  4. num <- sample(1:10,nrow(churnTrain),replace=T)

    这个不是平均分配吧?做检验时候分成是个子集是否需要平均分配呢?

    回复删除
    回复
    1. 写错了,是‘十个’,另外如果不是平均随机分配的话,是不是就不能保证每一个观测值都被检验一次了?

      删除
    2. 这个不是绝对的平均,不过也差不多,也可以保证每个观测值都被检验。

      删除
  5. 博主,我的问题每次都很低级啊:您这个代码不需要set.seed吗?那么是不是每次运行的结果可能会不同?谢谢啦!

    回复删除
    回复
    1. 我是懒人啊,因为用到sample,所以没加set.seed是会造成每次结果不一样。你自己加一个也行。

      删除
  6. data <- data.frame(c50=rate.c,rpart=rate.r,party=rate.p)
    data.melt <- melt(data)
    这段代码中的data已经包含了三组100个数值,为什么需要用melt呢?如果不用reshape的话结果也是一样的吧?

    回复删除