自编程实现决策树(使用ID3算法)

不使用sklearn中的决策树方法,根据以下数据集自己编写决策树构建程序(建议用python语言)。

Tid Refund Marital Status Taxable Income Cheat
1 yes single 125k no
2 no married 100k no
3 no single 70k no
4 yes married 120k no
5 no divorced 95k yes
6 no married 60k no
7 yes divorced 220k no
8 no single 85k yes
9 no married 75k no
10 no single 90k yes

过程记录

一开始不知道要从哪里开始下手,自己开始逐步摸索,首先将老师给的数据存到了Excel表格中,之后通过pandas的read_excel()函数读入,并拿到了各属性列的数据,但是之后就没大有思路了(怪自己没有将本次实验内容与老师上课所讲内容好好结合),于是在百度上搜索自编程实现决策树,发现可以用ID3算法实现,于是就去仔细看了下ID3算法是什么,发现就是老师上课讲的内容根据信息熵计算信息增益,然后选取信息增益最大的进行分类,重复此过程!ID3算法数值分析过程这篇博客讲的过程十分清晰,之后开始着手写信息熵和信息增益的计算

import pandas as pd
import numpy as npdef get_entropy(data, name):# 找出该属性列的唯一值data_items =  data[name].unique().tolist()entropy_items = 0for item in data_items:# 对每个不同item属性值求信息熵data_item = data[data[name] == item]sums_item_no = data_item[data_item['Cheat'] == 'no'].shape[0]sums_item_yes = data_item[data_item['Cheat'] == 'yes'].shape[0]sums_item_no_p = sums_item_no / (sums_item_no + sums_item_yes)sums_item_yes_p = sums_item_yes / (sums_item_no + sums_item_yes)# 计算不同item属性值的信息熵if sums_item_no_p == 0 or sums_item_yes_p == 0:  # 这里要处理子数据集为空的情况;这里暂未处理entropy_item = 0else:entropy_item = -np.log2(sums_item_no_p) * sums_item_no_p - np.log2(sums_item_yes_p) * sums_item_yes_p# 计算改item属性值所占概率item_p = data_item.shape[0] / sums# 计算信息增益entropy_items += item_p * entropy_itemreturn entropy_itemsif __name__ == '__main__':inputfile = 'D:\shujuwajue\data.xls'data = pd.read_excel(inputfile, index_col=u'Tid')# 找出各属性列的唯一属性值refunds = data['Refund'].unique().tolist()print(refunds)marital_status = data['Marital Status'].unique().tolist()print(marital_status)taxable_income = data['Taxable Income'].unique().tolist()print(taxable_income)cheat = data['Cheat'].unique().tolist()print(cheat)# 总记录数sums = data.shape[0]print(sums)# 结果Cheat为no、yes的记录数sums_no = data[data['Cheat'] == 'no'].shape[0]sums_yes = data[data['Cheat'] == 'yes'].shape[0]# 结果Cheat为no、yes的概率sums_no_p = sums_no / sumssums_yes_p = 1 - sums_no_p# 一开始未划分时信息熵entropy = -np.log2(sums_no_p) * sums_no_p - np.log2(sums_yes_p) * sums_yes_pprint(entropy)# 调用编写的get_entropy函数获取据该属性划分信息熵、信息增益entropy_Refund = get_entropy(data, 'Refund')gain_entropy_refund = entropy - entropy_Refundprint(gain_entropy_refund)entropy_Marital_Status = get_entropy(data, 'Marital Status')gain_entropy_Marital_Status = entropy - entropy_Marital_Statusprint(gain_entropy_Marital_Status)entropy_income = get_entropy(data, 'Taxable Income')gain_entropy_income = entropy - entropy_incomeprint(gain_entropy_income)


根据输出结果发现由于Taxable Income的值是间断的,每个值都唯一,所以不能用data[‘Taxable Income’].unique().tolist()取出唯一值据此划分,观察了下数据以85k为分界点,将data[‘Taxable Income’]分为>=85k和<85k,由于对字符串大小进行比较时是从字符串的第一个字母开始的,所以对字符串长度不等的数据先用0进行了填充。

