分类分析--决策树
决策树是数据挖掘领域中的常用模型。其基本思想是对预测变量进行二元分离,从而构造一棵可用于预测新样本单元所属类别的树。两类决策树:经典树和条件推断树。
1 经典决策树
经典决策树以一个二元输出变量(对应威斯康星州乳腺癌数据集中的良性/恶性)和一组预测变量(对应九个细胞特征)为基础。具体算法如下:
(1) 选定一个最佳预测变量将全部样本单元分为两类,实现两类中的纯度最大化(即一类中良性样本单元尽可能多,另一类中恶性样本单元尽可能多)。如果预测变量连续,则选定一个分割点进行分类,使得两类纯度最大化;如果预测变量为分类变量(本例中未体现),则对各类别进行合并再分类。
(2) 对每一个子类别继续执行步骤(1)。
(3) 重复步骤(1)~(2),直到子类别中所含的样本单元数过少,或者没有分类法能将不纯度下降到一个给定阈值以下。最终集中的子类别即终端节点(terminal node)。根据每一个终端节点中样本单元的类别数众数来判别这一终端节点的所属类别。
(4) 对任一样本单元执行决策树,得到其终端节点,即可根据步骤3得到模型预测的所属类别。
上述算法通常会得到一棵过大的树,从而出现过拟合现象。结果就是,对于训练集外单元的分类性能较差。为解决这一问题,可采用10折交叉验证法选择预测误差最小的树。这一剪
枝后的树即可用于预测。
R中的rpart包支持rpart()函数构造决策树,prune()函数对决策树进行剪枝。下面给出判别细胞为良性或恶性的决策树算法实现。
(1)使用rpart()函数创建分类决策树:
#生成树:rpart()函数可用于生成决策树
library(rpart)
set.seed(1234)
dtree <- rpart(class ~ ., data=df.train, method="class",
parms=list(split="information"))
#rpart() 返回的cptable值中包括不同大小的树对应的预测误差,因此可用于辅助设定最终的树的大小。
dtree$cptable
结果分析: 复杂度参数(cp)用于惩罚过大的树。树的大小即分支数(nsplit),有n个分支的树将有n+1个终端节点;rel error栏即训练集中各种树对应的误差;交叉验证误差(xerror)即基于训练样本所得的10折交叉验证误差;xstd栏为交叉验证误差的标准差。
#剪枝:print(dtree)和summary(dtree)可用于观测所得模型,此时所得的树可能过大,需要剪枝。
plotcp(dtree)
结果分析:借助plotcp()函数可画出交叉验证误差与复杂度参数的关系图(如图所示)。对于所有交叉验证误差在最小交叉验证误差一个标准差范围内的树,最小的树即最优的树。虚线是基于一个标准差准则得到的上限(0.12+1×0.0264=0.15)。从图像来看,应选择虚线下最左侧cp值对应的树。
本例中,最小的交叉验证误差xerror为0.12,标准误差xstd为0.0264,则最优的树为交叉验证误差在0.12±0.0264(0.094和0.15)之间的树。由代码cptable表可知,四个终端节点(即三次分割)的树满足要求(交叉验证误差为0.1588235);根据图也可以选得最优树,即三次分割(四个节点)对应的树。
dtree.pruned <- prune(dtree, cp=.0176)
#在完整树的基础上,prune()函数根据复杂度参数剪掉最不重要的枝,从而将树的大小控制在理想范围内,从代码的cptable中可以看到,三次分割对应的复杂度参数为0.0176,从而prune(dtree, cp=0.0176)可得到一个理想大小的树。
install.packages("partykit")
library(partykit)
plot(as.party(dtree.pruned)) #画出生成的决策树
结果分析:每个节点中的阴影区域代表这个节点对应的恶性肿瘤比例。
library(rpart.plot)
prp(dtree.pruned, type = 2, extra = 104,
fallen.leaves = TRUE, main="Decision Tree")
结果分析:rpart.plot包中的prp()函数可用于画出最终的决策树,如图所示。prp()函数中有许多可供选择的参数(详见?prp),如type=2可画出每个节点下分割的标签,extra=104可画出每一类的概率以及每个节点处的样本占比,fallen.leaves=TRUE可在图的底端显示终端节点。对观测点分类时,从树的顶端开始,若满足条件则从左枝往下,否则从右枝往下,重复这个过程直到碰到一个终端节点为止。该终端节点即为这一观测点的所属类别。
#对训练集外样本单元分类
dtree.pred <- predict(dtree.pruned, df.validate, type="class")
#predict()函数用来对验证集中的观测点分类
dtree.perf <- table(df.validate$class, dtree.pred, dnn=c("Actual", "Predicted"))
#生成实际类别与预测类别的交叉表
dtree.perf
结果分析:整体来看,验证集中的准确率达到了(129+69)/210=94%
2 条件推断树
在介绍随机森林之前,我们先介绍传统决策树的一种重要变体,即条件推断树(conditional inference tree)。条件推断树与传统决策树类似,但变量和分割的选取是基于显著性检验的,而不是纯净度或同质性一类的度量。显著性检验是置换检验。条件推断树的算法如下:
(1) 对输出变量与每个预测变量间的关系计算p值。
(2) 选取p值最小的变量。
(3) 在因变量与被选中的变量间尝试所有可能的二元分割(通过排列检验),并选取最显著的分割。
(4) 将数据集分成两群,并对每个子群重复上述步骤。
(5) 重复直至所有分割都不显著或已到达最小节点为止。
条件推断树可由party包中的ctree()函数获得。如下代码是对乳腺癌数据生成条件推断树。
(1)使用ctree()函数创建条件推断树
library(party)
fit.ctree <- ctree(class~., data=df.train) #ctree()函数可用于条件推断树
plot(fit.ctree, main="Conditional Inference Tree") #画出生成的条件推断树
结果分析:每个节点中的阴影区域代表这个节点对应的恶性肿瘤比例。
ctree.pred <- predict(fit.ctree, df.validate, type="response")
#predict()函数用来对验证集中的观测点分类
ctree.perf <- table(df.validate$class, ctree.pred, dnn=c("Actual", "Predicted"))
#生成实际类别与预测类别的交叉表
ctree.perf
结果分析:整体来看,验证集中的准确率达到了(131+67)/210=94%