Decision Tree决策树 ID3,C4.5,CART方法原理及伪代码

1. 算法原理

决策树:决策树是一个通过训练的数据来搭建起的树结构模型,根节点中存储着所有数据集和特征集,当前节点的每个分支是该节点在相应的特征值上的表现,而叶子节点存放的结果则是决策结果。通过这个模型,我们可以高效的对于未知的数据进行归纳分类。每次使用决策树时,是将测试样本从根节点开始,选择特征分支一直向下直至到达叶子节点,然后得到叶子节点的决策结果。

其中决策树算法的关键在于如何选出一个特征,根据这个特征对数据集进行分裂,随着划分的不断进行,希望决策树的分支节点所包含的样本尽可能的属于同一类别。刚开始时特征集中有很多特征,其中有的特征十分重要而有的特征无足轻重,我们倾向于先选择重要的特征对根节点进行分支,因为如果前面的节点就使用意义不大的特征进行分支,则最终使用这个决策树预测结果时,没走几步直接就进入了错误的子节点中,这样再向下遍历也没有意义。而关于本如何选择具有最优划分属性的特征,有以下的几种方法。

3个特征选择方法:

这几种方法有涉及到熵的概念,在信息论里,熵是对不确定性的测量,假如一个随机变量X的取值为{x1,x2,x3...},每一种取到的概率分别是{p1,p2,p3...},那么X的熵定义为 .意思是一个变量的变化情况可能越多,那么它携带的信息量就越大。

然后是信息增益的概念,信息增益是针对特征而言的,就是看一个特征,系统有它和没有它时的信息量各是多少,两者的差值就是这个特征给系统带来的信息量,即信息增益。在本次实验中,信息增益就是决策树在进行特征选择划分前和划分后信息量的差值。

 

使用信息增益:ID3

1)经验熵:Entropy(S),用当前数据集S以及式计算得出的熵,代表当前数据集S的有序化程度。

2)条件熵:Entropy(S|T),使用特征T将数据集S划分成几部分后,分别计算他们的熵,然后按百分占比相加得出的熵,代表使用特征T划分后,当前数据集S的有序化程度。

3)信息增益:IG(T)=Entropy(S)-Entropy(S|T),以经验熵减去条件熵,就知道使用这个特征后能带来多少信息增益。

ID3算法的核心思想:在决策树的每一个非叶子结点划分之前,先计算每一个特征所带来的信息增益,选择其中最大信息增益的特征来划分该节点,因为信息增益越大,区分样本的能力就越强,越具有代表性,

使用信息增益率:C4.5

C4.5算法是对ID3算法的改进,ID3算法是用信息增益来选择特征的,而信息增益的缺点是比较偏向选择取值较多的特征,如果有的特征取值比其他特征的取值多很多的话,这个特征基本就直接被认为是最重要的特征,但实际却未必。因此在C4.5中,为了改善这种情况,引入了对取值数量的惩罚,得到信息增益率作为特征重要性的衡量标准。如果某一个特征取值越多,那么对他的惩罚越严重,其信息增益率也能得到控制。

1)每个特征的信息增益IG(T)

2)每个特征在这个数据集中的熵IV(T),即每个特征有多种取值,那么应用公式即可求出每个特征的熵

3)信息增益率IGR=IG(T)/IV(T),特征的熵作为分母,如果某个特征可能的取值很多,则混乱程度很高,熵很大,会削弱这个特征的信息增益率。

使用GINI系数:CART

GINI系数

CART假设决策树是二叉树,内部结点特征的取值为“是”和“否”,左分支是取值为“是”的分支,右分支是取值为“否”的分支。在CART算法中,GINI系数表示一个随机选中的样本在子集中被分错的可能性。GINI系数为这个样本被选中的概率乘以它被分错的概率。

gini系数值越小表示不确定性越小,当一个节点中所有样本都是一个类时,GINI系数为零。我们选取gini系数最小的特征作为决策点

2、伪代码

