python实现决策树生成算法ID3、C4.5

有用请点赞,没用请差评。

欢迎分享本文,转载请保留出处。

 

目录

 决策树原理

    决策树模型

 决策树生成算法python实现

  

前言:

本章节实现了ID3和C4.5的决策树生成算法,决策树的剪枝请参考下一篇博客。算法是基于李航老师的《统计学习方法》,相关公式在代码中都分别标注了。博客内容参考于李航老师《统计学习方法》和某位大佬的博客https://blog.csdn.net/c406495762/article/details/75663451

 

一 决策树原理

1、决策树模型

决策树是一种基本的分类与回归方法。决策树模型呈树形结构,在分类过程中表示基于特征对实例进行分类的过程,可以认为是if-then规则的集合。分类决策树由结点(node)和有向边组成。结点有两种类型:内部结点和叶结点。内部结点表示一个特征或者属性,叶结点表示一个类。如下图,图中圆和方框分别表示内部结点和叶结点,箭头表示有向边。

 我们可以把决策树看成一个if-then规则的集合,将决策树转换成if-then规则的过程是这样的:由决策树的根结点(root node)到叶结点(leaf node)的每一条路径构建一条规则;路径上内部结点的特征对应着规则的条件,而叶结点的类对应着规则的结论。决策树的路径或其对应的if-then规则集合具有一个重要的性质:互斥并且完备。这就是说,每一个实例都被一条路径或一条规则所覆盖,而且只被一条路径或一条规则所覆盖。这里所覆盖是指实例的特征与路径上的特征一致或实例满足规则的条件。

2、决策树计算

 

 

 

   ID3算法 

 

C4.5算法 

 

 

 二决策树生成算法的实现

采用的数据集:

                                                          贷款申请样本数据表

ID年龄有工作有自己的房子信贷情况类别(是否个给贷款)
1青年一般
2青年
3青年
4青年一般
5青年一般
6中年一般
7中年
8中年
9中年非常好
10中年非常好
11老年非常好
12老年
13老年
14老年非常好
15老年一般

源码:

# -*- coding:utf-8 -*-
# Decision tree 决策树,ID3\C4.5算法,算法参考李航《统计学习方法》
#author:Tomator


import numpy as np
import math


