决策树、熵与信息增益
- 决策树
- 熵
- 信息增益
- Python 与 决策树
决策树
决策树(Decision Tree) 是一种基于树形结构的分类算法,它通过一系列的询问(也称为测试或判定条件)来判断一个数据实例属于哪个类别。
以一个案例贯穿全文,我们尝试通过数据库表中三个特征判断是猫还是狗子:
- 特征一: 耳朵形状(折耳、尖耳)
- 特征二: 脸的形状(圆、不圆)
- 特征三: 有无长须(有、无)
耳朵形状 | 脸的形状 | 有无长须 | 是不是猫子 |
---|---|---|---|
尖 | 圆 | 有 | 是 |
折 | 不圆 | 有 | 是 |
折 | 圆 | 无 | 不是 |
尖 | 不圆 | 有 | 不是 |
尖 | 圆 | 有 | 是 |
尖 | 圆 | 无 | 是 |
折 | 不圆 | 无 | 不是 |
尖 | 圆 | 无 | 是 |
折 | 圆 | 无 | 不是 |
折 | 圆 | 无 | 不是 |
根据上表,决策树的一种构造方案如下:
在这里容易产生两个疑问:
- 为什么根节点选择判断耳朵形状,而不是根节点先判断脸的形状?
- 为什么当耳朵形状是尖的时,去判断脸的形状而不是长须?
因为熵与信息增益。
熵
熵(Entropy) 本意上,是一个表示数据集无序程度的指标,它可以用来衡量在数据集中混杂着多少种不同的类别。熵越高,表示数据集的无序程度越高,即混杂的类别越多。在决策树算法中,我们希望使用尽可能少的测试来划分数据 集,因此我们会选择那些能够最大程度地减少数据集熵的测试条件,也就是信息增益最大。
在本案例中,熵的概念为一个数据集中混杂的猫子和狗子的混乱程度。换句话说,如果一个数据集里全是猫子,熵为0,或者全是狗子,熵同样为0,但是如果一半猫子一半狗子,那就会达到熵的最大值:1。
熵的公式为:
H
(
p
1
)
=
−
p
1
l
o
g
2
(
p
1
)
−
(
1
−
p
1
)
l
o
g
2
(
1
−
p
1
)
H(p_1)=-p_1log_2(p_1)-(1-p_1)log_2(1-p_1)
H(p1)=−p1log2(p1)−(1−p1)log2(1−p1)
其中 p 1 p_1 p1 代表着数据集中猫子的占比,故 ( 1 − p 1 ) (1-p_1) (1−p1) 即为数据集中狗子的占比。
故有熵图像如下:
- p = 0 p=0 p=0 代表着全是狗子
- p = 1 p=1 p=1 代表着全是猫子
根据数据表格,初始情况下,熵的值为:
p
0
=
5
/
10
=
0.5
p_0=5/10=0.5
p0=5/10=0.5
H
(
p
0
)
=
−
0.5
∗
l
o
g
2
(
0.5
)
−
(
1
−
0.5
)
∗
l
o
g
2
(
1
−
0.5
)
=
1
H(p_0)=-0.5*log_2(0.5)-(1-0.5)*log_2(1-0.5)=1
H(p0)=−0.5∗log2(0.5)−(1−0.5)∗log2(1−0.5)=1
而在决策树算法中,我们要做的下一步就是最大程度地减少数据集的熵,也就是尝试将猫子和狗子区分出,而每次熵的减少的值,就是信息增益的值。
信息增益
信息增益(Information Gain) 是指在使用某个测试条件对数据集进行划分后,数据集熵的减少量。信息增益越大,表示使用该测试条件能够最大程度地减少数据集的熵,也就是最大程度地增加数据集的有序程度。
所以我们在初始状态下,我们有三种测试条件可以对数据集进行划分,从而减少熵,我们的目标是从这三种测试条件中筛选出最大信息增益的选择:
- 耳朵的形状
- 脸的形状
- 有无长须
信息增益
=
初始熵
−
结果熵
信息增益 = 初始熵 - 结果熵
信息增益=初始熵−结果熵
如上图所示,初始熵为 H ( 0.5 ) = 1 H(0.5)=1 H(0.5)=1,如果使用耳朵的形状作为测试条件,信息增益最大,所以我们选择耳朵的形状作为第一个测试条件对原始数据集进行划分。
下一步的划分原则同上述,按照信息增益最大作为判断条件,直到熵的值为0;
当然在实际情况下,会存在一些噪点,这些噪点会导致熵不会为0,所以我们常常会设定决策树的深度。构造有限深度的决策树。
Python 与 决策树
案例导入:
X_train = np.array([[1, 1, 1],[0, 0, 1],[0, 1, 0],[1, 0, 1],[1, 1, 1],[1, 1, 0],[0, 0, 0],[1, 1, 0],[0, 1, 0],[0, 1, 0]])
y_train = np.array([1, 1, 0, 0, 1, 1, 0, 1, 0, 0])
计算熵:
已知熵的计算公式为:
H
(
p
)
=
−
p
l
o
g
2
(
p
)
−
(
1
−
p
)
l
o
g
2
(
1
−
p
)
H(p) = -plog_2(p)-(1-p)log_2(1-p)
H(p)=−plog2(p)−(1−p)log2(1−p)
Python程序编程为:
def entropy(p):
if p == 0 or p == 1:
return 0
else:
return -p * np.log2(p) - (1- p)*np.log2(1 - p)
将原始数据集按照测试条件划分为两个部分:
def split_indices(X, index_feature):
left_indices = []
right_indices = []
for i,x in enumerate(X):
if x[index_feature] == 1:
left_indices.append(i)
else:
right_indices.append(i)
return left_indices, right_indices
计算带有权重的熵(结果熵):
def weighted_entropy(X,y,left_indices,right_indices):
w_left = len(left_indices)/len(X)
w_right = len(right_indices)/len(X)
p_left = sum(y[left_indices])/len(left_indices)
p_right = sum(y[right_indices])/len(right_indices)
weighted_entropy = w_left * entropy(p_left) + w_right * entropy(p_right)
return weighted_entropy
计算信息增益:
def information_gain(X, y, left_indices, right_indices):
p_node = sum(y)/len(y)
h_node = entropy(p_node)
w_entropy = weighted_entropy(X,y,left_indices,right_indices)
print(h_node)
return h_node - w_entropy