def set_income(data):data_income = data['Taxable Income'].drop_duplicates().tolist()for index in range(len(data_income)):f = '85k'l1 = len(data_income[index])l2 = len(f)if l1&gt;l2:for i in range(l1-l2):f = '0'+ felse:for i in range(l2-l1):data_income[index] = '0'+data_income[index]if data_income[index] >=f:data_income[index] = '>=85k'else:data_income[index] = '<85k'return data_income

为了方便以后的操作,将对Taxable Income列数据的划分结果存储到了Excel表的income列

data['income'] = None
# 根据Taxable Income中的值进行分类写入income属性列
data['income'] = set_income(data)
DataFrame(data).to_excel('D:/shujuwajue/data.xlsx', sheet_name='Sheet1', index=True, header=True)


注意:在向Excel表格中写入数据时,写入文件不能处于打开状态,不然的话会写入失败报错如下图:

写完未划分的信息熵和信息增益的计算之后,对下一步如何做没有了思路,怎样进一步划分,划分好了之后应该怎么做,怎样把划分结果存储下来,对于这些都没有明确的思路,于是再次在网上查找,找了很多博客,一开始觉得代码太长不想看,但是找了几个发现大概都这么长,恰巧又找到了一个文章排版比较好的博客决策树之ID3算法,于是耐下性子来看,因为有了上面求信息熵和信息增益的思路,所以理解起来不是太难,主要是要沉下心,对我自己来说比较难的是建树那一块,因为对字典不大了解,又去看了字典的相关操作,然后对自己不理解的语句打印输出一下,看一下这些语句是什么作用。最后有了清晰地理解,然后根据老师的要求对代码进行修改,同时添加修改了一些注释,对老师所给数据进行构建决策树,并使用了一条测试数据进行测试,成功!

最终代码

