使用ID3算法实现决策树

决策树

基本介绍
决策树通过把数据样本分配到某个叶子结点来确定数据集中样本所属的分类。
决策树由决策结点分支叶子结点组成。

  • 决策结点表示在样本的一个属性上进行的划分;

  • 分支表示对于决策结点进行划分的输出;

  • 叶子节点代表经过分支到达的类。

从决策树根据节点出发,自顶向下移动,在每个决策结点都会进行次划分,通过划分的结果将样本进行分类,导致不同的分支,最后到达个 叶子结点,这个过程就是利用决策树进行分类的过程。

ID3算法原理

ID3算法是在每个结点处选取能获得最高信息增益的分支属性进行分裂。

在每个决策结点处划分分支,选取分支属性的目的就是将整个决策树的样本纯度提高。

衡量样本集合纯的指标则是熵(熵越大,所含有用信息就越少,不确定性就越大,在决策树中,熵指的是纯度,熵越小,纯度越高),设S为数量为n的样本集,其分支属性有m个取值用来定义m个不同分类Ci(i=1,2,3,…,m)那么熵为:
在这里插入图片描述
计算分支属性对于样本集分类好坏程度的度量——信息增益。
由于分裂后样本集的纯度提高,则样本集的熵降低,熵降低的值即为该分裂方法的信息增益:
在这里插入图片描述

ID3代码

  1. 第一步,创建数据和标签。
from math import log
import operator#用于函数操作

def create_data():  # 构建数据和标签
    dataSet = [['short', 'long hair', 'thin', 'female'],
               ['high', 'short hair', 'thin', 'male'],
               ['short', 'long hair', 'fat', 'female'],
               ['high', 'long hair', 'thin', 'female'],
               ['short', 'short hair', 'fat', 'male'],
               ['short', 'short hair', 'thin', 'female'],
               ['high', 'short hair', 'fat', 'male'],
               ['high', 'long hair', 'fat', 'male'],
               ['short', 'short hair', 'thin', 'male'],
               ['high', 'short hair', 'thin', 'female'],
               ['short', 'long hair', 'fat', 'female']]
    labels = ['stature', 'hair', 'weight', 'gender']
    return dataSet, labels
  1. 使用ID3算法需计算信息熵,所以第二步创建cal_entropy方法来计算信息熵。
def cal_entropy(dataSet):
    num = len(dataSet)      #总共有多少行数据
    label_count = {}
    for fea in dataSet:     #遍历整个数据集,每次取一行
        current_label = fea[-1]  # 统计每条数据的类,取该行最后一列的值,即标签
        if current_label not in label_count.keys():     #判断在字典中标签是否存在
            label_count[current_label] = 0
        label_count[current_label] += 1  # 计算每个类中有多少数据
    entropy = 0.0           #初始化信息熵
    for i in label_count:  # 计算经验熵
        Pi = float(label_count[i]) / num
        entropy -= Pi * log(Pi, 2)
    return entropy      #返回信息熵
  1. 第三步,创建remove_feature方法来去除某个特征,对数据集进行分割。
def remove_feature(dataSet, axis, feature):  # 去除某个特征
    retdataset = []
    for featVec in dataSet:
        if featVec[axis] == feature:
            reducedata = featVec[:axis]  # 某个特征前数据
            reducedata.extend(featVec[axis + 1:])  # 某个特征后数据
            # 去掉了axis
            retdataset.append(reducedata)
    return retdataset
  1. 第四步,通过信息熵计算信息增益率来求出划分数据集的最优信息增益比。
def choose_best_feature(dataSet):
    entropy = cal_entropy(dataSet)
    feature_num = len(dataSet[0]) - 1      #获取当前数据集的特征个数,最后一列是分类标签
    max_mutual_info = 0
    best_feature = -1       #初始化最优特征
    for i in range(feature_num):
        feature_list = [example[i] for example in dataSet]  #获取数据集中当前特征下的所有值
        feature_class = set(feature_list)  # 得到该特征的所有可能取值
        conditional_entropy = 0
        for value in feature_class:
            retdataset = remove_feature(dataSet, i, value)  #去处某一特征,方便计算
            Pi = len(retdataset) / float(len(dataSet))
            conditional_entropy += Pi * cal_entropy(retdataset)  # 求条件熵
        mutual_info = entropy - conditional_entropy  # 互信息量
        if (mutual_info > max_mutual_info):
            #比较每个特征的信息增益比,只要最好的信息增益比
            max_mutual_info = mutual_info
            best_feature = i
    return best_feature
  1. 创建一个majority_vote方法将传入的数据按出现的频率进行降序排列,并返回第一个键名。