# 测试数据集,《统计学习方法》P59,贷款申请样本数据集
def createDataSet():
    dataSet = [[0, 0, 0, 0, 'no'],                        #数据集
            [0, 0, 0, 1, 'no'],
            [0, 1, 0, 1, 'yes'],
            [0, 1, 1, 0, 'yes'],
            [0, 0, 0, 0, 'no'],
            [1, 0, 0, 0, 'no'],
            [1, 0, 0, 1, 'no'],
            [1, 1, 1, 1, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [2, 0, 1, 2, 'yes'],
            [2, 0, 1, 1, 'yes'],
            [2, 1, 0, 1, 'yes'],
            [2, 1, 0, 2, 'yes'],
            [2, 0, 0, 0, 'no']]
    labels = ['年龄', '有工作', '有自己的房子', '信贷情况']		#特征标签
    return dataSet, labels                             #返回数据集和特征标签

# 计算经验熵,《统计学习方法》P62,公式5.7
def cal_empirical_entropy(data_vector):
    nums_data=len(data_vector)   #数据集样本数
    counts_by_labels={}      #用来保存每个label下的样本数
    entroy=0
    for vector in data_vector:
        if vector[-1] not in counts_by_labels:       #vector[-1]为label值
            counts_by_labels[vector[-1]]=0
        counts_by_labels[vector[-1]]+=1              #统计label出现的次数
    for key in counts_by_labels:
        p=float(counts_by_labels[key]/nums_data)          #计算每个标签出现的概率
        entroy-=p*math.log(p,2)                     #计算经验熵,公式5.7
    return entroy

"""
根据每个特征划分数据集
data_vector
index_feature:特征的索引位置i
value:用来划分的特征取值

返回划分后的子数据及样本数,和子数据集(子数据集剔除了第i列特征)
"""
def split_datatset(data_vector,index_feature,value):
    split_set=[]
    for vector in data_vector:
        # 挑选vector[index_feature]==value的数据
        if vector[index_feature]==value:
            # 去掉第i列特征
            split_1=vector[:index_feature]
            split_1.extend(vector[index_feature+1:])
            split_set.append(split_1)
    return len(split_set),split_set

# 用于返回fea_x1,max_x2中较大一方所对应的值和索引位置。
def choose_max(fea_x1,max_x2,fea_index1,max_indx2):
    if fea_x1>max_x2:
        return fea_x1,fea_index1
    else:
        return max_x2,max_indx2

# 选择最优分类特征
# create_alg_para,生成决策树的方法:ID3或者C45
def choose_bestfeture(data_vector,create_alg_para):
    nums_data=len(data_vector)
    nums_feature=len(data_vector[0])-1              #每个样本所包含的特征个数
    empirical_entropy=cal_empirical_entropy(data_vector)   #计算经验熵
    max_information_gain=0                     #表示最大信息增益
    max_information_gain_ratio=0                 #表示最大的信息增益比
    best_index_feature=0                         #表示最优特征的索引位置index
    for i in range(nums_feature):                #遍历所有的特征
        features_i_set=[vector[i] for vector in data_vector]           #提取第i个特征中所包含的可能取值
        features_i_set=set(features_i_set)             #对特征值去重
        conditional_entroy=0                        #表示每个特征的经验条件熵,公式5.8
        ha_d_entroy=0                                      #表示数据集D关于特征A的值的熵Ha(D),公式5.10
        for fea in features_i_set:                 #遍历第i个特征的所有vlaue
            nums_di,di_set=split_datatset(data_vector,i,fea)     #
            p_di=nums_di/nums_data                 #计算|Di|/|D|,公式5.8
            ha_d_entroy-=p_di*math.log(p_di,2)     #计算数据集D关于特征A的值的熵Ha(D),参考公式5.10
            entroy_di=cal_empirical_entropy(di_set)   #计算子类的经验熵,公式5.8中的H(Di)
            conditional_entroy+=p_di*entroy_di
        fea_information_gain=empirical_entropy-conditional_entroy    #计算每个特征对应的信息增益,公式5.9
        fea_information_gain_ratio=fea_information_gain/ha_d_entroy   #计算每个特征对应的信息增益比,公式5.10
        # print(i,fea_information_gain)

        # 选择最大的信息增益或者信息增益比所对应的特征索引位置
        # 通过create_alg_para参数选择是ID3还是C4.5算法。
        if create_alg_para == "ID3":
            max_information_gain,best_index_feature=choose_max(fea_information_gain,max_information_gain,i,best_index_feature)
        elif create_alg_para == "C45":
            max_information_gain_ratio,best_index_feature=choose_max(fea_information_gain_ratio,max_information_gain_ratio,i,best_index_feature)
        else:
            exit("create_alg_para should be 'ID3' or 'C45'.")

    return best_index_feature          #返回最优分类特征的索引位置

# 返回类列表中出现次数最多的类标签
def max_class(label_list):
    count_label={}
    for label in label_list:
        if label not in count_label:
            count_label[label]=0
        count_label[label]+=1
    #     选择字典value最大的所对应的key值
    return max(count_label,key=count_label.get)



# 决策树的生成
class Decision_tree(object):
    def __init__(self,data_vector,labels,create_alg_para='C45'):
        # 数据集
        self.data_vector=data_vector
        # 特征标签
        self.labels=labels
        # 生成决策树的方法:ID3或者C45
        self.create_alg_para=create_alg_para

    # 生成决策树,返回决策树tree,字典形式
    def tree_main(self):
        tree=self.create_decision_tree(self.data_vector,self.labels)
        return tree


    """
    递归函数,用于生成每一个子树,并返回。
    《统计学习方法》ID3或C4.5算法
    data_vector:每一个待分类数据集
    labels:待分类特征标签 
    
    """
    def create_decision_tree(self,data_vector,labels):
        nums_label=[vector[-1] for vector in data_vector]
        # 如果数据集中所有实例属于同一个类,则停止划分。返回该类 标签。
        if len(set(nums_label))==1:
            return nums_label[0]
        # print("a",'\n',data_vector)
        # 如果特征集只有一类时,即已经遍历完了所有特征,则停止划分。返回出现次数最多的类标签
        if len(data_vector[0])==1:
            return max_class(nums_label)

        best_index_feature=choose_bestfeture(data_vector,self.create_alg_para)    #选择最优特征
        best_feature_label=labels[best_index_feature]         #最优特征的标签
        myTree = {best_feature_label: {}}                    #子决策树,key为最优特征的标签,value为子决策树
        del (labels[best_index_feature])                    #删除已经使用过的最优特征标签
        best_feature_value = [vector[best_index_feature] for vector in data_vector]
        best_feature_set = set(best_feature_value )
        # 根据最优特征标签的属性值划分新的子数据集,并递归生成子树
        for f_value in best_feature_set:
            nums_data_vector,data_vector_split=split_datatset(data_vector,best_index_feature,f_value)
            myTree[best_feature_label][f_value]=self.create_decision_tree(data_vector_split,labels)
        return  myTree

    def cart(self):
        # CART算法参考下一篇博客
        pass

if __name__ == '__main__':
    dataSet, labels = createDataSet()
    # best=choose_bestfeture(dataSet)
    # print(best)

    # create_alg_para should be 'ID3' or 'C45'
    tree=Decision_tree(dataSet,labels,create_alg_para="C45")
    print(tree.tree_main())

 输出:

 

  • 11
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
决策树是一种常见的机器学习算法,其中ID3C4.5和CART是三种常见的决策树分类算法。下面是它们的Python代码介绍: 1. ID3算法代码: ``` def ID3(data, labels): # 计算数据集的信息熵 entropy = calcEntropy(data) # 如果数据集的信息熵为0,则直接返回该数据集的类别 if entropy == 0: return data[0][-1] # 如果特征集为空,则返回数据集中出现次数最多的类别 if len(labels) == 0: return majorityClass(data) # 选择最优划分特征 bestFeature = chooseBestFeature(data, labels) # 根据最优特征生成决策树 decisionTree = {bestFeature: {}} # 从特征集中删除已经使用的特征 labels.remove(bestFeature) # 获取最优特征的所有取值 featureValues = set([example[bestFeature] for example in data]) # 遍历最优特征的所有取值,生成子树 for value in featureValues: subLabels = labels[:] decisionTree[bestFeature][value] = ID3(splitData(data, bestFeature, value), subLabels) return decisionTree ``` 2. C4.5算法代码: ``` def C45(data, labels): # 计算数据集的信息熵 entropy = calcEntropy(data) # 如果数据集的信息熵为0,则直接返回该数据集的类别 if entropy == 0: return data[0][-1] # 如果特征集为空,则返回数据集中出现次数最多的类别 if len(labels) == 0: return majorityClass(data) # 选择最优划分特征 bestFeature = chooseBestFeature(data, labels) # 根据最优特征生成决策树 decisionTree = {bestFeature: {}} # 从特征集中删除已经使用的特征 labels.remove(bestFeature) # 获取最优特征的所有取值 featureValues = set([example[bestFeature] for example in data]) # 遍历最优特征的所有取值,生成子树 for value in featureValues: subLabels = labels[:] # 计算每个取值的信息增益率 subData = splitData(data, bestFeature, value) ratio = calcRatio(subData, entropy) # 如果信息增益率高于平均水平,则生成子树 if ratio >= averageRatio(data, bestFeature): decisionTree[bestFeature][value] = C45(subData, subLabels) # 否则返回数据集中出现次数最多的类别 else: decisionTree[bestFeature][value] = majorityClass(subData) return decisionTree ``` 3. CART算法代码: ``` def CART(data, labels): # 如果数据集中只有一个类别,则直接返回该类别 if len(set([example[-1] for example in data])) == 1: return data[0][-1] # 如果特征集为空,则返回数据集中出现次数最多的类别 if len(labels) == 0: return majorityClass(data) # 选择最优划分特征 bestFeature, bestValue, bestScore = chooseBestSplit(data) # 根据最优特征生成决策树 decisionTree = {bestFeature: {}} # 从特征集中删除已经使用的特征 labels.remove(bestFeature) # 生成左子树和右子树 leftData = [example for example in data if example[bestFeature] <= bestValue] rightData = [example for example in data if example[bestFeature] > bestValue] decisionTree[bestFeature]['left'] = CART(leftData, labels) decisionTree[bestFeature]['right'] = CART(rightData, labels) return decisionTree ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值