基于周志华西瓜数据集的决策树算法及准确率测试

1.决策树介绍
举个通俗的栗子来解释一下什么是决策树,想象一个女孩的母亲要给这个女孩介绍男朋友:

女儿:有没有房子?母亲:有。

女儿:长的帅不帅?母亲:挺帅的。

女儿:收入高不?
母亲:不算很高,中等情况。

女儿:是公务员不?母亲:是,在税务局上班呢。

女儿:那好,我去见见。

这个女孩的决策过程就是典型的分类树决策。相当于通过是否有房、长相、收入和是否公务员对将男人分为两个类别:见和不见。下面我们通过流程图把女儿的决策树判断过程展现出来:

通过这个例子,大家已经对决策树算法有个基本了解了吧,这也是决策树算法的一大优势——数据形式非常容易理解。

2.用python构造决策树基本流程
下图是西瓜书中的决策树学习基本算法,接下来我们将根据这个算法流程用python代码自己写一棵决策树。

在构造决策树时,要解决的第一个问题就是,当前数据集哪个特征在划分数据分类时起决定性作用。在前面相亲的例子中,女孩为何第一个问题是“是否有房子”呢,因为是否有房子这个特征能够提供的“信息量”很大,划分选择就是找提供“信息量”最大的特征,学术上叫信息增益。

3.划分选择(按照信息增益)
什么是信息增益呢,官方介绍请参考西瓜书哈,个人认为就是一个信息提纯的过程,比如一堆黄豆和一堆红豆混在一起,这时候信息的纯度是很低的,如果我们把红豆挑出来了分成两堆,那这时候纯度就高了。这就是一个信息增益的过程,衡量信息纯度的标准,就是信息熵。

信息熵是度量样本集合纯度最常用的一种指标,我的个人理解是对一个事件进行编码,所需要的平均码长就是信息熵,纯度越高,需要的平均代码就越短,信息熵越低。

当前样本集合D中第k类样本所占的比例为pk(k=1,2,…,n),则D的信息熵定义为
Ent(D)=−∑k=1npklog2pk
Ent(D)=−∑k=1npklog2pk

Ent(D)的值越小,则D的纯度越高。
西瓜数据集:链接: https://pan.baidu.com/s/1jxZvzUYX6QUk0cVH3d1vfw 提取码: 3ee9
随机1/3数据作为测试集
最初代码:

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import collections#计算给定数据集的香浓熵
from math import log
def splitDataSet(dataSet, index, feature):splitedDataSet = []mD = len(dataSet)for data in dataSet:if(data[index] == feature):sliceTmp = data[:index]sliceTmp.extend(data[index + 1:])splitedDataSet.append(sliceTmp)return splitedDataSet
def Ent(dataset):n = len(dataset)label_counts = {}for item in dataset:#遍历数据集label_current = item[-1]#存入if label_current not in label_counts.keys():label_counts[label_current] = 0#将特征值存入,并标记为0label_counts[label_current] += 1ent = 0.0for key in label_counts:prob = label_counts[key]/nent -= prob * log(prob,2)return ent#测试我们编写的香浓熵计算函数
data = pd.read_csv('xigua1.csv',encoding='gbk')
print(data)#test=pd.read_csv('textSet.csv')#print(test)
#a=Ent(data.iloc[:,-1])#取数据集最后一列#按照权重计算各分支的信息熵
def sum_weight(grouped,total_len):weight = len(grouped)/total_lenreturn weight * Ent(grouped.iloc[:,-1])#根据公式计算信息增益
def Gain(column, data):lenth = len(data)ent_sum = data.groupby(column).apply(lambda x:sum_weight(x,lenth)).sum()#按照column重新排列,然后计算信息熵,再加一块 ☆!!#print("11",ent_sum)ent_D = Ent(data.iloc[:,-1])#print("22",ent_D)return ent_D - ent_sum#计算按照属性'色泽'的信息增益# 计算获取最大的信息增益的feature,输入data是一个dataframe,返回是一个字符串
def get_max_gain(data):max_gain = 0.0cols = data.columns[:-1]for col in cols:gain = Gain(col,data)#print(gain)if gain > max_gain:max_gain = gainmax_label = colreturn max_label#获取data中最多的类别作为节点分类,输入一个series,返回一个索引值,为字符串
def get_most_label(label_list):return label_list.value_counts().idxmax()  #value_counts:指数据集中值有哪些,每个出现多少次# 创建决策树,传入的是一个dataframe,最后一列为labeldef TreeGenerate(data):feature = train.columns[:-1]label_list = data.iloc[:, -1]#如果样本全属于同一类别C,将此节点标记为C类叶节点if len(pd.unique(label_list)) == 1:return label_list.values[0]#如果待划分的属性集A为空,或者样本在属性A上取值相同,则把该节点作为叶节点,并标记为样本数最多的分类elif len(feature)==0 or len(data.loc[:,feature].drop_duplicates())==1:return get_most_label(label_list)#从A中选择最优划分属性best_attr = get_max_gain(data)tree = {best_attr: {}}#对于最优划分属性的每个属性值,生成一个分支for attr,gb_data in data.groupby(by=best_attr):if len(gb_data) == 0:tree[best_attr][attr] = get_most_label(label_list)else:#在data中去掉已划分的属性new_data = gb_data.drop(best_attr,axis=1)#递归构造决策树tree[best_attr][attr] = TreeGenerate(new_data)return tree#使用递归函数进行分类
def tree_predict(tree, data):#print(data)feature = list(tree.keys())[0]#取树第一个结点的键(特征)#print(feature)label = data[feature]#该特征下所有属性next_tree = tree[feature][label]#下一个结点树if type(next_tree) == str:#如果是个字符串return next_treeelse:return tree_predict(next_tree, data)#切割训练集和测试集# 训练模型from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split#切割训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(data.iloc[:,:-1], data.iloc[:,-1], test_size = 0.3, random_state=1)
train = pd.concat([X_train,y_train],axis=1)
print("train",X_train)
print("test",y_test)decition_tree = TreeGenerate(train)print(decition_tree)y_predict = X_test.apply(lambda x:tree_predict(decition_tree, x),axis=1)
score = accuracy_score(y_test,y_predict)
print('第实验准确率为:'+repr(score*100)+'%')

