统计学习方法4
第四章 决策树
前言
最近拜读了机器学习领域,经典书籍,李航老师的《统计学习方法》,深受裨益。现实现算法,记录分享。
一、决策树是什么
决策树(Decision Tree)是一种基本的分类与回归法,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是 IF-THAN 规则的集合。也可以认为是定义在特征空间与类空间上的条件概率分布。决策树学习通常包括 3 个步骤:特征选择、决策树生成、以及决策树修剪。决策树最重要的特征选取,特征的选取主要来源于 ID3、C45 以及 CART 算法。
二、决策树的算法原理分析
1、 在决策树算法中,主要是要找的能最大程度划分数据类别的特征属性(某个 x i x_i xi的值),也就是找到信息增益最大的特征属性作为划分的节点。将数据划分,建立决策树。那舍玩意叫信息增益最大?
举例子,有这么一堆人类相关的属性,分别有以下这些属性:{ 身高、体重、腰围、胸围、是否爱看美女 },需要根据这些属性的值判性别。其中 “是否爱看美女” ,这个属性,最能分辨出是男是女。因为爱看美女的大概率就是“男人”。于是我们就选“是否爱看美女”作为决策树的第一个分支节点。然后在剩下的属性再去找,例如,“胸围”,这也是一个比较好去区分“性别的”一个关键特征属性,于是用“胸围”作为决策树的第二分支节点。如此类推直到,特征属性用完了、或者可划分的数据小于阈值、或者得出的信息增益值小于阈值就可以停止建立决策树。
2、ID3 与 C4.5 算法。
这里先介绍随机变量
X
X
X 熵定义:
H
(
X
)
=
−
∑
i
=
i
n
p
i
l
o
g
p
i
H(X)=-\sum_{i=i}^np_ilogp_i
H(X)=−i=i∑npilogpi其中,
p
i
=
P
(
X
=
x
i
)
p_i = P(X=x_i)
pi=P(X=xi), 是
X
X
X 取有限值的随机变量的概率分布。若
p
i
=
0
p_i =0
pi=0,则定义
0
l
o
g
0
=
0
0log0 = 0
0log0=0。由以上定义可知,熵只依赖于
X
X
X 的分布与值无关,所以以上定义也可以写作:
H
(
p
)
=
−
∑
i
=
1
n
p
i
l
o
g
p
i
H(p)=-\sum_{i=1}^np_ilogp_i
H(p)=−i=1∑npilogpi假设随机变量
(
X
,
Y
)
(X, Y)
(X,Y),其联合概率分布为:
P
(
X
=
x
i
,
Y
=
y
j
)
=
p
i
j
,
i
=
1
,
2
,
3
,
.
.
.
,
n
;
j
=
1
,
2
,
3...
,
m
P(X=x_i, Y=y_j) = p_{ij}, i = 1, 2, 3, ..., n; j=1,2,3...,m
P(X=xi,Y=yj)=pij,i=1,2,3,...,n;j=1,2,3...,m那么条件熵
H
(
X
∣
Y
)
H(X|Y)
H(X∣Y) 表示在已知随机变量
X
X
X 的条件下随机变量
Y
Y
Y 的不确定性。它的定义为:
H
(
Y
∣
X
)
=
∑
i
=
1
n
p
i
H
(
Y
∣
X
=
x
i
)
H(Y|X) = \sum_{i=1}^np_iH(Y|X=x_i)
H(Y∣X)=i=1∑npiH(Y∣X=xi)其中
p
i
=
P
(
X
=
x
i
)
,
i
=
1
,
2
,
3...
,
n
p_i=P(X=x_i), i=1,2,3...,n
pi=P(X=xi),i=1,2,3...,n。
p
i
p_i
pi 这里解析一下
H
(
Y
∣
X
=
x
i
)
H(Y|X=x_i)
H(Y∣X=xi),以上面判别男女为例子。假设总共有 12 人, 在“是否喜欢看美女”这个特征属性中,喜欢看美女共有 8 人,其中 6 个为男,2 个为女。而不喜欢看美女有 4 人,其中男人 1 个,女人 3 个。那么
H
(
Y
∣
X
=
x
喜欢
)
=
P
喜欢
(
−
P
男喜欢
l
o
g
P
男喜欢
)
+
P
喜欢
(
−
P
女喜欢
l
o
g
P
女喜欢
)
H(Y|X=x_{喜欢}) = P_{喜欢}(-P_{男喜欢}logP_{男喜欢}) + P_{喜欢}(-P_{女喜欢}logP_{女喜欢})
H(Y∣X=x喜欢)=P喜欢(−P男喜欢logP男喜欢)+P喜欢(−P女喜欢logP女喜欢)其中有,
P
喜欢
=
8
/
12
,
P
男喜欢
=
6
/
8
,
P
=
2
/
8
P_{喜欢} = 8 / 12, P_{男喜欢} = 6 / 8,P_{} = 2 / 8
P喜欢=8/12,P男喜欢=6/8,P=2/8 。然后不喜欢的条件熵为:
H
(
Y
∣
X
=
x
不喜欢
)
=
P
不喜欢
(
−
P
男不喜欢
l
o
g
P
男不喜欢
)
+
P
不喜欢
(
P
女不喜欢
l
o
g
P
女不喜欢
)
H(Y|X=x_{不喜欢}) = P_{不喜欢}(-P_{男不喜欢}logP_{男不喜欢})+P_{不喜欢}(P_{女不喜欢}logP_{女不喜欢})
H(Y∣X=x不喜欢)=P不喜欢(−P男不喜欢logP男不喜欢)+P不喜欢(P女不喜欢logP女不喜欢)其中
P
不喜欢
=
4
/
12
,
P
男不喜欢
=
1
/
4
,
P
女不喜欢
=
3
/
4
P_{不喜欢} = 4 / 12,P_{男不喜欢} = 1 / 4,P_{女不喜欢} = 3 / 4
P不喜欢=4/12,P男不喜欢=1/4,P女不喜欢=3/4。 然后关于“是否喜欢看美女”这个特征属性的条件熵为:
H
(
Y
∣
X
)
=
H
(
Y
∣
X
=
x
喜欢
)
+
H
(
Y
∣
X
=
x
不喜欢
)
H(Y|X) = H(Y|X=x_{喜欢}) + H(Y|X=x_{不喜欢})
H(Y∣X)=H(Y∣X=x喜欢)+H(Y∣X=x不喜欢)然后其信息增益为:
g
(
D
,
A
)
=
H
(
D
)
−
H
(
D
∣
A
)
g(D, A) = H(D) - H(D|A)
g(D,A)=H(D)−H(D∣A)以上是 ID3 算法中关于信息增益的计算。
3、信息增益比,在 ID3 的算法基础上,C4.5算法改进了信息增益,使用了信息增益比: g R ( D , A ) = g ( D , A ) H A ( D ) g_R(D, A) = \frac {g(D,A)}{H_A(D)} gR(D,A)=HA(D)g(D,A)其中, H A ( D ) = ∑ i = 1 n D i D l o g 2 D i D H_A(D)=\sum_{i=1}^n\frac{D_i}{D}log_2\frac{D_i}{D} HA(D)=∑i=1nDDilog2DDi。
最后关于 CART 算法,会在后面文章《第五章,Adaboost》中提及,这里就不在叙述。
三、上代码
关于决策树的 C 式伪代码:
1、一个多节点决策树的树节点:
typdef struct {
bool is_leaf;
int leaf_value;
dc_tree_node_t* children:
int children_size;
int spet_index;
int spet_attr_value;
} dc_tree_node_t
2、建立决策树(使用 ID 3):
#define min_data_set_size 100;
#define gain_epsilon 1e-5;
dc_tree_node_t* decision_tree_build(matrix_t* data, matrix_t* label, int* attr_indexes)
{
bool build_leaf = false;
// 1 检查要分割的数据量是否不足了。
// 2 检查可供分割的属性数量是否为 0。
if (data->size < min_data_set_size
|| count(attr_indexes) == 0) {
build_leaf = true;
}
double gain = -FLT_MAX;
int best_spet_index = -1;
for (i:attr_indexes) {
// 遍历所有的列
matrix_t* data_col_i = matrix_slice_col(data, i);
// 计算这一列的 信息增益
double GAi = calculate_gain_d_a(data, data_col_i);
// 找到最大的信息增益的那一列。
if (GAi > gain) {
gain = GAi;
best_spet_index = i;
}
}
// 检查是否小于最低信息增益的阈值。
if (gain < gain_epsilon) build_leaf = true;
if (build_leaf) {
// 符合建立叶子节点的就建立叶子节点
dc_tree_node_t* node = malloc (sizeof(dc_tree_node_t));
node->is_leaf = true;
// 叶子节点的值等 label 中最多的那个值。
node->leaf_value = count_max(label);
return node;
} else {
// 否则建立中间节点
dc_tree_node_t* node = malloc(sizeof(dc_tree_node_t));
// 根据最佳分割的那一列,根据特征属性的值,来把 data、labal 分组。
{sub_datas, sub_labels, group_size} = matrix_group_by(data, label, best_spet_index);
node->is_leaf = false;
node->children = malloc( group_size * sizeof(dc_tree_node_t) );
node->spet_index = best_spet_index;
node->children_size = group_size;
// 这个特征属性,已被使用,需要剔除在候选分割属性列表。
move_spet_index(attr_indexes, best_spet_index);
int* sub_attr_indexes = copy_arr(best_spet_index);
// 递归调用本函数,直到决策树建立完成为止。
for (i:group_size) {
node->children[i] = decistion_tree_build(sub_data[i], sub_label[i], sub_attr_indexes);
}
return node;
}
}
3、 决策树推理伪代码:
int decision_tree_predict(dc_tree_node_t* root, matrix_t* _Input)
{
// 若是叶子节点,直接返回叶子节点的值,也就是预测值。
if(root->is_leaf) return root->left_value;
// 根据最佳分割点找 _Input 对应的值。
int value = _Input[root->spet_index];
// 根据 value 找到分支在哪一个脉络。
int child_index = find_child_index_by_value(root->children, value);
// 继续递归查找。
return decision_tree_predict(root->children[child_index], _Input);
}
源码:https://github.com/zuweie/boring-code/blob/main/src/statistical_learning/decision_tree.c
总结
分类决策树模型是表示基于特征对实例进行分类的树形结构。决策树可以转换成一个 if-then 规则的集合,也可以看做定义在特征空间划分上的类的条件概率分布。在特征属性选择上,除了使用信息增益、信息增益比这两个指标外外,还有基尼指数(CART)。集合 D 的基尼指数: G i n i ( D ) = 1 − ∑ k = 1 K ( ∣ C k ∣ D ) 2 Gini(D) = 1 - \sum_{k=1}^K(\frac{|C_k|}{D})^2 Gini(D)=1−k=1∑K(D∣Ck∣)2基于特征 A 条件下集合 D 的基尼指数: G i n i ( D , A ) = ∣ D 1 ∣ ∣ D ∣ G i n i ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ G i n i ( D 2 ) Gini(D,A)=\frac{|D_1|}{|D|}Gini(D_1)+\frac{|D_2|}{|D|}Gini(D_2) Gini(D,A)=∣D∣∣D1∣Gini(D1)+∣D∣∣D2∣Gini(D2)基尼指数一般在 Adaboost 算法中用到,在下一章将继续讲解。
完