上面这个流程图就是一个决策树。它包含了决策块(长方形,后面用圆形)和终点块(椭圆形,后面用长方形),其中终点块表示已经做出了对应的决策。决策树还包含左右分支,对应于决策块的不同取值。决策树提取数据中的知识表现良好。
创建一个决策树类
DecisionTree <- R6Class("DecisionTree",
private = list(
tree = NULL
),
public = list(
initialize = function(){
private$tree <- igraph::graph.empty()
},
getTree = function(){
private$tree
}
)
)
#给决策树类加公共方法createDataSet,生成数据集
createDataSet <- function(){
canLiveInWater <- c('yes','yes','yes','no','no')
hasFlipper <- c('yes','yes','no','yes','yes')
isFish <- c("yes","yes","no","no","no")
dataSet <- data.frame(canLiveInWater,hasFlipper,isFish,stringsAsFactors = F)
dataSet
}
DecisionTree$set("public","createDataSet",createDataSet,overwrite=T)
决策树的伪代码:
Check if every item in the dataset is in the same class:
If so return the class label
Else
Check if the dataset has any feature:
If none return the most voted class label
Else
find the best feature to split the data
split the dataset
create a branch node
for each split
call createTree and add the result to the branch node
return branch node
建树
想要建立一个决策树,首先需要做的决定就是用什么特征来切分数据集。通常有三种分割数据集的方法,分别对应于决策树的三种算法:
- 信息增益;
- 信息增益比;
- 基尼增益。
给决策树类动态增加一个计算熵的方法,一个数据集的熵通常是根据它的类别列来计算。
calcShannonEnt <- function(dataset){
numCols <- ncol(dataset)
clasCol <- dataset[,numCols]
tbl <- table(clasCol)
tbl <- tbl[!tbl==0]#去掉频数为0的项,避免log报错
prob <- tbl/sum(tbl)
-sum(prob*log(prob,base=2))
}
DecisionTree$set("public","calcShannonEnt",calcShannonEnt,overwrite=T)
dT <- DecisionTree$new()
myDat <- dT$createDataSet()
dT$calcShannonEnt(myDat)
熵的值越大,表明数据的混杂程度就越高,因此用熵较高的特征来划分数据集能取得较好的划分效果。
可以用原始数据集来做个试验,当我将原始数据集的第一个标签换成“maybe”,这时类别列就有三种类别,显然数据更加复杂了,熵应该会升高。
myDat[1,ncol(myDat)] <- 'maybe'
myDat
dT$calcShannonEnt(myDat)
计算结果为1.3709,熵果然增大了,也就是说明数据集的混乱程度更大了。
- 当一个数据集根据一个特征划分成若干个小的数据集之后,这些数据集的熵如何计算?还是用上述的数据集作为例子。
假如用第一个指标(canLiveInWater)来划分数据集,由于该指标只有两个取值,所以可以将原数据集划分成两个子数据集。
dataset1 d a t a s e t 1
dataset