其实上面算法是有缺陷的,有可能缺失分支,需要补全分支:

import numpy as np
import pandas as pd
import random
import csv
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split#计算熵
def calcEntropy(dataSet):mD = len(dataSet)dataLabelList = [x[-1] for x in dataSet]dataLabelSet = set(dataLabelList)ent = 0for label in dataLabelSet:mDv = dataLabelList.count(label)prop = float(mDv) / mDent = ent - prop * np.math.log(prop, 2)return ent# # 拆分数据集
# # index - 要拆分的特征的下标
# # feature - 要拆分的特征
# # 返回值 - dataSet中index所在特征为feature,且去掉index一列的集合
def splitDataSet(dataSet, index, feature):splitedDataSet = []mD = len(dataSet)for data in dataSet:if(data[index] == feature):sliceTmp = data[:index]sliceTmp.extend(data[index + 1:])splitedDataSet.append(sliceTmp)return splitedDataSet#根据信息增益 - 选择最好的特征
# 返回值 - 最好的特征的下标
def chooseBestFeature(dataSet):entD = calcEntropy(dataSet)mD = len(dataSet)featureNumber = len(dataSet[0]) - 1maxGain = -100maxIndex = -1for i in range(featureNumber):entDCopy = entDfeatureI = [x[i] for x in dataSet]featureSet = set(featureI)for feature in featureSet:splitedDataSet = splitDataSet(dataSet, i, feature)  # 拆分数据集mDv = len(splitedDataSet)entDCopy = entDCopy - float(mDv) / mD * calcEntropy(splitedDataSet)if(maxIndex == -1):maxGain = entDCopymaxIndex = ielif(maxGain < entDCopy):maxGain = entDCopymaxIndex = ireturn maxIndex# 寻找最多的,作为标签
def mainLabel(labelList):labelRec = labelList[0]maxLabelCount = -1labelSet = set(labelList)for label in labelSet:if(labelList.count(label) > maxLabelCount):maxLabelCount = labelList.count(label)labelRec = labelreturn labelRec#生成决策树
# featureNamesSet 是featureNames取值的集合
# labelListParent 是父节点的标签列表
def createDecisionTree(dataSet, featureNames):labelList = [x[-1] for x in dataSet]if(len(dataSet[0]) == 1): #没有可划分的属性了return mainLabel(labelList)  #选出最多的label作为该数据集的标签elif(labelList.count(labelList[0]) == len(labelList)): # 全部都属于同一个Labelreturn labelList[0]bestFeatureIndex = chooseBestFeature(dataSet)bestFeatureName = featureNames.pop(bestFeatureIndex)myTree = {bestFeatureName: {}}featureList = [x[bestFeatureIndex] for x in dataSet]featureSet = set(featureList)for feature in featureSet:featureNamesNext = featureNames[:]splitedDataSet = splitDataSet(dataSet, bestFeatureIndex, feature)myTree[bestFeatureName][feature] = createDecisionTree(splitedDataSet, featureNamesNext)return myTreedef createFullDecisionTree(dataSet, featureNames, featureNamesSet, labelListParent):labelList = [x[-1] for x in dataSet]if(len(dataSet) == 0):return mainLabel(labelListParent)elif(len(dataSet[0]) == 1): #没有可划分的属性了return mainLabel(labelList)  #选出最多的label作为该数据集的标签elif(labelList.count(labelList[0]) == len(labelList)): # 全部都属于同一个Labelreturn labelList[0]bestFeatureIndex = chooseBestFeature(dataSet)#print('index',bestFeatureIndex)bestFeatureName = featureNames.pop(bestFeatureIndex)myTree = {bestFeatureName: {}}featureList = featureNamesSet.pop(bestFeatureIndex)#print('ss',featureList)featureSet = set(featureList)#print('featureSet',featureSet)for feature in featureSet:featureNamesNext = featureNames[:]#print('featureNamesNext',featureNamesNext)featureNamesSetNext = featureNamesSet[:][:]#print('featureNamesSetNext',featureNamesSetNext)splitedDataSet = splitDataSet(dataSet, bestFeatureIndex, feature)myTree[bestFeatureName][feature] = createFullDecisionTree(splitedDataSet, featureNamesNext, featureNamesSetNext, labelList)return myTree#读取西瓜数据集2.0
def readWatermelonDataSet():ifile = open("xigua1.txt")#print(ifile)featureName = ifile.readline()  #表头featureName = featureName.rstrip("\n")#print(featureName)featureNames = (featureName.split(' ')[0]).split(',')#print(featureNames)lines = ifile.readlines()dataSet = []for line in lines:tmp = line.split('\n')[0]#print('tmp',tmp)tmp = tmp.split(',')dataSet.append(tmp)random.shuffle(dataSet)dlen = int(len(dataSet) * 2 / 3)testDlen = len(dataSet) - dlenD = dataSet[0:dlen]#print('d',D)testD = dataSet[dlen:len(dataSet)]labelList = [x[-1] for x in D]#print('labelList',labelList)#获取featureNamesSetfeatureNamesSet = []for i in range(len(D[0]) - 1):col = [x[i] for x in D]colSet = set(col)featureNamesSet.append(list(colSet))#print('saa',featureNamesSet)return D, featureNames, featureNamesSet,labelList,testDdef tree_predict(tree, data):#print(data)feature = list(tree.keys())[0]#取树第一个结点的键(特征)#print(feature)label = data[feature]#该特征下所有属性next_tree = tree[feature][label]#下一个结点树if type(next_tree) == str:#如果是个字符串return next_treeelse:return tree_predict(next_tree, data)def main():#读取数据pingjun=0.0for i in range(1,11):dataSet, featureNames, featureNamesSet,labelList,testD = readWatermelonDataSet()#print('daas',dataSet)tree=createFullDecisionTree(dataSet, featureNames,featureNamesSet,labelList)tree2=createDecisionTree(dataSet, featureNames)#print('tree2',tree2)print(tree)train= pd.DataFrame(dataSet, columns=['色泽','根蒂','敲声','纹理','脐部','触感','好瓜'])#print('train',train)test=pd.DataFrame(testD, columns=['色泽','根蒂','敲声','纹理','脐部','触感','好瓜'])#print('test', test)feature = list(train.columns[:])#print('feat',feature)y_predict = test.apply(lambda x: tree_predict(tree, x), axis=1)label_list = test.iloc[:, -1]score = accuracy_score(label_list, y_predict)pingjun+=scoreprint('第'+repr(i)+'次补全分支准确率为:' + repr(score * 100) + '%')print("平均准确率为:"+repr(pingjun*10)+'%')if __name__ == "__main__":main()