import pandas as pd
import numpy as np
from pandas import DataFrame# 设置income列
def set_income(data):data_income = data['Taxable Income'].drop_duplicates().tolist()for index in range(len(data_income)):f = '85k'l1 = len(data_income[index])l2 = len(f)if l1>l2:for i in range(l1-l2):f = '0'+ felse:for i in range(l2-l1):data_income[index] = '0'+data_income[index]if data_income[index] >=f:data_income[index] = '>=85k'else:data_income[index] = '<85k'return data_incomedef split_dataSet(dataSet, column, level):"""根据给定的column(列名属性名)和其level(属性值)来获取子数据集"""subdata = dataSet[dataSet[column] == level]del subdata[column]  # 删除这个划分字段列return subdata.reset_index(drop=True)  # 重建索引def entropy_init(data):"""计算给定数据集的熵"""labels = list(data.columns)level_count = data['Cheat'].value_counts().to_dict()  # 统计分类标签不同水平的值,一开始为:{'no': 7, 'yes': 3}entropy_i = 0.0for key, value in level_count.items():prob = float(value) / data.shape[0]entropy_i += -prob * np.log2(prob)return entropy_idef get_best_level(data, gain, count,index):"""计算每个分类标签的信息增益"""best_info_gain = 0.0  # 最大信息增益best_label = None  # 最大信息增益对应的标签(字段)labels = list(data.columns)[: index]  # 第一次为:['Refund', 'Marital Status', 'income']init_entropy = entropy_init(data)  # 先求靶标签的熵# 遍历用于分类的属性labelsfor i, label in enumerate(labels):# 根据该label(也即column字段)的唯一值(levels)来切割成不同子数据集,并求它们的香农熵levels = data[label].unique().tolist()  # 获取该分类标签的不同levellabel_entropy = 0.0  # 用于累加各水平的信息熵;分类标签的信息熵等于该分类标签的各水平信息熵与其概率积的和。for level in levels:  # 循环计算不同水平的信息熵level_data = data[data[label] == level]  # 获取该水平的数据集prob = level_data.shape[0] / data.shape[0]  # 计算该水平的数据集在总数据集的占比# 计算香农熵,并更新到label_entropy中label_entropy += prob * entropy_init(level_data)  # _entropy用于计算该水平数据集的熵# 计算信息增益info_gain = init_entropy - label_entropy  # 代码至此,已经能够循环计算每个分类标签的信息增益# 用best_info_gain来取info_gain的最大值,并获取对应的分类标签if info_gain > best_info_gain:best_info_gain = info_gainbest_label = label# 这里保存一下每一次计算的信息增益,便于查看和检查错误gain.setdefault(count, {})  # 建立本次函数调用时各属性增益,设其值value为字典,count代表第几次gain[count][label] = info_gain  # 把本次函数调用时计算的各个标签数据存到字典里count += 1return best_label,countdef top_amount_level(target_list):class_count = target_list.value_counts().to_dict()  # 计算靶标签的不同水平的样本量,并转化为字典# 字典的items方法可以将键值对转成[(), (), ...],可以使用列表方法sorted_class_count = sorted(class_count.items(), key=lambda x: x[1], reverse=True)return sorted_class_count[0][0]def mktree(data,gain,count,index):"""创建决策树"""target_list = data['Cheat']  # target_list 靶标签的那一列数据# 程序终止条件一: 靶标签(数据集的最后一列因变量)在该数据集上只有一个水平,返回该水平if target_list.unique().shape[0] <= 1:return target_list[0]  # !!!# 程序终止条件二: 数据集只剩下把标签这一列数据;返回数量最多的水平if data.shape[1] == 1:return top_amount_level(target_list)# 不满足终止条件时,做如下递归处理# 1.选择最佳分类标签best_label, count = get_best_level(data,gain,count,index)# 2.递归计算最佳分类标签的不同水平的子数据集的信息增益#   各个子数据集的最佳分类标签的不同水平...#   ...#   直至递归结束best_label_levels = data[best_label].unique().tolist()tree = {best_label: {}}  # 生成字典,用于保存树状分类信息;这里不能用self.tree = {}存储for level in best_label_levels:level_subdata = split_dataSet(data, best_label, level)  # 获取该水平的子数据集tree[best_label][level] = mktree(level_subdata,gain,count,index-1)  # 返回结果return treedef predict(tree, labels, test_sample):"""对单个样本进行分类tree: 训练的字典labels: 除去最后一列的其它字段test_sample: 需要分类的一行记录数据"""firstStr = list(tree.keys())[0]  # tree字典里找到第一个用于分类键值对secondDict = tree[firstStr]featIndex = labels.index(firstStr)  # 找到第一个建(label)在给定label的索引for key in secondDict.keys():if test_sample[featIndex] == key:  # 找到test_sample在当前label下的值# 判断secondDict[key]类型是否为字典,若为字典递归if secondDict[key].__class__.__name__ == "dict":classLabel = predict(secondDict[key], labels, test_sample)# secondDict[key]类型不是字典,则走到了树的叶子结点,即为结果else:classLabel = secondDict[key]return classLabelif __name__ == '__main__':# 文件目录inputfile = 'D:\shujuwajue\data.xlsx'data = pd.read_excel(inputfile, index_col=u'Tid')data['income'] = None# 根据Taxable Income中的值进行分类写入income属性列data['income'] = set_income(data)DataFrame(data).to_excel('D:/shujuwajue/data.xlsx', sheet_name='Sheet1', index=True, header=True)count =1# 存储每次建树前计算的信息增益gain={}# 建树(字典类型)tree = mktree(data,gain,count,3)print("tree:")print(tree)# 测试数据labels = ["Refund", "Marital Status", "income"]test_sample = ["no", "single", "100k"]  # [0, 1, 0, 0, "no"]# 划分income所属值的范围test_income = test_sample[2]f = '85k'l1 = len(test_income)l2 = len(f)if l1 > l2:for i in range(l1 - l2):f = '0' + felse:for i in range(l2 - l1):test_income = '0' + test_incomeif test_income >= f:test_income = '>=85k'else:test_income = '<85k'test_sample[2] = test_income# 预测值result = predict(tree,labels,test_sample)print("预测结果为:")print(result)print(gain)

