分类决策树
决策树由结点和有向边组成,其中结点有两种类型:内部节点和叶节点。内部节点表示一个特征和一个属性,叶节点表示一个类。
决策树与if-then规则转化
可以将决策树看作一个if-then规则的集合,由决策树的根结点到叶结点的每一条路径构建一条规则;路径上内部节点的特征对应着规则的条件,而叶结点的类对应着规则的结论。
决策树的学习
假设给定训练数据集
其中,
=
为输入实例(特征向量),n为特征个数,
∈{1,2,…,K}为类标记,
为样本容量。决策树学习的目标是根据给定的训练数据集构建一个决策树模型,使它能够对实例进行正确的分类。
决策树的学习是为了归纳出一组分类规则,估计出特征空间划分的条件概率模型,要求具有较好的泛化性能。
决策树学习的目标是使损失函数最小化。由于从所有可能的决策树树中选取最优决策树是NP完全问题,因此需要采用一些启发式算法来增加运算速率。此时得到的解是次优解。
生成的决策树很有可能产生过拟合,因此需要进行剪枝来增加模型的泛化性能。具体来说,就是去掉过于细分的叶结点,使其退回到父结点,甚至更高的结点,然后将父结点或更高的结点改为新的叶结点。
如果特征数量很多,可以在一开始就对特征进行选择。
特征选择
特征选择问题
决定用哪一个特征来划分特征空间。
通常特征选择的准则是信息增益或信息增益比。
信息增益
熵(entropy)是表示随机变量不确定性的度量。设X为一个取有限个值的离散随机变量,其概率分布为
则随机变量的熵定义为:
式中,对数通常以2为底或以e为底,此时熵的单位分别称作比特(bit)或纳特(nat)。
熵越大,随机变量的不确定就越大。从定义可以验证
当随机变量只取两个值时,例如0,1时,即X的分布为
熵为
随机变量X给定条件下随机变量Y的条件熵
,定义为X给定条件下Y的条件概率分布的熵对X的期望
这里,
。
信息增益表示得知特征X的信息而使得类Y的信息的不确定性减少的程度。特征A对训练集D的信息增益
,定义为
下面来编程计算信息增益
首先输入数据(来源:《统计学习方法》)
import numpy as np
A = [['青年', '否', '否', '一般', '否'],
['青年', '否', '否', '好', '否'],
['青年', '是', '否', '好', '是'],
['青年', '是', '是', '一般', '是'],
['青年', '否', '否', '一般', '否'],
['中年', '否', '否', '一般', '否'],
['中年', '否', '否', '好', '否'],
['中年', '是', '是', '好', '是'],
['中年', '否', '是', '非常好', '是'],
['中年', '否', '是', '非常好', '是'],
['老年', '否', '是', '非常好', '是'],
['老年', '否', '是', '好', '是'],
['老年', '是', '否', '好', '是'],
['老年', '是', '否', '非常好', '是'],
['老年', '否', '否', '一般', '否']]
data = np.array(A)
X1 = ['青年', '中年', '老年']
X2 = ['是', '否']
X3 = ['是', '否']
X4 = ['一般', '好', '非常好']
Y = ['是', '否']
接下来,计算信息增益。在算信息增益的过程中,需要计算出每一个属性所对应的信息增益,然后挑选出最大的信息增益所对应的属性,作为划分特征空间的依据。
def information_gain():
y = data[:, 4].tolist()
y_dic = dict(Counter(y))
Hy1 = y_dic['是']/len(y)
Hy2 = y_dic['否']/len(y)
HD = -Hy1*np.log2(Hy1)-Hy2*np.log2(Hy2)#计算训练集的经验熵
#计算第一个属性的信息增益
t1 = []
t2 = []
t3 = []
A1 = data[:, 0].tolist()
for i in range(len(A1)):
if A1[i] == '青年':
t1.append(i)
elif A1[i] == '老年':
t2.append(i)
else:
t3.append(i)
y11 = data[t1, 4].tolist()
y12 = data[t2, 4].tolist()
y13 = data[t3, 4].tolist()
y11_dic = dict(Counter(y11))
y12_dic = dict(Counter(y12))
y13_dic = dict(Counter(y13))
HA11 = -y11_dic['是']/len(y11)*np.log2(y11_dic['是']/len(y11))-y11_dic['否']/len(y11)*np.log2(y11_dic['否']/len(y11))
HA12 = -y12_dic['是']/len(y12)*np.log2(y12_dic['是']/len(y12))-y12_dic['否']/len(y12)*np.log2(y12_dic['否']/len(y12))
HA13 = -y13_dic['是']/len(y13)*np.log2(y13_dic['是']/len(y13))-y13_dic['否']/len(y13)*np.log2(y13_dic['否']/len(y13))
HA1 = len(t1)/len(y)*HA11 + len(t2)/len(y)*HA12 + len(t3)/len(y)*HA13
gDA1 = HD - HA1
print('第一个属性(年龄)对于训练集的信息增益为:{}'.format(gDA1))
# 计算第二个属性的信息增益
t1 = []
t2 = []
A1 = data[:, 1].tolist()
for i in range(len(A1)):
if A1[i] == '是':
t1.append(i)
else:
t2.append(i)
y11 = data[t1, 4].tolist()
y12 = data[t2, 4].tolist()
y11_dic = dict(Counter(y11))
y12_dic = dict(Counter(y12))
y11_dic['否'] = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000001#避免出现log0的情况
HA11 = -y11_dic['是'] / len(y11) * np.log2(y11_dic['是'] / len(y11)) - y11_dic['否'] / len(y11) * np.log2(
y11_dic['否'] / len(y11))
HA12 = -y12_dic['是'] / len(y12) * np.log2(y12_dic['是'] / len(y12)) - y12_dic['否'] / len(y12) * np.log2(
y12_dic['否'] / len(y12))
HA1 = len(t1) / len(y) * HA11 + len(t2) / len(y) * HA12
gDA1 = HD - HA1
print('第二个属性(有工作)对于训练集的信息增益为:{}'.format(gDA1))
# 计算第三个属性的信息增益
t1 = []
t2 = []
A1 = data[:, 2].tolist()
for i in range(len(A1)):
if A1[i] == '是':
t1.append(i)
else:
t2.append(i)
y11 = data[t1, 4].tolist()
y12 = data[t2, 4].tolist()
y11_dic = dict(Counter(y11))
y12_dic = dict(Counter(y12))
y11_dic['否'] = 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
HA11 = -y11_dic['是'] / len(y11) * np.log2(y11_dic['是'] / len(y11)) - y11_dic['否'] / len(y11) * np.log2(
y11_dic['否'] / len(y11))
HA12 = -y12_dic['是'] / len(y12) * np.log2(y12_dic['是'] / len(y12)) - y12_dic['否'] / len(y12) * np.log2(
y12_dic['否'] / len(y12))
HA1 = len(t1) / len(y) * HA11 + len(t2) / len(y) * HA12
gDA1 = HD - HA1
print('第三个属性(有房子)对于训练集的信息增益为:{}'.format(gDA1))
# 计算第四个属性的信息增益
t1 = []
t2 = []
t3 = []
A1 = data[:, 3].tolist()
for i in range(len(A1)):
if A1[i] == '一般':
t1.append(i)
elif A1[i] == '好':
t2.append(i)
else:
t3.append(i)
y11 = data[t1, 4].tolist()
y12 = data[t2, 4].tolist()
y13 = data[t3, 4].tolist()
y11_dic = dict(Counter(y11))
y12_dic = dict(Counter(y12))
y13_dic = dict(Counter(y13))
y13_dic['否'] = 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
HA11 = -y11_dic['是'] / len(y11) * np.log2(y11_dic['是'] / len(y11)) - y11_dic['否'] / len(y11) * np.log2(
y11_dic['否'] / len(y11))
HA12 = -y12_dic['是'] / len(y12) * np.log2(y12_dic['是'] / len(y12)) - y12_dic['否'] / len(y12) * np.log2(
y12_dic['否'] / len(y12))
HA13 = -y13_dic['是'] / len(y13) * np.log2(y13_dic['是'] / len(y13)) - y13_dic['否'] / len(y13) * np.log2(
y13_dic['否'] / len(y13))
HA1 = len(t1) / len(y) * HA11 + len(t2) / len(y) * HA12 + len(t3) / len(y) * HA13
gDA1 = HD - HA1
print('第四个属性(信贷情况)对于训练集的信息增益为:{}'.format(gDA1))
运行结果如下图所示:
通过比较,我们应当选择A3(有房子)作为划分特征空间的依据。
由于采用信息增益作为选择特征的依据时会有偏向于选择取值较多的特征的问题,因此可以采用信息增益比来修正。
信息增益比定义为信息增益
与训练数据集D关于特征A的值的熵
之比,即
其中,
,
是特征
取值的个数。