ID3西瓜决策树python实现


前言

一、代码

代码如下(示例):

# coding=utf8

from math import log


# 构造数据集
def create_dataset():
    features = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']
    dataset = [
        ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
        ['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '是'],
        ['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
        ['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '是'],
        ['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
        ['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '是'],
        ['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘', '是'],
        ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑', '是'],
        ['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑', '否'],
        ['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', '否'],
        ['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', '否'],
        ['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', '否'],
        ['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑', '否'],
        ['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑', '否'],
        ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '否'],
        ['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑', '否'],
        ['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', '否']]
    return dataset, features


# 计算信息熵
def compute_entropy(dataset):
    # 求总样本数
    num_of_example = len(dataset)
    labelCnt = {}
    # 遍历整个样本集合
    for example in dataset:
        # 当前样本的标签值是该列表的最后一个元素
        currentLabel = example[-1]
        # 统计每个标签出现了几次,正负样本
        if currentLabel not in labelCnt.keys():
            labelCnt[currentLabel] = 0
        labelCnt[currentLabel] += 1
    entropy = 0.0
    # 对于原样本集,labelCounts={'no':6,'yes':9}
    # 对应的初始shannonEnt={(-6/15*log(6/15))+(-9/15*log(9/15))}
    for key in labelCnt:
        p = labelCnt[key] / num_of_example
        entropy += p * log(p, 2)
    return -1*entropy


# 提取子集合
# 功能:从dataSet中先找到所有第axis个标签值=value的样本
# 然后将这些样本删去第axis个标签值,再全部提取出来成为一个新的样本集
def create_sub_dataset(dataset, index, value):
    sub_dataset = []
    for example in dataset:
        current_list = []
        if example[index] == value:
            current_list = example[:index]
            current_list.extend(example[index + 1:])
            sub_dataset.append(current_list)
    return sub_dataset


# 选择最好的分裂特征
def choose_best_feature(dataset):
    num_of_features = len(dataset[0]) - 1
    # 计算当前数据的信息熵
    current_entropy = compute_entropy(dataset)
    # 初始化信息增益
    best_information_gain = 0.0
    # 初始化最佳特征下标为-1
    index_of_best_feature = -1
    # 通过下标遍历整个特征列表
    for i in range(num_of_features):
        # 构造所有样本在当前特征的取值的列表
        values_of_current_feature = [example[i] for example in dataset]
        unique_values = set(values_of_current_feature)
        # 初始化新的信息熵
        new_entropy = 0.0
        # 初始化分离信息
        split_info = 0.0
        for value in unique_values:
            sub_dataset = create_sub_dataset(dataset, i, value)
            p = len(sub_dataset) / len(dataset)
            # 计算使用该特征进行样本划分后的新信息熵
            new_entropy += p * compute_entropy(sub_dataset)
        # 计算信息增益
        information_gain = current_entropy - new_entropy
        if information_gain > best_information_gain:
            best_information_gain = information_gain
            index_of_best_feature = i
    # 这里返回的是特征的下标
    return index_of_best_feature


# 返回具有最多样本数的那个标签值('yes' or 'no')
def find_label(classList):
    # 初始化统计各标签次数的字典
    # 键为各标签,对应的值为标签出现的次数
    labelCnt = {}
    for key in classList:
        if key not in labelCnt.keys():
            labelCnt[key] = 0
        labelCnt[key] += 1
        # 将classCount按值降序排列
        # 例如:sorted_labelCnt={'yes':9,'no':6}
        sorted_labelCnt = sorted(labelCnt.items(), key=lambda a: a[1], reverse=True)
        # 取sorted_labelCnt中第一个元素中的第一个值,即为所求
        return sorted_labelCnt[0][0]


# 建树
def create_decision_tree(dataset, features):
    # 求出训练集所有样本的标签
    # 对于初始数据集,其label_list=['no','no','yes','yes','no','no','no',yes','yes','yes','yes','yes','yes','yes','no']
    label_list = [example[-1] for example in dataset]
    # 先写两个递归结束的情况
    # 若当前集合的所有样本标签相等(即样本已被分‘纯’)
    # 则直接返回该标签值作为一个叶子节点
    if label_list.count(label_list[0]) == len(label_list):
        return label_list[0]
    # 若训练集的所有特征都被使用完毕,当前无可用特征,但样本仍未被分“纯”
    # 则返回所含样本最多的标签作为结果
    if len(dataset[0]) == 1:
        return find_label(label_list)
    # 下面是正式建树的过程
    # 选取进行分支的最佳特征的下标
    index_of_best_feature = choose_best_feature(dataset)
    # 得到最佳特征
    best_feature = features[index_of_best_feature]
    # 初始化决策树
    decision_tree = {best_feature: {}}
    # 使用过当前最佳特征后将其删去
    del (features[index_of_best_feature])
    # 取出各样本在当前最佳特征上的取值列表
    values_of_best_feature = [example[index_of_best_feature] for example in dataset]
    # 用set()构造当前最佳特征上的取值列表
    unique_values = set(values_of_best_feature)
    # 对于unique_values中的每一个取值
    for value in unique_values:
        # 子特征=当前特征(因为刚才已经删去了用过的特征)
        sub_features = features[:]
        # 递归调用create_decision_tree去生成新节点
        decision_tree[best_feature][value] = create_decision_tree(
            create_sub_dataset(dataset, index_of_best_feature, value), sub_features)
    return decision_tree


# 用上面训练好的决策树对新样本分类
def classify(decision_tree, features, test_example):
    classLabel = ''
    # 根节点代表的属性
    first_feature = list(decision_tree.keys())[0]
    # second_dict是第一个分类属性(也是字典)
    second_dict = decision_tree[first_feature]
    # 树根代表的属性,所在属性标签中的位置,即第几个属性
    index_of_first_feature = features.index(first_feature)
    # 对于second_dict.keys()
    for key in second_dict.keys():
        if test_example[index_of_first_feature] == key:
            # 若当前second_dict的key的value是一个字典
            if type(second_dict[key]).__name__ == 'dict':
                # 则需要递归查询
                classLabel = classify(second_dict[key], features, test_example)
            # 若当前second_dict的key的value是一个单独的值
            else:
                # 则就是要找的标签值
                classLabel = second_dict[key]
    return classLabel


if __name__ == '__main__':
    dataset, features = create_dataset()
    # print(dataset,features)
    decision_tree = create_decision_tree(dataset, features)
    # 打印生成的决策树
    print("----")
    print(decision_tree)
    print("----")
    # 对新样本进行分类测试
    # features=['age','work','houes','credit']
    features = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']
    # test_example=['midlife','yes','no','great']
    test_example = ['青绿', '稍蜷', '沉闷', '清晰', '稍凹', '硬滑']
    calssLabel=classify(decision_tree, features, test_example)
    if calssLabel == '':
        calssLabel="无法判断"
    print('\n',calssLabel )






运行截图

在这里插入图片描述

参考博客:https://blog.csdn.net/qq_45717425/article/details/120959148

  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,关于Python实现西瓜2.0决策树,以下是基本的流程和示例代码: 1.首先需要导入 necessary 模块: ``` import numpy as np import pandas as pd from math import log import operator ``` 2.读入西瓜2.0数据并做处理: ``` watermelon_data = pd.read_csv("watermelon_2.0.csv") watermelon_data = watermelon_data.iloc[:,1:] ``` 3.定义生成决策树的函数 create_tree: ``` def create_tree(data_set, features): # 判断样本中是否属于同一类别,若是,则返回该类别 class_list = data_set.iloc[:,-1].tolist() if class_list.count(class_list[0]) == len(class_list): return class_list[0] # 样本集中只有一个特征时,返回样本中出现次数最多的类别 if len(features) == 1: return majority_count(class_list) # 选取最优特征 best_feature = choose_best_feature_to_split(data_set, features) best_feature_name = features[best_feature] my_tree = {best_feature_name: {}} # 从特征列表中删除最优特征 del(features[best_feature]) # 找出该特征对应的所有值,建立决策树 feature_values = data_set.iloc[:,best_feature].tolist() unique_values = set(feature_values) for value in unique_values: sub_features = features[:] # 对于该特征下的每一个取值,都再建立一个决策树,即遍历该特征的所有取值 my_tree[best_feature_name][value] = create_tree(split_data_set(data_set, best_feature, value), sub_features) return my_tree ``` 4.定义划分数据集的函数 split_data_set: ``` def split_data_set(data_set, axis, value): ret_data_set = data_set.loc[data_set[axis] == value].drop([axis], axis=1) return ret_data_set ``` 5.定义计算信息熵的函数 calc_shannon_ent: ``` def calc_shannon_ent(data_set): num_entries = len(data_set) label_counts = data_set.iloc[:,-1].value_counts() shannon_ent = 0.0 for key in label_counts: prob = float(label_counts[key])/num_entries shannon_ent -= prob * log(prob, 2) return shannon_ent ``` 6.定义选择最优特征的函数 choose_best_feature_to_split: ``` def choose_best_feature_to_split(data_set, features): base_entropy = calc_shannon_ent(data_set) best_info_gain = 0.0 best_feature = -1 for i in range(len(features)): feat_list = data_set.iloc[:,i].tolist() unique_values = set(feat_list) new_entropy = 0.0 for value in unique_values: sub_data_set = split_data_set(data_set, i, value) prob = len(sub_data_set) / float(len(data_set)) new_entropy += prob * calc_shannon_ent(sub_data_set) info_gain = base_entropy - new_entropy if info_gain > best_info_gain: best_info_gain = info_gain best_feature = i return best_feature ``` 7.定义计算类别出现次数最多的函数 majority_count: ``` def majority_count(class_list): class_count = {} for vote in class_list: if vote not in class_count.keys(): class_count[vote] = 0 class_count[vote] += 1 sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True) return sorted_class_count[0][0] ``` 以上就是Python实现西瓜2.0决策树的基本流程和示例代码。如果您有任何疑问,请随时问我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小凉爽&玉米粒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值