文章目录
1、信息熵
- 信息熵,用来描述系统信息量的不确定度,不确定性越大,则信息熵越大,反之,信息熵越小。
1.1 信息熵公式
假设随机变量X具有M个值,分别为: V1,V2 ,… ,Vm ,并且各个值出现的概率(各概率值的和为1)如下:
则变量X的信息熵为:
1.2 概率分布与信息熵
- 对于信息熵,可以用概率分布来衡量:对于随机变量X,其分布越均衡,则不确定性越多,信息熵越大;其分布越不均衡,则不确定性越小,信息熵越小。
- 如果把概率分布转换到数据集上,信息熵体现的就是数据的不纯度,即样本类别的均衡程度:
样本类别越均衡,不纯度越高,信息熵越大;样本类别越不均衡,不纯度越低,信息熵越小。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams["font.size"] = 12
# 假设随机变量X可以取两个值,一个值的概率为p,则另外一个值的概率为1 - p。
p = np.linspace(0.01, 0.99, 100)
# 计算在不同概率分布下的信息熵。
h = -p * np.log2(p) - (1 - p) * np.log2(1 - p)
plt.plot(p, h)
plt.xlabel("概率")
plt.ylabel("信息熵")
plt.title("概率-信息熵对比")
plt.show()
从上图可以看出,概率p越大时,分布越均衡,其信息熵也越来越大,并在概率为0.5时达到最大值,此时两个分类的概率相等,分布也最均衡。
2、决策树
2.1 决策树概念
- 决策树是一种树形结构,通过特征的不同来将样本数据划分到不同的分支(子树)中,最终,每个样本一定会划分到一个叶子节点中。
- 我们可以将每个特征视为一个问题(提问),特征值的不同,就视为样本给出的不同答案,然后,我们就可以根据一系列问题(特征),将样本划分到不同的叶子节点中。
- 决策树是一种非参数监督学习方法,可以用于分类与回归。
2.2 决策树预测原理
- 当对训练集进行训练,构建决策树后,我们就可以对未知样本进行预测。
- 预测的过程为:根据未知样本的特征,逐步进行分支选择(回答问题),直到叶子节点为止。
然后我们就可以使用该叶子节点中的已知样本来预测该未知样本。 - 对于分类树,使用叶子节点中类别数量最多的类别,作为未知样本的类别。
- 对于回归树,使用叶子节点中所有样本的均值,作为未知样本的类别。
3、分类决策树
3.1 信息增益
- 信息增益在决策树算法中是用来选择特征的指标,信息增益越大,则这个特征的选择性越好。
信息增益(IG-Information gain)定义如下:
- 通过定义可知:信息增益就是父节点的不纯度减去所有子节点不纯度(加权)。
- 在选择特征进行划分时,特征的顺序不是任意的,而是应该选择在分割样本集后,能够使得所有子节点不纯度最低(加权)的特征。
- 由于父节点的不纯度是不变的,因此,能够让所有子节点不纯度最小的特征,实际上也就是能够所得信息增益最大的特征。 而这,也正是训练分类决策树时,选择特征顺序的依据。
3.2 训练规则
训练分类决策树的具体规则如下:
(1)将每一个特征看成是一种分裂可能,特征可以分为离散型与连续性。
- 对于离散型特征,每一个类别可以划分为一个子节点(多叉树),或者属于类别A与不属于类别A(二叉树)。
- 对于连续性特征,可以划分为大于等于A与小于A。
(2)从根节点开始,选择可获得最大信息增益的特征进行分裂(实现信息增益最大化)。
(3)对子节点继续选择能够获得最大信息增益的特征进行分裂,直到满足如下条件之一,停止分裂:
- 所有叶子节点中的样本属于同一个类别。
- 树达到指定的最大深度(max_depth),每次分裂视为一层。
- 叶子节点包含的样本数量小于指定的最小分裂样本数量(min_samples_split)。
- 如果分裂后,叶子节点包含的样本数量小于指定的叶子最小样本数量 (min_samples_leaf)。
3.3 分类决策树示例
例如,给定如下的数据集,预测样本11的结果:
序号 | 拥有房产(x1) | 婚姻状态(x2) | 年收入(x3) | 能否偿还债务(Y) |
---|---|---|---|---|
1 | 是 | 单身 | 125 | 能 |
2 | 否 | 已婚 | 100 | 能 |
3 | 否 | 单身 | 100 | 能 |
4 | 是 | 已婚 | 110 | 能 |
5 | 是 | 离婚 | 60 | 能 |
6 | 否 | 离婚 | 95 | 不能 |
7 | 否 | 单身 | 85 | 不能 |
8 | 否 | 已婚 | 75 | 能 |
9 | 否 | 单身 | 90 | 不能 |
10 | 是 | 离婚 | 220 | 能 |
11 | 否 | 已婚 | 94 | ? |
我们可以将三个特征作为三个问题,依次来“询问”数据集中的每个样本,经过每个样本依次“作答”之后,就可以将样本划分到不同的分支中,这样,决策树就训练完成(决策树的训练,就是根据训练集去构建一颗决策树)。
以不纯度衡量使用信息熵为例,父节点的信息熵为:
如果以特征“拥有房产”作为分裂特征,则:
因此,特征“拥有房产”的信息增益为:
同样的方法可求出:
对于收入来说,为连续型变量,我们这里将收入的取值进行排序,然后选择“否”与“是”的分界点(75与85之间,95与100之间),取平均值进行分割:
同样的方法可求出:
从上面的结果中可知,相比于房产、婚姻、年收入=80来说,年收入=97.5可以获得更大的信息增益。于是可以选择年收入作为父节点,训练结果如下图所示:
则对于样本11,很容易就可以得出预测的类别结果为:能。
4、不纯度度量标准
- 信息熵(Entropy)
- 基尼系数(Gini Index)
- 错误率(classification error)
- 无论哪种度量标准,都有一个特性:如果样本以相同的比例分布于不同的类别时,度量值最大,不纯度最高。如果所有的样本都属于同一个类别,则度量值为0,不纯度最低。
5、决策树算法
决策树主要包含以下三种算法:
- ID3
- C4.5
- CART(Classification And Regression Tree)
5.1 ID3
ID3(Iterative Dichotomiser3-迭代二分法)算法是非常经典的决策树算法,该算法描述如下:
- 使用多叉树结构
- 使用信息熵作为不纯度度量标准,选择信息增益最大的特征分割数据。
ID3算法简单,训练较快。但该算法具有一些局限,如下:
- 不支持连续特征
- 不支持缺失值
- 仅支持分类,不支持回归。
- 在选择特征时,会倾向于选择类别多的特征。
5.2 C4.5
C4.5算法是在ID3算法上改进而来,该算法描述如下:
- 使用多叉树结构
- 仅支持分类,不支持回归。
不过,C4.5在ID3算法上,进行了一些优化,包括:
- 支持对缺失值的处理
- 支持将连续值进行离散化处理
- 使用信息熵作为不纯度度量标准,但选择信息增益率(而不是信息增益)最大的特征分裂节点。
信息增益率的定义方式为:
之所以从信息增益改为信息增益率,是因为在ID3算法中,倾向于选择类别多的特征,因此,经过这样的调整,在C4.5中就可以得到缓解。因为类别多的特征在计算信息熵时,往往会比类别少的特征信息熵 IH(f) 大。这样,就可以在分母上进行一定的惩罚。
5.3 CART
CART(Classification And Regression Tree),分类与回归树。该算法描述如下:
-
使用二叉树结构
-
支持连续值与缺失值处理
-
既支持分类,也支持回归。
-
分类决策:使用基尼系数作为不纯度度量标准,选择基尼增益最大的特征分裂节点。
-
回归决策:使用MSE或MAE最小的特征分类节点。
6、回归决策树
- 回归任务的标签(y 值)是连续的,所以之前以分类为基础的不纯度度量标准(信息熵,基尼系数与错误率)都不适用于回归树。
- 在回归树中,也没有信息增益,信息增益率或基尼增益等概念。可以说,分类决策树选择特征的方式,完全不适用于回归决策树。
- 对于回归决策树,会使用叶子节点的均值来预测未知样本。
- 回归决策树使用MSE或MAE作为评估指标,用来选择特征。也就是说,回归决策树在选择特征上,每次选择能够使得MSE或MAE最小的特征,用来分裂节点。
7、决策树实践
- 在scikit-learn中,使用优化的CART算法来实现决策树。
7.1 分类决策树实践
scikit-learn中,提供DecisionTreeClassifier类,用来实现决策树分类(以鸢尾花数据集为例):
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
X, y = load_iris(return_X_y=True)
X = X[:, :2] # 为了后续的可视化方便,这里选择两个特征。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
tree = DecisionTreeClassifier()
"""
criterion:不纯度度量标准,默认为gini。
gini:基尼系数 entropy:信息熵
splitter:选择分裂节点的方式。默认为best。
best:在最好的位置分裂节点。 random:在随机的位置分裂节点。
max_depth:树的最大深度,默认为None(不限制深度)。
min_samples_split:分裂节点的最小样本数,默认为2。
min_samples_leaf:分裂节点后,叶子节点最少的样本数量,默认为1。
max_features:分裂节点时,考虑的最大特征数量,默认为None(考虑所有特征)。
random_state:随机种子。
"""
tree.fit(X_train, y_train)
print(tree.score(X_train, y_train))
print(tree.score(X_test, y_test))
----------------------------------------------
0.9375
0.6578947368421053
从以上结果看出,训练集高于测试集,原因就在于过拟合。因为如果没有指定树的深度,则默认会训练一颗完全生长的决策树(不限深度),这会容易导致模型复杂化,从而过分依赖于训练集数据的特性,造成过拟合。
我们可以从不同深度树的决策边界,来证实这一点:
from matplotlib.colors import ListedColormap
def plot_decision_boundary(model, X, y):
color = ["r", "g", "b"]
marker = ["o", "v", "x"]
class_label = np.unique(y)
cmap = ListedColormap(color[: len(class_label)])
x1_min, x2_min = np.min(X, axis=0)
x1_max, x2_max = np.max(X, axis=0)
x1 = np.arange(x1_min - 1, x1_max + 1, 0.02)
x2 = np.arange(x2_min - 1, x2_max + 1, 0.02)
X1, X2 = np.meshgrid(x1, x2)
Z = model.predict(np.c_[X1.ravel(), X2.ravel()])
Z = Z.reshape(X1.shape)
plt.contourf(X1, X2, Z, cmap=cmap, alpha=0.5)
for i, class_ in enumerate(class_label):
plt.scatter(x=X[y == class_, 0], y=X[y == class_, 1], c=cmap.colors[i], label=class_, marker=marker[i])
plt.legend()
plt.figure(figsize=(15, 10))
for index, depth in enumerate([1, 4, 7, 12], start=1):
plt.subplot(2, 2, index)
plt.title(f"最大深度:{depth}")
tree = DecisionTreeClassifier(random_state=0, max_depth=depth)
tree.fit(X_train, y_train)
plot_decision_boundary(tree, X_test, y_test)
从以上结果可以看出:当最大深度越来越大时,决策边界越来越复杂,模型也就越复杂。
对于决策树来说,最大深度对模型有着较重要的影响,如果最大深度很小,意味着仅进行少数的切分,容易欠拟合,但是,如果最大深度很大,则意味着可能进行较多次切分,容易过拟合:
# 定义列表,用来存储在不同深度下,模型的分值。
train_score = []
test_score = []
for depth in range(1, 13):
tree = DecisionTreeClassifier(random_state=0, max_depth=depth)
tree.fit(X_train, y_train)
train_score.append(tree.score(X_train, y_train))
test_score.append(tree.score(X_test, y_test))
plt.plot(train_score, marker="o", c="red", label="训练集")
plt.plot(test_score, marker="o", c="green", label="测试集")
plt.legend()
从以上结果可以看出:随着最大深度的增加,训练集的表现越来越好,但是测试集的表现,是先增加后减少,这说明,在树深度较小时,模型是欠拟合的,因此,增加树深度,能够提升预测效果,但随着深度的增加,模型越来越依赖于训练集,这反而降低预测效果,造成过拟合。
7.2 回归决策树实践
scikit-learn中,提供DecisionTreeRegressor类,用来实现决策树回归(以波士顿房价数据集为例):
from sklearn.datasets import load_boston
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split
X, y = load_boston(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
tree = DecisionTreeRegressor(max_depth=3) # 回归决策树的参数,可以参考分类决策树的参数。
tree.fit(X_train, y_train)
print(tree.score(X_train, y_train))
print(tree.score(X_test, y_test))
-------------------------------------
0.8290972700366354
0.6354364289453209