机器学习之决策树(C语言描述)

统计学习方法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=inpilogpi其中, 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=1npilogpi假设随机变量 ( 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(XY) 表示在已知随机变量 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(YX)=i=1npiH(YX=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(YX=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(YX=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/12P男喜欢=6/8P=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(YX=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/12P男不喜欢=1/4P女不喜欢=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(YX)=H(YX=x喜欢)+H(YX=x不喜欢)然后其信息增益为: g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D, A) = H(D) - H(D|A) g(D,A)=H(D)H(DA)以上是 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)=1k=1K(DCk)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)=DD1Gini(D1)+DD2Gini(D2)基尼指数一般在 Adaboost 算法中用到,在下一章将继续讲解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值