自编程实现决策树(使用ID3算法)相关推荐

  1. 【Machine Learning】决策树之ID3算法 (2)

    决策树之ID3算法 Content 1.ID3概念 2.信息熵 3.信息增益 Information Gain 4. ID3 bias 5. Python算法实现(待定) 一.ID3概念 ID3算法最 ...

  2. 利用计算机语言实现ID3算法,机器学习之决策树学习-id3算法-原理分析及c语言代码实现.pdf...

    机器学习之决策树学习-id3算法-原理分析及c语言代码实现.pdf 还剩 23页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,很抱歉,此页已超出免费预览范围啦! 如果喜欢就下载吧,价低环保 ...

  3. 决策树(1)——ID3算法与C4.5算法的理论基础与python实现

    1.前言   决策树是一种常用的机器学习算法,既可以做分类任务也可以做回归任务,本文主要讨论用于分类任务的决策树.决策树与数据结构中的树相同,也是由一个根结点.若干个内部结点和若干个叶结点构成.这里我 ...

  4. 决策树之ID3算法以及决策树挑西瓜代码实现

    决策树之ID3算法以及决策树挑西瓜代码实现 一.决策树 1. 决策树的基本认识 2. 决策树的构造过程 (1)特征选择 (2)决策树的生成 (3)决策树的裁剪 决策树的优缺点 二.决策树之ID3算法 ...

  5. 【机器学习基础】数学推导+纯Python实现机器学习算法4:决策树之ID3算法

    Python机器学习算法实现 Author:louwill 作为机器学习中的一大类模型,树模型一直以来都颇受学界和业界的重视.目前无论是各大比赛各种大杀器的XGBoost.lightgbm还是像随机森 ...

  6. 决策树的ID3算法的应用

    决策树 决策树方法在分类.预测.规则提取等领域有着广泛应用.在20世纪70代后期8习研究者JRossQuinilan提出了ID3日算法以后,决策树在机器学习.数据挖掘邻域得到极大的发展.Quinila ...

  7. 简单易学的机器学习算法——决策树之ID3算法

    一.决策树分类算法概述     决策树算法是从数据的属性(或者特征)出发,以属性作为基础,划分不同的类.例如对于如下数据集 (数据集) 其中,第一列和第二列为属性(特征),最后一列为类别标签,1表示是 ...

  8. 决策树之 ID3 算法

    概述 ID3 算法是构建决策树算法中一种非常重要的算法,可以说它是学习决策树算法的基础吧.比如,下一篇博客要说的 C4.5 决策树,就是基于 ID3 上的一个改进算法.还有 CART.随机森林算法,都 ...

  9. id3决策树_信息熵、信息增益和决策树(ID3算法)

    决策树算法: 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关的特征数据. 缺点:可能会产生过度匹配问题. 适用数据类型:数值型和标称型. 算法原理: 决策树是一个简单的为 ...

最新文章

  1. NOI Day1线上同步赛梦游记
  2. android程序日历layout,Android使用GridLayout绘制自定义日历控件
  3. ASP.NET系统退出(移除Session 、清除浏览器缓存)
  4. mybatis plus 入门
  5. ZooKeeper在分布式应用中的作用
  6. mybatis的mysql分页_使用MyBatis+Mysql实现分页的插件PageInfo使用介绍
  7. 吾管不到的地方,资源已开始混乱
  8. 电子公文的七大问题与八大关系(转)
  9. 计算机在输电线路设计中的应用研究,计算机在输电线路基础设计中的应用原稿(电子版)...
  10. 第二章 基本放大电路
  11. 网线插座板上网络模块接线
  12. Pi滤波中磁珠和电感的使用注意事项
  13. 高亮显示化学结构式中的子结构----Highlight a substructure in the depiction
  14. iOS应用的游戏中心和排行榜
  15. JAVA宠物医院管理系统计算机毕业设计Mybatis+系统+数据库+调试部署
  16. 【JSD2209-DAY05】for、while、数组(上)
  17. 计算机原理电梯控制系统设计,《智能电梯控制系统的实现》-毕业论文(设计).doc...
  18. WSN(3)(1):第三章  无线传感网络的通信与组网
  19. 可嵌入Excel到系统的前端表格控件SpreadJS v16.0——拥有全新的新文件格式
  20. 利用Web Audio API将振动数据转化为音频数据并播放

热门文章

  1. 【效率为王】超详细 Hexo + Github Pages 博客搭建教程
  2. TopCoder Arena 插件配置(1)Greed 2.0
  3. 如何去除Discuz标题栏中的Powered by Discuz!
  4. matlab实现GPC隐写算法,基于LSB信息隐藏算法的MATLAB实现
  5. 手机端设置缩放的解决方法和遇到的UC浏览器的坑
  6. Codeforces 780G Andryusha and Nervous Barriers
  7. CEF(Chromium Embedded Framework和JavaScript交互相互调用函数和设置数据
  8. linux服务器下降,Linux服务器CPU占用率上升速度下降的解决
  9. 在 JavaScript 中为任何表格添加分页
  10. 石英晶体振荡器的基本原理