您的位置:首页 > 编程语言 > Python开发

决策树与随机森林相关概念及其Python实现

2016-07-20 11:24 302 查看

决策树

所谓的决策树, 就是一种树形结构。其内部每个节点代表一个特征的测试,每个一个分支代表测试的输出,而每个叶子节点则代表一种类别。

而随机森林,就是指的一群决策树所组成的一个森林。当一个新的样本需要归类,它的结果不是仅仅取决于某一刻决策树的结果,而是让森林里所有的决策树进行投票,选出结果最多的那类作为输出。

决策树形式如下:



构建决策树

构建决策树的基本思想是以信息熵为度量,构造一棵熵值下降最快的树(就是先判断对结果影响大的),到叶子节点处时熵值将为零(熵值大小即代表事物的不确定性度)。

建立决策树有三种算法:

- ID3 : 以信息增益大小来建立。

- C4.5 : 以信息增益率大小来建立。

- CART : 以基尼系数大小来建立。

首先看看随机变量熵的定义:

信息增益:



信息增益率:



基尼指数:



其中,D表示数据集,|D|表示样本个数,A表示特征,|Ck|表示在有K个类的情况下属于类Ck的 样本个数(明显,∑|Ck|=|Dk|)。

关于熵的复习,参照以前写的笔记。

注:一个属性的信息增益越大,表明属性对样本的熵的减少能力更强,这个属性使得数据由不确定性变成确定性的能力更强。

代码如下:

#构造数据集及特征标签集
dataset = [    ['youth', 'no', 'no', 'just so-so', 'no'],
['youth', 'no', 'no', 'good', 'no'],
['youth', 'yes', 'no', 'good', 'yes'],
['youth', 'yes', 'yes', 'just so-so', 'yes'],
['youth', 'no', 'no', 'just so-so', 'no'],
['midlife', 'no', 'no', 'just so-so', 'no'],
['midlife', 'no', 'no', 'good', 'no'],
['midlife', 'yes', 'yes', 'good', 'yes'],
['midlife', 'no', 'yes', 'great', 'yes'],
['midlife', 'no', 'yes', 'great', 'yes'],
['geriatric', 'no', 'yes', 'great', 'yes'],
['geriatric', 'no', 'yes', 'good', 'yes'],
['geriatric', 'yes', 'no', 'good', 'yes'],
['geriatric', 'yes', 'no', 'great', 'yes'],
['geriatric', 'no', 'no', 'just so-so', 'no']]
fea_labels = ['age', 'work', 'house', 'credit']

#计算数据集的经验熵
from math import log
from collections import Counter
def calEntropy(labels):
newdic = {}
Entropy=0.0
for item in labels:
newdic[item]=newdic.get(item,0)+1
for itemN in newdic:
prob=newdic[itemN]/len(labels)
Entropy-=(prob*log(prob,2))
return Entropy

#计算特征X对数据集D的经验条件熵H(D|X)
def feaX_condi_Entropy(dataset,i):
#提取第i项特征所有值及其对应的label
feaX_label=[[x[i],x[-1]] for x in dataset]
#去掉重复
feaX=[x[i] for x in dataset]
feaX_diff=list(set(feaX))

feaX_Entropy=0.0
for diff_item in feaX_diff:
labels=[]
count=0
for item in feaX_label:
if diff_item==item[0]:
count+=1
labels.append(item[1])
feaX_Entropy+=count/len(feaX)*calEntropy(labels)
return feaX_Entropy

#计算信息增益
def cal_InfoGain(dataset,i):
info_gain=0.0
label=[x[-1] for x in dataset]
info_gain=calEntropy(label)-feaX_condi_Entropy(dataset,i)
return info_gain

#寻找当前数据集最大信息增益对应特征标号
def find_max_InfoGain(dataset):
fea_num=len(dataset[1])-1
infogain=[]
for i in range(fea_num):
infogain.append(cal_InfoGain(dataset,i))
return infogain.index(max(infogain)),max(infogain)

#构建决策树
def CreateDecesionTree(dataset,delta):
#如果所有label均为同一类,则为单节点,并将其作为类标记
label=[x[-
d0a2
1] for x in dataset]
if len(set(label))==1:
return label[0]
#寻找当前数据集特征最大信息增益
max_feainfo_index,max_feainfo_val=find_max_InfoGain(dataset)
#判断增益是否大于阈值,如果小于,则为单节点树,节点为D中最多的类作为类标记
if max_feainfo_val<delta:
label_count=Counter(label)
return max(label_count.items(), key=lambda x: x[1])[0]
#以上都不满足,说明树可以继续生长,使用递归的方式继续建立树
#以字典方式来构建决策树,第一个存特征的标签,第二个存特征取的不同值,每一层决策树都由这两个字典共同构建
fea_dic={}
fea_val_dic={}
#首先找出最大信息增益的特征的标签
max_fea=[x[max_feainfo_index] for x in dataset]
max_fea_diff=list(set(max_fea))
fea_label=fea_labels[max_feainfo_index]
#根据选出的特征先划分数据集,然后递归生成决策树
for diff_val in max_fea_diff:
dataset_new=[]
for val in dataset:
if diff_val==val[max_feainfo_index]:
dataset_new.append(val[:max_feainfo_index]+val[max_feainfo_index+1:])
fea_val_dic[diff_val]=fea_val_dic.get(diff_val,CreateDecesionTree(dataset_new,delta))
fea_dic[fea_label]=fea_dic.get(fea_label,fea_val_dic)
return fea_dic

#最后可以直接用以下方式生成决策树:
CreateDecesionTree(dataset,0.001)


生成的决策树如下:

{‘house’: {‘no’: {‘work’: {‘no’: ‘no’, ‘yes’: ‘yes’}}, ‘yes’: ‘yes’}}

这里决策树的每一层都用了两级字典来表示,第一级是特征标签,第二级是特征取值。

构建随机森林

构建随机森林实质就是构建多颗决策树。里面的每一颗决策树都是没有关联的。

在构建决策树的过程中,有两点改进。

第一,对于训练数据是通过采样得到的。例如,训练集有N个样本,那么我们每次构建决策树时,都会又放回地对这个训练集采样N次,得到N个数据作为真正的训练集,这样做会出现的问题就是样本数据集里有很多重复的(一个通常说法是只有60%多的非重复数据)。这样,每一棵树的样本都不是全部样本,这就有效避免了过拟合问题。

第二,对于特征,也是通过采样得到的。例如,原来有M个特征,现在我们采样m个,使得m<=M。

通过以上两点,就能建立随机森林了。最后,当一个新样本进来时,森林里每一颗决策树都会产生一个结果,看看哪一类得到结果多,就认为样本属于那一类了。

对于随机森林的本质的一个比喻,引用如下:

按这种算法得到的随机森林中的每一棵都是很弱的,但是大家组合起来就很厉害了。我觉得可以这样比喻随机森林算法:每一棵决策树就是一个精通于某一个窄领域 的专家(因为我们从M个feature中选择m让每一棵决策树进行学习),这样在随机森林中就有了很多个精通不同领域的专家,对一个新的问题(新的输入数 据),可以用不同的角度去看待它,最终由各个专家,投票得到结果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息