基于周志华西瓜数据集的决策树算法及准确率测试相关推荐

  1. 《机器学习》(周志华)西瓜书读书笔记

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 第1章 绪论 第2章 模型评估与选择 第3章 线性模型 第4章 决策树 第5章 神经网络 第6章 神经网络 第7章 贝 ...

  2. 周志华西瓜书3.4题——用十折交叉验证法和留一法估计对率回归的误差

    周志华西瓜书3.4题. 本文所编写的代码均使用python3.7进行调试,依靠的sklearn进行的实验. 第一步,导入iris数据集,数据集使用sklearn包里面自带的. from sklearn ...

  3. 周志华西瓜书《机器学习》习题提示——第2章

    2.1:分层采样, [ ( 500 500 × 70 % ) ] 2 \left[ \binom{500}{500\times 70\%} \right]^2 [(500×70%500​)]2 2.2 ...

  4. 周志华西瓜书课后习题答案总目录

    https://blog.csdn.net/icefire_tyh/article/details/52064910 机器学习(周志华西瓜书)参考答案总目录 从刚开始学习机器学习到现在也有几个月了,期 ...

  5. 周志华西瓜书学习笔记(一)

    周志华西瓜书学习笔记 第一章 绪论 数据处理分为三个阶段:收集,分析,预测. 一.基本概念 机器学习致力于研究如何通过计算的手段,利用经验来改善系统自身的性能. Mitchell给出的更形式化的定义为 ...

  6. 周志华团队 | TensorFlow开源决策森林库TF-DF

    点上方计算机视觉联盟获取更多干货 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:机器之心 AI博士笔记系列推荐 周志华<机器学习>手推笔记正式开源!可打印版本附pdf下载链接 在 ...

  7. ID3的REP(Reduced Error Pruning)剪枝代码详细解释+周志华《机器学习》决策树图4.5、图4.6、图4.7绘制

    处理数据对象:离散型数据 信息计算方式:熵 数据集:西瓜数据集2.0共17条数据 训练集(用来建立决策树):西瓜数据集2.0中的第1,2,3,6,7,10,14,15,16,17,4 请注意,书上说是 ...

  8. 周志华西瓜书公式勘误(一)之公式2.27勘误

    刚开始读周志华老师的机器学习西瓜书,读到第38页时感觉公式2.27的公式有误,照书上的理解怎么也说不通,网上搜一下,果然发现知乎上有人提问.可惜知乎上的回答也不能让人满意,不仅罗里吧嗦,还满屏公式让人 ...

  9. 周志华西瓜书第三章学习笔记

    第三章学习笔记 文章目录 第三章学习笔记 1.知识脉络 2.我的笔记 参考 1.知识脉络 2.我的笔记 这一章公式推导实在太多了,需要补充的推导过程也有很多,就不写电子档了.扩展公式推导和LDA部分补 ...

  10. #《机器学习》_周志华(西瓜书)南瓜书_第6章 支持向量机

    待做: P134-P139理论部分 整理习题,补充 问题: 1.距离计算 2.线性核和高斯核? 第6章 支持向量机 6.1 间隔与支持向量 基于训练集DDD在样本空间中找到一个划分超平面. 对训练样本 ...

