一、ID3算法
信息熵。信息熵是用来描述信息的纯度,或者确定性的。已经确定的东西,当然就没有什么信息可以发现了。越是确定的信息,这个值越小,如果信息是均匀分布,这个值就会很大。相反,要是都确定这个值就会很小。计算公式如下
Pi 可以看作一个类别的概率。
信息增益。信息增益是指信息熵的有效减少量。熵变少了,不确定性就小了,我们就又收获了一点信息。也就是说信息增益越大,我们越能获得多的信息。具体来说计算公式如下
决策树。要构建一棵决策树,要解决的问题就是当前找哪个变量来分类。有了信息增益这个概念,我们就可以选择信息增益最大的这个变量来分类。找出信息增益最大的变量,相当于有了一个节点。在该节点不同分支上,再递归的找信息增益最大的变量,最终就构成了一棵树。
二、举例说明
摘抄一个《数据挖掘概念与技术》中的例子:
这是一张表。记录了人的ID,年龄,收入,是否是学生,信用等级和 这个人是否会购买电脑。共14条数据。我们先计算原本的信息熵。书中用的是H来表示:
14是这里共有14条记录,其中5个人没买电脑,9个人买了。在当前这个集合中,信息熵就是0.94.
这时候我们开始计算各个变量的信息增益。从年龄开始。首先计算年龄为yonth的样本,把他们都抽出来,一共有5个人,其中买了电脑的2个没买的三个,在这种情况下的信息熵是
。然后再看年龄为middle_aged的人,他们所有人都买了电脑,如果按公式计算会发现log2(0)这样的错误,此时规定,如果碰到已2为底0为幂来求对数这样的错误情况,就把改项变为0 ,另外一项是 1*log2(1),这一项也为0 。 所以年龄为middle_aged这情况下,信息是100%确定的,此时熵为0. 再看年龄为senior的,计算结果和youth一样,都是0.971 。我们算出了年龄下每一种情况的熵,就可以计算年龄这个变量的信息熵了。
。有两个熵之后,相减就是信息增益
。类似的我们还可以计算其他几个信息增益Gain(income)=0.029,Gain(stduent)=0.151,Gain(credit_rating)=0.048。 增益最大的是年龄,所以我们选择年龄为第一个分类变量得到下图:
按年龄分成了三组数据。我们递归的对每组数据做同样的事情,最终就会得到一棵树,如下图
一棵树就构建出来了。
我们递归的停止条件。一是当前已经都分好类了,也就是信息熵为0,比如middle_aged这个子集,所有人都会买电脑,已经不需要再挖了。二是,我们已经没有变量再分了。比如不是学生有可能买也有可能不买,那么上面的树最左下角的no其实就是不确定的,这时候,我们要门增加数据量和变量。要么对这课树进行剪枝,认为不是学生这种情况下,都不会买。一般设置一个阈值,比如不是学生的人有80%的人都不买电脑,我们就把这个节点下的分支剪掉,当作不是学生就一定不买。
三、R程序编写
首先编写一些普遍的方法
#计算一列数据的信息熵
calculateEntropy
t
sum
t
entropy
return(entropy)
}
#计算两列数据的信息熵
calculateEntropy2
var
p
varnames
array
for(name in varnames){
array
}
return(sum(array*p))
}
开始遍历构建树
buildTree
#如果熵为0,停止递归
if(length(unique(data$result)) == 1){
cat(data$result[1])
return()
}
#如果已经没有别的变量,但还不能完全分类,需要剪枝,这里简单处理一下。
if(length(names(data)) == 1){
cat("...")
return()
}
#开始计算
entropy
labels
label
temp
subentropy
for(i in 1:(length(data)-1)){
temp2
if(temp2
temp
label
}
subentropy
}
cat(label)
cat("[")
nextLabels
for(value in unlist(unique(data[label]))){
cat(value,":")
buildTree(subset(data,data[label]==value,select=nextLabels))
cat(";")
}
cat("]")
}
使用如下数据,预测如何选择隐形眼睛的种类:lenses.txt 内容如下
young myope no reduced no lenses
young myope no normal soft
young myope yes reduced no lenses
young myope yes normal hard
young hyper no reduced no lenses
young hyper no normal soft
young hyper yes reduced no lenses
young hyper yes normal hard
pre myope no reduced no lenses
pre myope no normal soft
pre myope yes reduced no lenses
pre myope yes normal hard
pre hyper no reduced no lenses
pre hyper no normal soft
pre hyper yes reduced no lenses
pre hyper yes normal no lenses
presbyopic myope no reduced no lenses
presbyopic myope no normal no lenses
presbyopic myope yes reduced no lenses
presbyopic myope yes normal hard
presbyopic hyper no reduced no lenses
presbyopic hyper no normal soft
presbyopic hyper yes reduced no lenses
presbyopic hyper yes normal no lenses
data
sep="\t",stringsAsFactors=F)
names(data)
buildTree(data)
#tearRate[reduced :no lenses;normal :astigmatic[no :age[young :soft;pre :soft;presbyopic
#:perscript[myope :no lenses;hyper :soft;];];yes :perscript[myope :hard;hyper :age[young :hard;
#pre :no lenses;presbyopic :no lenses;];];];]
程序会输出下面的字符串,稍微整理一下(好吧是大整),就得到了树结构:
tearRate[
reduced :no lenses;
normal :astigmatic[
no :age[
young :soft;
pre :soft;
presbyopic :perscript[
myope :no lenses;
hyper :soft;]
;];
yes :perscript[
myope :hard;
hyper :age[
young :hard;
pre :no lenses;
presbyopic :no lenses;
];
];
];
]