决策树
决策树是一种基本的分类和回归算法。它可以认为是if-then规则的集合,也可以认为是特征空间与类空间上的条件概率分布。其主要优点是模型具有可读性,分类速度快。学习时利用训练数据,根据损失函数最小化的原则建立决策树模型。预测时,对新的数据,利用决策树模型进行分类。
决策树学习通常包含3个步骤:特征选择,决策树的生成和决策树的剪枝。
决策树模型
决策树由结点和有向边组成。结点有内部结点和叶子结点两种类型。内部结点表示一个属性或特征,叶子结点表示一个类别。
如下图所示,圆形表示内部结点,方形表示叶子结点。
决策树可以看做if-then规则的集合,从决策树的根节点到叶结点的每一条路径对应一条规则,路径上的内部结点表示规则的条件,而叶结点的类对应着符合该规则的类别。决策树的路径或对应的if-then规则集合具有一个重要的性质,互斥并且完备。即每一个实例对应着一条路径(1对1的关系)。
决策树学习,假设给定训练数据集$D=\{(x_1,y_1),(x_2,y_2),...,(x_n,y_n)\}$,其中$x_i=(x_i^{(1)},x_i^{(2)},...,x_i^{(n)})$为特征向量,$y_i=\{1,2,...,K\},i\in \{1,2,...,N\}$为类标记。N为样本容量,n为特征数目(维度)。学习的目标是根据给定的训练数据集构建一个决策树模型,使它能够对实例进行正确的分类。
决策树学习本质上是从训练数据中归纳出一组分类规则。从另一个角度来看,决策树学习是由训练数据集估计条件概率模型。基于特征空间划分的类的条件概率模型有无穷多个。我们选择的条件概率模型应该不仅对训练数据有很好的拟合,而且对未知数据有很好的预测。
决策树学习用损失函数表示这一目标。决策树学习的损失函数通常是正则化的极大似然损失函数。决策树学习的策略是以损失函数为目标函数的最小化。
决策树学习的算法通常是一个递归的选择最优特征,并根据该特征对训练数据进行分割,使得对各个子数据集有一个最好的分类的过程。这一过程对应着特征空间的划分,也对应着决策树的构建。
以上方法生成的决策树可能对训练数据有很好的分类能力,但对未知的测试数据却未必有很好的分类能力,即可能发生过拟合现象。我们需要对已生成的树自下而上进行剪枝,将树变得更简单,从而使它具有更好的泛化能力。
如果特征数量很多,也可以在决策树学习开始的时候,对特征进行选择,只留下对训练数据有足够分类能力的特征。
决策树学习算法包含特征选择、决策树的生成与决策树的剪枝过程。由于决策树表示一个条件概率分布,所以深浅不同的决策树对应着不同复杂度的概率模型。决策树的生成对应于模型的局部选择,决策树的剪枝对应于模型的全局选择。决策树的生成只考虑局部最优,相对地,决策树的剪枝则考虑全局最优。
决策树学习的常用算法有ID3、C4.5和CART,以下结合算法分别介绍决策树算法的3个过程。
特征选择
特征选择在于选取对数据具有分类能力的特征。这样可以提高决策树学习的效率。通常特征选择的准则是信息增益或信息增益比。
特征选择是决定用哪个特征来划分特征空间。
信息增益
在信息论和概率统计中,熵(Entropy)是表示随机变量不确定性的度量。设X为一个取有限个值的离散随机变量,其概率分布为
$$P(X=x_i)=p_i,i=1,2,...,n$$
则随机变量X的熵定义为:
$$H(X)=-\sum_{i=1}^np_iInp_i \tag{1}$$
在式(1)中,若$p_i=0$,则定义$0In0=0$。通常式(1)中的对数取自然对数,这时熵的单位分别称作比特(bit)或纳特(nat)。由定义可知,熵只依赖于X的分布,而与X的取值无关,所以也可将X的熵记作H(p),即
$$H(p)=-\sum_{i=1}^np_iInp_i \tag{2}$$
熵越大,随机变量的不确定性就越大,从定义可以验证:
$$0\leq H(P) \leq Inn \tag{3}$$
当随机变量只取两个值时,例如0、1,即X的分布为$P(X=1)=p,P(X=0)=1-p,0\leq p \leq 1$,熵为
$$H(p)=-pInp-(1-p)In(1-p)\tag{4}$$
这时,熵H(p)随概率p变化的曲线如下图所示
当p=0或p=1时,随机变量的不确定性为0,当p=0.5时,H(p)=1,熵取值最大,随机变量不确定性最大。
设有随机变量(X,Y)其联合概率分布为
$$P(X=x_i, Y=y_j)=p_{ij},i=1,2,...,n;j=1,2,...,m$$
条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性。随机变量X给定的条件下随机变量Y的条件熵H(Y|X),定义为X给定条件下Y的条件概率分布的熵对X的数学期望
$$H(Y|X)=\sum_{i=1}^np_iH(Y|X=x_i)\tag{5}$$
其中$p_i=p(X=x_i),i=1,2,...,n$。
当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的熵与条件熵分别称为经验熵和经验条件熵。
信息增益(information gain)表示得知特征X的信息而使得类Y的信息的不确定性减少的程度。
信息增益:特征A对训练数据集D的信息增益g(D, A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即
$$g(D,A)=H(D)-H(D|A)\tag{6}$$
一般地,熵H(Y)与条件熵H(Y|X)之差称为互信息(mutual information)。决策树学习中的信息增益等价于训练数据集中类与特征的互信息。
决策树学习应用信息增益准则选择特征。给定训练数据集D和特征A,经验熵H(D)表示对数据集进行分类的不确定性。而经验条件熵H(D|A)表示在特征A给定的条件下对数据集D进行分类的不确定性。那么它们的差,即信息增益,就表示由于特征A而使得对数据集D的分类的不确定性减少的程度,显然,对于数据集D而言,信息增益依赖于特征,不同的特征往往具有不同的信息增益,信息增益大的特征具有更强的分类能力。
根据信息增益准则的特征选择方法是:对训练数据集(或子集)D,计算其每个特征的信息增益,并比较它们的大小,选择信息增益最大的特征。
设训练数据集为D,D的样本容量为N(N个样本)。设有K个类别$c_k,k=1, 2,...,K$,$N_k$为类别为$c_k$的样本容量,$\sum_{k=1}^KN_k=N$。设特征A有n个不同的取值$\{a_1,a_2,...,a_n\}$,根据特征A的取值将D划分为n个子集$D_1,D_2,...,D_n,N_i$表示$D_i$的样本个数,$\sum_{i=1}^nN_i=N$,记子集$D_i$中属于类$C_k$的样本的集合为$D_{ik}$,即$D_{ik}=D_i\bigcap C_k,N_{ik}$表示$D_{ik}$的样本个数。于是信息增益的算法如下:
输入:训练数据集D和特征A;
输出:特征A对D的信息增益。
下面以表5.1的数据为例,分别计算信息增益
- 计算数据集D的经验熵H(D)
$$H(D)=-\sum_{k=1}^K\frac{N_k}{N}In\frac{N_k}{N}$$
上表中数据集共有2个类别,即K=2,类别为否的样本$D_1$数目为6,类别为是的样本$D_2$数目为9,所以有
$$H(D)=-\frac{6}{15}In\frac{6}{15}-\frac{9}{15}In\frac{9}{15}=0.673$$
- 计算年龄A对数据集D的条件经验熵
$$H(D|A)=\sum_{i=1}^n\frac{N_i}{N}H(D_i)=-\sum_{i=1}^n\frac{N_i}{N}\sum_{k=1}^{K}\frac{N_{ik}}{N_i}In\frac{N_{ik}}{N_i}$$
$\begin{split} H(D|A)&=\frac{5}{15}H(D_1)+\frac{5}{15}H(D_2)+\frac{5}{15}H(D_3)\\&=\frac{5}{15}(-\frac{2}{5}In\frac{2}{5}-\frac{3}{5}In\frac{3}{5})+\frac{5}{15}(-\frac{2}{5}In\frac{2}{5}-\frac{3}{5}In\frac{3}{5})+\frac{5}{15}(-\frac{4}{5}In\frac{4}{5}-\frac{1}{5}In\frac{1}{5})\\ &=0.615\end{split}$
- 计算信息增益
$$g(D,A)=H(D)-H(D|A)=0.673-0.615=0.058$$
- 按照这样的方式计算其余3个特征(”有工作“、”有自己的房子“、”信贷情况“)的信息增益。
通过计算,得到特征($A_3$,有自己的房子)的信息增益最大,最终选择特征$A_3$作为最优特征。
信息增益比
信息增益值的大小是相对于训练数据集而言的,并没有绝对意义。在分类问题困难时,也就是说在训练数据集的经验熵大的时候,信息增益值会偏大。反之,信息增益值会偏小。比如一个数据集中包含日期特征或是序号等混乱的特征(特征的经验熵很大),这时信息增益会很大。而使用信息增益比(Information gain ratio)可以对这一问题进行校正。这是特征选择的另一准则。
信息增益比:特征A对训练数据集D的信息增益比$g_R(D,A)$定义为其信息增益g(D,A)与训练数据集D的经验熵H(D)之比:
$$g_R(D,A)=\frac{g(D,A)}{H(D)}\tag{7}$$
决策树的生成
ID3算法
ID3算法的核心是在决策树各个结点上应用信息增益准则选择特征,递归地构建决策树。具体方法是:从根节点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子节点;再对子节点递归地调用以上方法,构建决策树;直到所有特征的信息增益均很小或没有特征可以选择为止。最后得到一个决策树。ID3相当于用极大似然法进行概率模型的选择。
ID算法
输入:训练数据集D,特征集A,阈值$\xi$
输出:决策树T
- 若D中所有实例属于同一类$C_k$,则T为单节点树,并将类$C_k$作为该节点的类标签,并返回T;
- 若$A=\oslash$,则T为单节点树,并将D中实例数最大的类$C_k$(包含样本最多的类别)作为该节点的类标记,并返回T;
- 否则,按公式(6)计算A中每个特征对于数据集D的信息增益,选择信息增益最大的特征$A_g$;
- 如果$A_g$的信息增益小于阈值$\xi$,则置T为单节点树,并将D中实例树最大的类$C_k$作为该节点的类标记,返回T;
- 否则,对$A_g$的每一可能值$a_i$,依$A_g=a_i$将D分割为若干非空子集$D_i$,将$D_i$中实例数最大的类作为标记,构建子节点,由结点机器子节点构成数T,返回T;
- 对第i个子节点,以$D_i$为训练集,以$A-\{A_g\}$为特征集,递归地调用步骤1-5,得到子树$T_i$,返回$T_i$。
构建决策树的代码如下:
class DecisionTree:
def __init__(self, thresh=1e-2, criterion='gain'):
self.tree = None
self.thresh = thresh
self.criterion = self.calc_gain if criterion == 'gain'else self.calc_gain_ratio
self.num_leaf = 0
self.feat_names = None
def fit(self, x_train, y_train):
self.tree = self._construct(x_train, y_train)
print('Finish train')
def predict(self, x_test,y_test=None):
# 预测
y_pred = []
x_test = np.array(x_test)
x_test = x_test.reshape((x_test.shape[0], -1))
for x in x_test:
y_pred.append(self._search(x))
if y_test is not None:
self._score(y_test, y_pred)
return y_pred
def _score(self, y_test, y_pred):
# 计算得分
return np.count_nonzero(y_pred=y_test) / len(y_test)
def _search(self, x_test):
res = self.tree
key = list(res.values())[0]
while key is not None:
fname = list(res.keys())[0]
fidx = self.feat_names.index(fname)
res = res[fname][x_test[fidx]]
key = list(res.values())[0]
return list(res.keys())[0]
def calc_entropy(self, label):
# 计算数据集的经验熵
res = 0
for lab in label.unique():
ratio = len(label[label == lab]) / len(label)
res += ratio * np.log(ratio)
return -res
def calc_cond_entropy(self, feature, label):
# 计算数据集的经验条件熵
res = 0
for f in feature.unique():
idx = feature == f
fcount = idx.sum()
fratio = fcount / len(feature)
fres = 0
for lab in label.unique():
ratio = sum(label[idx] == lab) / fcount
if ratio != 0:
fres += ratio * np.log(ratio)
else:
fres += 0
res += fratio * fres
return -res
def calc_gain(self, feature, label):
"""
Calculate information gain for specific feature
计算指定特征对数据集的信息增益
Params:
feature(pandas.Series): feature A
label(pandas.Series): labels
"""
#
exp_ent = calc_entropy(label)
cond_ent = calc_cond_entropy(feature, label)
return exp_ent - cond_ent
def calc_gain_ratio(self, feature, label):
"""
Calculate information gain ratio for specific feature
计算指定特征对数据集的信息增益比
Params:
feature(pandas.Series): feature A
label(pandas.Series): labels
"""
exp_ent = calc_entropy(label)
cond_ent = calc_cond_entropy(feature, label)
return (exp_ent - cond_ent)/ exp_ent
def _construct(self, x, y):
"""
构建二叉树
Params:
x(Pandas.DataFrame): train features
y(Pandas.Series): train labels
"""
ck, cnts = np.unique(y, return_counts=True)
# 如果只有一个类别
if len(ck) == 1:
self.num_leaf += 1
return {ck[0]: None}
# 如果没有特征
if len(x) == 0:
self.num_leaf += 1
return {ck[cnts.argmax(0)]: None}
self.feat_names = list(x.columns)
# 逐特征计算信息增益
max_gain = 0
max_fidx = 0
for i in range(x.shape[1]):
cur_gain = self.criterion(x.iloc[:, i], y)
if cur_gain > max_gain:
max_gain = cur_gain
max_fidx = i
# 如果最大的信息增益小于阈值, 则返回
if max_gain < self.thresh:
self.num_leaf += 1
return {ck[cnts.argmax(0)]: None}
fk = np.unique(x.iloc[:, max_fidx])
res = dict()
# 对于特征的每个取值,往下构建节点
for i in fk:
fidx = x.iloc[:, max_fidx] == i
res.update({i: self._construct(x[fidx], y[fidx])})
self.tree = {x.columns[max_fidx]: res}
return self.tree
ID3算法只有树的生成,所以该算法生成的树容易产生过拟合。
C4.5的生成算法
C4.5算法采用信息增益率准则来选择特征, 过程同上。
总结
本文主要介绍了决策树算法的实现过程, 并分别使用ID3和C4.5算法构建了决策树分类模型。
- 分类决策树模型是表示基于特征对实例进行分类的树形结构。决策树可以转换成一个if-then规则的集合,也可以看作是定义在特征空间划分上的类的条件概率分布。
- 决策树学习旨在构建一个与训练数据拟合很好,并且复杂度小的决策树。因为从可能的决策树中直接选取最优决策树是NP完全问题。现实中采用启发式方法学习次优的决策树。
- 决策树学习算法包括3部分:特征选择、树的生成和树的剪枝。常用的算法有ID3、C4.5和CART。
- 决策树特征选择使用的主要准则有信息增益(ID3)、信息增益比(C4.5)和基尼指数(CART)。ID3算法只能处理离散特征,C4.5和CART既可以处理离散特征也可以处理连续特征。
Reference
李航《统计学习方法》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。