最新文章

  1. OpenStack之虚拟机热迁移
  2. win7、win10进程pid4占用80端口的解决办法
  3. CSS实现 全兼容的多列均匀布局问题
  4. UISegmentedControl的详细使用
  5. 新浪微博学习的知识点
  6. idea 创建 spring 配置文件
  7. spring boot几个初始配置文件
  8. 【华为云技术分享】物体检测yolo3算法 学习笔记(1)
  9. android静态动画,LayoutAnimation给ListView中的item设置动态出场效果(实例)
  10. 【转】打开,另存为,属性等14个javascript代码
  11. 使用Struts2和jQuery EasyUI实现简单CRUD系统(五)——jsp,json,EasyUI的结合
  12. Android:日常学习笔记(7)———探究UI开发(4)
  13. VR打造视觉盛宴,丰富精彩生活
  14. jms是java平台中面向_面向Web的JMS应用系统
  15. 用户分层,该怎么分才合理(实操版)
  16. 计算机网络 子网掩码
  17. telegram群组管理机器人
  18. jspdf添加宋体_JSPDF支持中文(思源黑体)采坑之旅,JSPDF中文字体乱码解决方案...
  19. [2018][PAMI]Deep Self-Evolution Clustering 笔记
  20. 【2021】网络协议从入门到底层原理-MJ【新】附上下载链接

热门文章

  1. win7如何关闭uac(图文详解)
  2. sis最新ip地址2020_2020 前端面试 | 第一波面试题总结
  3. Python—正则表达式基础详解及re库运用
  4. 卫星通信 | 使用虹科SAF手持式频谱分析仪进行TDD信号分析
  5. Safari浏览器兼容性问题处理
  6. Android WAP NET 区别
  7. 虚拟机Ubuntut tftp服务不启动,service tftpd-hpa restart 失败的处理
  8. 测试移动硬盘的真实容量的软件,u盘扩容修复工具
  9. php 抓取天气显示天气图片,Geektool 使用 python+beautifulsoup 抓取天气显示
  10. 逆向学习1-[脱壳技术]/篇1