def majority_vote(class_list):
    class_count = {}        #存各种分类出现的频率
    for vote in class_list:
        if vote not in class_count.keys():
            class_count[vote] = 0
        class_count[vote] += 1
    #对字典进行排序
    sort_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    # 排序来决定该节点的类
    return sort_class_count[0][0]
  1. 最后一步,根据得到的最优信息增益比生成决策树。
#生成决策树
def create_tree(dataSet, labels):
    class_list = [example[-1] for example in dataSet]
    #终止条件1:class_list是否纯净(纯净就是数据中所有特征都相等)
    if class_list.count(class_list[0]) == len(class_list):
        #当整个数据中的类别完全相同时类别已经纯净了,则停止继续划分,直接返回该类的标签
        return class_list[0]
    if len(dataSet[0]) == 1:
        # 节点已没有特征可以继续分解
        return majority_vote(class_list)
    best_feature = choose_best_feature(dataSet)#选择最好的分类特征索引
    best_feature_label = labels[best_feature]#获得该特征的名字
    #直接使用字典变量来存储树信息
    my_tree = {best_feature_label: {}}     #当前数据集选取最好的特征存储在best_feature中
    del (labels[best_feature])
    # 删掉已选择的特征
    feature = [example[best_feature] for example in dataSet]    #取出最优列的值
    feature_class = set(feature)
    #根据这个列的这个feature_class值来切分树的节点
    for value in feature_class:
        sublabels = labels[:]
        my_tree[best_feature_label][value] = create_tree(remove_feature(dataSet, best_feature, value), sublabels)
        # 迭代生成决策树
    return my_tree

运行结果为:
在这里插入图片描述
此决策树共进行四次分类,分别是:“stature”,“hair”,“weight”,“gender”。
ID3算法是由根节点通过计算信息增益选取最合适的属性进行分裂,若新生成的结点的分类属性不唯一,则对新生成的结点继续进行分裂,不断重复此步骤,直到所有样本属于同一类,或者达到要求的分类条件为止。

ID3(Iterative Dichotomiser 3)算法是一种经典的用于构建决策树算法,由Ross Quinlan在1986年提出。该算法基于信息增益或信息增益率来进行特征选择,主要用于分类问题。 以下是ID3算法的主要步骤: 1. **数据预处理**:首先对数据进行清洗,包括缺失值处理、编码等,确保所有特征都是离散的。 2. **计算信息熵**:对于原始数据集,信息熵(Entropy)用来衡量不确定度,初始时通常取所有样本类别分布的负对数之和。 3. **选择最优特征**: - 对于每个特征,计算基于当前特征划分后的子集的信息熵减少量,即信息增益或信息增益率。 - 选择信息增益或增益率最大的特征作为当前节点的分裂依据。 4. **递归分割**:对选定特征下的每个分支,重复上述过程,直到达到预定的停止条件(如叶节点的最小样本数、无可用特征可选等)。 5. **创建决策节点**:当找到最佳特征并分割后,创建一个新的决策节点,其内部包含这个特征及其可能的取值。 6. **创建叶节点**:当满足停止条件时,将该分支标记为叶节点,并存储相应的类别。 7. **剪枝优化**:如果允许,可以进行后剪枝或预剪枝来避免过拟合,提高模型的泛化能力。 以下是一个简单的Python示例(不包括完整的剪枝功能): ```python from collections import Counter def entropy(labels): total = len(labels) counts = Counter(labels) prob = {label: count / total for label, count in counts.items()} return sum(-prob[label] * math.log(prob[label], 2) for label in prob) def id3(X, y, features=None, entropy_threshold=0.0): # ... (数据预处理部分) if not features or all(y == y[0]): # 如果没有更多的特征或所有样本同类别,则返回叶节点 return LeafNode(y[0]) best_gain = 0 best_feature = None # 计算当前节点的熵 current_entropy = entropy(y) if not features: # 使用全特征集 features = X.columns for feature in features: # 计算分割后各个子集的熵 gain = current_entropy - weighted_average(entropy(subset[y]) for subset in partition_by(X, feature)) if gain > best_gain: best_gain = gain best_feature = feature # 创建新的决策节点 decision_node = DecisionNode(best_feature) # 分别构建左子树和右子树 for value, sub_y in partition_by(y, best_feature): decision_node.children[value] = id3(X[X[best_feature] == value], sub_y, features - {best_feature}, entropy_threshold) return decision_node ``` 在这个示例中,`partition_by()`函数用于根据特征值分割数据集,`weighted_average()`则计算加权平均信息熵。注意,这只是一个简化版本,实际应用中可能还需要处理更多细节,例如处理连续特征、数值型特征转换等。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值