决策树
5.1 决策树模型与学习
分类决策树模型是一种描述对实例进行分类得树形结构。内部节点表示一个特征或属性,叶子节点表示一个类。
路径上内部节点的特征对应着规则的结论,而叶节点的类对应着规则的结论。决策树的路径具有一个重要的性质:互斥并且完备,每一个实例都被一条路径或一条规则所覆盖,且只被一条路径或一条规则所覆盖。
- 决策树与条件概率
决策树还可以表示给定特征条件下类的条件概率分布。下图中(a)的大正方形表示特征空间,每个小矩形表示一个单元。假设 Y Y Y的取值只有-1和+1,小矩形中的式子表示单元的类。(b)图表示特征空间划分确定时,特征单元给定下的条件概率分布。当某个单元 c c c的条件概率满足 P ( Y = + 1 ∣ X = c ) > 0.5 P(Y=+1|X=c)>0.5 P(Y=+1∣X=c)>0.5时,落在这个单元的实例都被视为+1。
- 决策树学习
决策树学习本质上是从训练数据集中归纳出一组分类规则。决策树可能不止一个也可能一个都没有,所以目标是找到与训练数据矛盾较小的决策树,同时具有很好的泛化能力。
学习过程:
(1)首先构造根节点,将所有训练数据都放在根节点。
(2)选取一个最优特征,按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。
(3)若这些子集能够被基本正确分类,那么构建叶子节点,并将这些子集分到所对应的叶子节点中去;如果还有子集不能被基本正确分类,那么就对这些子集选择新的最优特征,继续进行分割,构建相应的结点。
(4)递归(2)(3),知道所有训练数据子集被基本正确分类,或者没有合适的特征。
通过这样生成的决策树,虽然对训练数据有较好的拟合效果,但是对于测试数据可能会发生过拟合现象,所以需要适当的对树进行剪枝,去掉过于细分的叶子节点。
决策树的生成对应于模型的局部选择(当前分割后损失函数最小化为目的),决策树的剪枝对应于模型的全局选择(测试集上的损失函数尽可能小) - 决策树学习算法:特征选择、决策树的生成、决策树的剪枝
5.2 特征选择
特征选取的目的:选取对训练数据具有分类能力的特征,提高决策树学习的效率。常见的选择指标为信息增益与信息增益比。
5.2.1 信息增益
- 熵:表示随机变量不确定性的度量,熵越大,随机变量的不确定性越大,数据混乱程度越大,不整齐;且熵仅依赖于X的分布,与X的取值范围无关。
P ( X = x i ) = p i i = 1 , 2 , . . . . n H ( X ) = − ∑ i = 1 n p i log p i P(X=x_i)=p_i\ \ \ i=1,2,....n\\ H(X)=-\sum\limits_{i=1}^{n}p_i\log p_i P(X=xi)=pi i=1,2,....nH(X)=−i=1∑npilogpi
H ( X ) H(X) H(X)即为随机变量X的熵。
P ( X = x i , Y = y i ) = p i j i = 1 , 2 , . . . , n ; j = 1 , 2 , . . . , m H ( Y ∣ X ) = ∑ i = 1 n p i H ( Y ∣ X = x i ) P(X=x_i,Y=y_i)=p_{ij} \ \ \ i=1,2,...,n;\ j=1,2,...,m\\ H(Y|X)=\sum\limits_{i=1}^np_iH(Y|X=x_i) P(X=xi,Y=yi)=pij i=1,2,...,n; j=1,2,...,mH(Y∣X)=i=1∑npiH(Y∣X=xi)
H ( Y ∣ X ) H(Y|X) H(Y∣X)表示随机变量X给定条件下随机变量Y的条件熵,换句话说,为X给定条件下Y的条件概率分布的熵对X的数学期望。
当熵和条件熵中的概率由数据统计(极大似然估计)得到,则对应称为经验熵和经验条件熵。 - 信息增益:集合D的经验熵H(D)与特征A在给定条件下D的经验条件熵H(D|A)之差,称为信息增益g(D,A)
g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D,A)=H(D)-H(D|A) g(D,A)=H(D)−H(D∣A)
该值表示由于特征A使得对数据集D的分类的不确定性减少的程度。信息增益越大,表示该特征对不确定性减少的程度越大,使得分类更偏向稳定。
5.2.2 信息增益比
信息增益作为划分时,为了尽可能降低不确定性,会出现偏向于选择取值较多的特征的问题,为了校正该问题,引入了信息增益比
- 信息增益比:信息增益 g ( D , A ) g(D,A) g(D,A)与训练数据集D关于特征A的值的熵 H A ( D ) H_A(D) HA(D)d的比值为信息增益比 g R ( D , A ) g_R(D,A) gR(D,A)。
g R ( D , A ) = g ( D , A ) H A ( D ) H A ( D ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ l o g 2 ∣ D i ∣ ∣ D ∣ n 为 A 的 特 征 取 值 个 数 g_R(D,A)=\frac{g(D,A)}{H_A(D)}\\ H_A(D)=-\sum\limits_{i=1}^n\frac{|D_i|}{|D|}log_2\frac{|D_i|}{|D|} \ \ \ n为A的特征取值个数 gR(D,A)=HA(D)g(D,A)HA(D)=−i=1∑n∣D∣∣Di∣log2∣D∣∣Di∣ n为A的特征取值个数
python代码实现例题:信息增益与信息增益比
import numpy as np
import math
#直接更改x,y即可
x = [[1, 0, 0, 1],
[0, 1, 1, 1],
[0, 0, 1, 0]]
y = [0, 0, 1]
feature_num = np.shape(x)[1]
y_len = len(y)
feature = np.array(x)
for i in range(feature_num):
_feature = feature[:, i]
temp_condition_ent = 0
temp_ent_i = 0
HA_D = 0
print(_feature)
for j in set(_feature):
D_i = _feature.tolist().count(j)
temp_ent = 0
for k in set(y):
temp_ent += -(y.count(k) / y_len) * math.log(y.count(k) / y_len)#H(D)
D_ik = 0
for index in range(len(y)):
if y[index] == k and _feature[index] == j:
D_ik = D_ik + 1
if D_ik != 0:
temp_ent_i += -(D_ik / D_i) * math.log(D_ik / D_i)
else:
temp_ent_i = 0
temp_condition_ent += (D_i / y_len) * temp_ent_i#H(D|A)
conditon_ent = temp_ent - temp_condition_ent#g(D|A)
HA_D += -(D_i / y_len) * math.log(D_i / y_len)#H_A(D)
conditon_ent_ratio = conditon_ent / HA_D #g_R(D,A)
print(conditon_ent)
print(conditon_ent_ratio)
5.3 决策树的生成
5.3.1 ID3算法(python实现)
ID3算法的核心是决策树的各个节点上应用信息增益准则选择特征,递归的构建决策树,直到所有特征信息的信息增益均很小或没有特征选择位置。
算法5.2 ID3算法
输入:训练数据集D, 特征集A的阈值 ϵ \epsilon ϵ
输出:决策树T
- 若D中所有的实例属于同一类 C k C_k Ck,则T为单节点树,并将类 C k C_k Ck作为该节点的类标记,返回T;
- 若 A = ∅ A=\varnothing A=∅,则T为单节点树,并将D中实例数最大的类 C k C_k Ck作为该节点的类标记,返回T;
- 否则,计算A中各特征对D的信息增益,选择信息增益最大的特征 A g A_g Ag;
- 如果 A g A_g Ag的信息增益小于阈值 ϵ \epsilon ϵ,则置T为单节点树,并将D中实例数最大的类 C k C_k Ck作为该节点的类标记,返回T;
- 否则, A g A_g Ag的每一可能值 a i a_i ai,依照, A g = a i A_g=a_i Ag=ai将D分割为若干非空子集 D i D_i Di,将 D i D_i Di中实例数最大的类作为标记,构建子节点,由结点及其子节点构成树T,返回T;
- 对第i个子节点,以 D i D_i Di为训练集,以 A − { A g } A-\{A_g\} A−{ Ag}为特征集,递归地调用步(1)到(5),得到子树 T i T_i Ti,返回 T i T_i Ti。
python实现ID3算法(参考机器学习实战)
from math import log
# 计算信息熵
def calcShannonEnt(dataSet):
numEntries = len(dataSet) # 样本数
labelCounts = {
}
for featVec in dataSet: # 遍历每个样本
currentLabel = featVec[-1] # 当前样本的类别
if currentLabel not in labelCounts.keys(): # 生成类别字典
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts: # 计算信息熵
prob = float(labelCounts[key]) / numEntries
shannonEnt = shannonEnt - prob * log(prob, 2)
return shannonEnt
# 划分数据集,axis:按第几个属性划分,value:要返回的子集对应的属性值
def splitDataSet(dataSet, axis, value):
retDataSet = []
featVec = []
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis + 1:])
retDataSet.append(reducedFeatVec)
return retDataSet
# 选择信息增益最大的特征划分数据
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 # 属性的个数
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeatures): # 对每个属性技术信息增益
featList = [example[i] for example in dataSet]
uniqueVals = set(featList) # 该属性的取值集合
newEntropy = 0.0
for value in uniqueVals: # 对每一种取值计算信息增益
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet) / float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy
if (infoGain > bestInfoGain): # 选择信息增益最大的属性
bestInfoGain = infoGain
bestFeature = i
return bestFeature
# 通过排序返回出现次数最多的类别
def majorityCnt(classList):
classCount = {
}
for vote in classList:
if vote not in classCount.keys(): classCount[vote] = 0
classCount[vote] += 1
sortedClassCount = sorted(classCount.iteritems(),
key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
# 递归构建决策树
def createTree(dataSet, labels):
classList = [example[-1] for example in dataSet] # 类别向量
if classList.count(classList[0]) == len(classList): # 如果只有一个类别,返回
return classList[