double Empirical_entropy(Node *p){		return 当前数据集的经验熵 HD;     }
double Conditional_entropy(int attr_index,Node *p){
	return 索引位置为attr_index的特征的条件熵HDA ;
}
int ID3(Node *p){
	double HD=Empirical_entropy(p);//经验熵
	double HDA[10];//条件熵
	for i=0:p->attrsize:
		HDA[i]=Conditional_entropy(i,p);
		G[i]=HD-HDA[i]//信息增益	
	return 信息增益最大的特征;
}
double SplitInfo(int attr_index,Node* p){
	return 索引位置为attr_index的特征的熵 ;
}
int C4_5(Node* p){
	double HD=Empirical_entropy(p);
	for i=0:p->attrsize:
		HDA=Conditional_entropy(i,p);//条件熵
		double sp_info=SplitInfo(i,p);//特征的熵
		gainRatio[i]=(HD-HDA)/sp_info;//信息增益率
	return 信息增益率最大的特征;
}
double gini(int attr_index,Node* p){
	return 索引位置为attr_index的特征的gini系数 ;
}
int CART(Node* p){
	double Gini[10];
	for i=0:p->attrsize:
		Gini[i]=gini(i,p);
	return 基尼系数最小的特征;
}
int choose_attr(Node *p){
	int attr;//被选中的特征,下面有三种选择方法
	attr=ID3(p);
	//attr=C4_5(p);
	//attr=CART(p);
	return attr;
}
void decide_final_label(Node* p){
	多数投票,在数据集中    正标签多 return 1;     负标签多 return -1;   }
bool meet_with_bound(Node* p){
	if 符合边界条件一:所有数据集样本的标签都相同; return 1;
	if 边界条件二:所有数据集的每个特征的取值都相同; return 1;
	else return 0;//即继续向下分支
}
void recursive(Node *p){
	if(meet_with_bound(p)){
		decide_final_label(p);//决定这个叶子结点的标签 
		return;
	}
	未达到边界,则继续向下分支
	int attr_chosen=choose_attr(p);//选择一个当前特征集中最优代表性的特征
	int index_chosen;
	找出这个被选中的特征在特征集里的索引位置即index_chosen;
	int maxnum,minnum;
	分别求出特征取值的最大最小值;
	for i=minnum:maxnum :
		Node *tem=new Node; 
		新节点的特征集是父节点特征集除去被选中的哪一个特征后所剩的特征集;
		新节点的数据集是父节点被选中特征的取值为i的那些数据样本的集合(删掉被选中特征那一列)
		if 被选中特征确实有i这个取值
			将tem与父节点连接起来
		else 释放tem节点
	for i=0:子节点数目:
		recursive(p->children[i]);
}
void validate(int index,Node *p){
	验证集使用决策树验证 :
	if 到达叶子节点 or 当前节点被剪枝
		取得其标签作为该验证集样例的预测结果存储进数组vali_label_result[]中;
		return ;
	for i=0:children.size():
		找到了对应当前验证集文本特征值的节点,
		则进入这个子节点继续往下遍历 
		validate(index,p->children[i]);
	if 上面没有找到对应的特征值子节点
		说明验证集出现训练集没有的新情况
		多少表决去标签存放数组vali_label_result[]中;
}
void prune(Node* p){
	if 到达叶节点 return;
	for i=0:children.size():
		prune(p->children[i]);//后序遍历
		p->prune_or_not=1;
		decide_final_label(p);
		调用validate()函数,验证集使用剪枝后的决策树预测
		根据数组vali_label_result[]和正确答案数组valilabel[]对比计算准确率
		if 准确率没有降低
			剪枝
		else p->prune_or_not=0;//不剪枝
}
void initial(){	
	Readtext();
	初始化根节点:初始化数据集、特征集等等参数
}
void Readtext(){
	读取train.csv文件,每五个样本取前四个进训练集数组,
	取第五个进验证集数组。且分别用一维数组记录其标签
}
void test_recursive(int index,Node* p){
	用决策树预测测试集标签;
	与validate函数类似,只是预测结果存放数组不同,不作赘述;
}
void output_test_result(){文件流输出测试集预测结果}
void Readtest(){读取测试集文本进测试集数组}
int main(){
	initial(); //初始化根节点 	
	recursive(root);//开始递归建立决策树
	for(int i=0;i<valicnt;i++)//未剪枝前,验证集使用决策树预测
		validate(i,root);
	计算验证集预测结果准确率
	prune(root);//剪枝	
	Readtest();
	for(int i=0;i<testcnt;i++)//决策树预测测试集
		test_recursive(i,root);
	output_test_result();//输出结果到txt文件
}

3、完整代码以及对应的训练集和测试集文件:

点击打开链接 https://download.csdn.net/download/weixin_41519463/10322726

猜你喜欢

转载自blog.csdn.net/weixin_41519463/article/details/79790534
今日推荐