要求编程实现基于信息熵进行划分选择的决策树算法。并为西瓜数据集3.0生成一棵决策树;

其实说白了,决策树就是一颗递归生成的树,每个中间结点都是属性的划分,叶节点给出分类结果。

从算法流程来看显然要构造一个node类,用来存储树的结构。这里设计了四个属性,分别来表示node的类别(-1表示中间结点,0表示负类,1表示正类),node的分支数组,node的最优划分属性和选择这个属性的值。

class Node:def __init__(self,ntype):self.ntype = ntypeself.children = []self.a = -1self.limit = "None"def __str__(self):return "node->a : %s node->limit : %s node->ntype : %s"%(self.a,self.limit,self.ntype)

然后就是算法的主流程

def treeGenerate(x,y,a):node = Node(-1)if(sum(y)==len(y)):  #判断数据集样本是不是全属于正类node.ntype = 1   #如果是,递归结束 返回node头节点return nodeif(sum(y)==0):       #同理,判断样本是不是全属于负类node.ntype = 0return nodeif(len(a)==0 or judge(x,a)==1): #judge函数判断所有样本是否在所有属性上取值相同node.ntype = maxy(y)        #如果相同,标记为数据集中最多的类return nodea_ = getMaxAv(x,y,a)            #该函数选出最优划分属性a*d_ = getdict(x,a_)              #生成一个字典,返回a*每一个值在数据集中出现的次数node.ntype = -1                 #node为中间结点node.a = a_for ai in set(x[a_]):           child = Node(-1)            #生成分支结点child.a = a_if(d_[ai] == 0):            #如果数据集中在a*上取值为ai的子集为空child.ntype = maxy(y)   #,标记为数据集中样本最多的类node.children.append(child)return nodeelse:xt,yt = getdata(x,y,a_,ai)        #获取样本子集xt.reset_index(drop = True,inplace = True) #重建索引at = [av for av in a if av != a_]          child = treeGenerate(xt,yt,at)             #递归建树child.limit = ainode.children.append(child)return node

接下来就是实现各个功能函数

judge函数判断x的每列列首元素是不是和每一列每个元素相等,这样就达到了判断每列所有元素是否相同的作用。

def judge(x,a):for ar in a:if((x.loc[:,ar][0]==x.loc[:,ar]).all() == False):return 0return 1

maxy函数比较简单,返回样本数最多的类。

def maxy(y):if(sum(y)*2 >= len(y)):return 1else:return 0

getMaxAv函数获取最大的信息增益和最优划分属性,其中信息增益由calGain函数给出

def getMaxAv(x,y,a):Max = -1MaxAv = a[0]for av in a:temp = calGain(x,y,av)if(temp > Max):Max = tempMaxAv = avreturn MaxAv

信息增益的定义其实就是父节点的信息熵减去子节点信息熵的总合;而信息熵度量了样本集合的纯度:信息熵越小,纯度越高。因而父节点又经过一次划分得到的子节点的信息熵一定更小。信息增益就定义了这种变小的幅度,因而我们要找到最大的信息增益。

def calGain(x,y,av):d = getdict(x,av)p1 = getp1(x,y,av)ans = calEnt(sum(y)/len(y))for key,value in d.items():ans -= (value/len(y))*calEnt(p1[key]/value) #Gain(D,a) = Ent(D) - sum(Ent(D.child))return ans
#计算信息熵
def calEnt(p1):  #p1 = sum(y)/len(y)p0 = 1 - p1if(p1 == 0 or p0 == 0):return 0return -1*(math.log(p1,2)*p1+math.log(p0,2)*p0)#辅助函数
def getdict(x,av):d = dict.fromkeys(set(x[av]),0)arr = np.array(x[av])for i in range(len(arr)):d[arr[i]] += 1return d#辅助函数 返回分支节点的p1
def getp1(x,y,av):p1 = dict.fromkeys(set(x[av]),0)arr = np.array(x[av])for i in range(len(arr)):if(y[i] == 1):p1[arr[i]] += 1return p1

最后就是getData函数,很简单,目的是得到递归建树时要用的样本子集。

def getdata(x,y,av,ai):xt = copy.deepcopy(x)yt = [] for i in range(x.shape[0]):if(x[av][i] != ai):                #删去a*属性上不符合要求取值的样本xt.drop(i,axis = 0,inplace = True)if(x[av][i] == ai):yt.append(y[i])yt = pd.Series(yt,name = "target",dtype = "int64")return xt,yt

最最后就是import的库和main函数了

import numpy as np
import pandas as pd
import math
import copydef display(node):              #打印树信息print(node)if(len(node.children) > 0):for i in range(len(node.children)):display(node.children[i])return 0def main():data = pd.read_csv("edata.txt",sep = ',')y = data.targetx = data.drop(['target'],axis = 1)a = np.array(x.columns)#print(x)#print(y)node = treeGenerate(x,y,a)display(node)
if __name__ == "__main__":main()
打印是按照深度优先遍历的,所以遇到type为-1的分支点,会一直往下打印
node.a为-1,就是当前node没有选择最优划分属性。最后结果:
node->a : v4 node->limit : None node->ntype : -1
node->a : -1 node->limit : 模糊 node->ntype : 0
node->a : v6 node->limit : 稍糊 node->ntype : -1
node->a : -1 node->limit : 硬滑 node->ntype : 0
node->a : -1 node->limit : 软粘 node->ntype : 1
node->a : v2 node->limit : 清晰 node->ntype : -1
node->a : v1 node->limit : 稍蜷 node->ntype : -1
node->a : -1 node->limit : 青绿 node->ntype : 1
node->a : v6 node->limit : 乌黑 node->ntype : -1
node->a : -1 node->limit : 软粘 node->ntype : 0
node->a : -1 node->limit : 硬滑 node->ntype : 1
node->a : -1 node->limit : 蜷缩 node->ntype : 1
node->a : -1 node->limit : 硬挺 node->ntype : 0

需要注意的是,这里的决策树没有涉及连续属性,当数据中由连续属性时需要适当改写。不过也很简单。

def getTb(x,av):Ta = []Tb = []for i in range(x.shape[0]):Ta.append(x[av][i])list.sort(Ta)for i in range(len(Ta)-1):Tb.append((Ta[i] + Ta[i+1])/2)return Tbdef divideByT(x,y,av,tb):t = f = 0pt1 = pf1 = 0for i in range(x.shape[0]):if(x[av][i] >= tb):t += 1if(y[i] == 1):pt1 += 1else:f += 1if(y[i] == 1):pf1 +=1return t,f,pt1,pf1def calGain(x,y,av):if(x[av].dtype != "float64"):d = getdict(x,av)p1 = getp1(x,y,av)ans = calEnt(sum(y)/len(y))for key,value in d.items():ans -= (value/len(y))*calEnt(p1[key]/value)return ans,Noneelse:Tb = getTb(x,av)Max = -1Maxt = Tb[0]for tb in Tb:ans = calEnt(sum(y)/len(y))t,f,pt1,pf1 = divideByT(x,y,av,tb)ans -= ((t/len(y))*calEnt(pt1/t) + (f/len(y))*calEnt(pf1/f))if ans > Max:Max = ansMaxt = tbreturn Max,Maxt  def getdata(x,y,av,ai):xt = copy.deepcopy(x)yt = [] for i in range(x.shape[0]):if(x[av][i] != ai):xt.drop(i,axis = 0,inplace = True)if(x[av][i] == ai):yt.append(y[i])yt = pd.Series(yt,name = "target",dtype = "int64")return xt,ytdef getcontinuousdata(x,y,av,ai,flag):xt = copy.deepcopy(x)xf = copy.deepcopy(x)yt = [] yf = []for i in range(x.shape[0]):if(x[av][i] > ai):xt.drop(i,axis = 0,inplace = True)yf.append(y[i])if(x[av][i] <= ai):yt.append(y[i])xf.drop(i,axis = 0,inplace = True)yt = pd.Series(yt,name = "target",dtype = "int64")yf = pd.Series(yf,name = "target",dtype = "int64")if(flag == 0):return xt,ytif(flag == 1):return xf,yfdef treeGenerate(x,y,a):node = Node(-1)if(sum(y)==len(y)):node.ntype = 1return nodeif(sum(y)==0):node.ntype = 0return nodeif(len(a)==0 or judge(x,a)==1):node.ntype = maxy(y)return nodea_,t_ = getMaxAv(x,y,a)d_ = getdict(x,a_)node.ntype = -1node.a = a_if(x[a_].dtype != "float64"):for ai in set(x[a_]):child = Node(-1)child.a = a_if(d_[ai] == 0):child.ntype = maxy(y)node.children.append(child)return nodeelse:xt,yt = getdata(x,y,a_,ai)xt.reset_index(drop = True,inplace = True)at = [av for av in a if av != a_]child = treeGenerate(xt,yt,at)child.limit = ainode.children.append(child)return nodeelse:t,f,pt1,pf1 = divideByT(x,y,a_,t_)if(t == 0 or f == 0):child.ntype = maxy(y)node.children.append(child)return nodeelse:for i in range(2):xt,yt = getcontinuousdata(x,y,a_,t_,i)xt.reset_index(drop = True,inplace = True)at = [av for av in a]child = treeGenerate(xt,yt,at)if(i == 0):child.limit = "<=" + str(t_)else :child.limit = ">" + str(t_)node.children.append(child)return node
结果:
node->a : v4 node->limit : None node->ntype : -1
node->a : -1 node->limit : 模糊 node->ntype : 0
node->a : v7 node->limit : 清晰 node->ntype : -1
node->a : -1 node->limit : <=0.38149999999999995 node->ntype : 0
node->a : -1 node->limit : >0.38149999999999995 node->ntype : 1
node->a : v6 node->limit : 稍糊 node->ntype : -1
node->a : -1 node->limit : 软粘 node->ntype : 1
node->a : -1 node->limit : 硬滑 node->ntype : 0
这里的数据集
v1,v2,v3,v4,v5,v6,target
青绿,蜷缩,浊响,清晰,凹陷,硬滑,1
乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,1
乌黑,蜷缩,浊响,清晰,凹陷,硬滑,1
青绿,蜷缩,沉闷,清晰,凹陷,硬滑,1
浅白,蜷缩,浊响,清晰,凹陷,硬滑,1
青绿,稍蜷,浊响,清晰,稍凹,软粘,1
乌黑,稍蜷,浊响,稍糊,稍凹,软粘,1
乌黑,稍蜷,浊响,清晰,稍凹,硬滑,1
乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0
青绿,硬挺,清脆,清晰,平坦,软粘,0
浅白,硬挺,清脆,模糊,平坦,硬滑,0
浅白,蜷缩,浊响,模糊,平坦,软粘,0
青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0
浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0
乌黑,稍蜷,浊响,清晰,稍凹,软粘,0
浅白,蜷缩,浊响,模糊,平坦,硬滑,0
青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0西瓜数据集3.0
v1,v2,v3,v4,v5,v6,v7,v8,target
青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46,1
乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,1
乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,1
青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,1
浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,1
青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,1
乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,1
乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,1
乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,0
青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,0
浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,0
浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,0
青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,0
浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,0
乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.36,0.37,0
浅白,蜷缩,浊响,模糊,平坦,硬滑,0.593,0.042,0
青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.719,0.103,0

西瓜书习题4.3 决策树相关推荐

  1. 西瓜书习题3.4 (交叉验证法)

    西瓜书习题3.4 (交叉验证法): ​ 选择两个UCI数据集,比较10折交叉验证法和留一法所估计出的对率回归的错误率. 1.数据集长啥样? ​ 于是就下载了一组UCI数据集,它长这样: 至于这些数据是 ...

  2. 西瓜书习题详解 机器学习能在互联网搜索的哪些环节起什么作用?

    看完了西瓜书的第一章,课后习题有这个问题.我先将这个问题定义为:机器学习在搜索引擎上的应用. 维基百科:搜索引擎(英语:Search Engine)是一种信息检索系统,旨在协助搜索存储在计算机系统中的 ...

  3. 西瓜书习题 - 3.线性模型

    1.线性回归 1.以下哪个不是线性模型的优势? 简单 复杂 基本 可理解性好 2.示例的属性可以属于下列哪个类别? 无序的离散属性 连续属性 有序的离散属性 以上都对 3.一卖伞商家想利用天气来预测销 ...

  4. 西瓜书习题4.3(基于信息熵的决策树)

    试编程实现基于信息熵进行划分选择的决策树算法,并为表4.3中数据生成一颗决策树. 代码 import numpy as np import matplotlib.pyplot as plt from ...

  5. 西瓜书习题 - 10.机器学习初步考试

    1.当学习器在训练集上把训练样本自身的一些特征当作了所有潜在样本都具有的一般性质时,泛化性能可能会因此下降,这种现象一般称为 ____.(过拟合/欠拟合) 过拟合 2.对于两个样本点 (0,0),(1 ...

  6. [西瓜书习题] 第二章 模型评估与选择

    2.1 数据集包含1000个样本,其中500个正例,500个反例,将其划分为包含70%样本的训练集和30%样本的测试集用于留出法评估,试估算共有多少种划分方式. 留出法将数据集划分为两个互斥的集合,为 ...

  7. 【机器学习-西瓜书】四、决策树:信息熵;信息增益;增益率;ID3;C4.5

    推荐阅读:纯度:信息熵:信息增益 关键词: 纯度:信息熵:信息增益:增益率:ID3:C4.5:基尼指数:预剪枝:后剪枝 4.1基本流程 关键词:决策树(decision tree) 决策树是一种分类方 ...

  8. 西瓜书习题 - 8.集成学习

    1.集成学习 1.下列关于集成学习描述错误的是哪个? 集成学习只能使用若干个相同类型的学习器 集成学习使用多个学习器解决问题 集成学习在许多比赛中取得了优异的成绩 集成学习在英文中是一个外来词 2.下 ...

  9. 「西瓜书」阅读笔记——决策树

    决策树是机器学习中一类非常著名的算法,它模拟人们在解决一个决策问题时的思考方式,因此具有非常好的可解释性.一般来说,一个训练好的决策树模型可以转化成一系列的"if-then"语句, ...

  10. 西瓜书《机器学习》决策树IDW3, C4.5公式推导

最新文章

  1. 分布式事务 GTS 的价值和原理浅析
  2. numpy matplotlib
  3. 《MySQL管理之道:性能调优、高可用与监控》china-pub首发!
  4. 从头学习linux C 冒泡法排序
  5. 软件工程详细设计说明书_软件工程导论知识点梳理之简答题
  6. 996.ICU 下被过度消费的程序员,还配享受生活吗?
  7. 单词的理解 —— 通过上下文环境
  8. 微信小程序——图片打马赛克
  9. 华为odjava机试题_手心里的咕咕机,华为手机大小,性价比赶超小米的学习打印机...
  10. sqlplus连接mysql_sqlplus连接的三种方式
  11. BAT 条件判断 IF
  12. 爱康科技压力大:前三季亏损1.2亿,中泰证券喊话全年净利3.92亿
  13. 几种 FPGA 芯片的工艺结构
  14. linux python2升级到python3(源码编译安装)
  15. 记一次搭建 nodebb 论坛
  16. MAC系统重置root密码
  17. 自己做量化交易软件(9通通量化框架的雏形建立
  18. Scrum敏捷价值观与原则
  19. 雷军微博拧螺丝CFO为粉丝数发愁
  20. 数据分析报告中如何选择合适的统计图表

热门文章

  1. 打印excel html js,前端js打印(导出)excel表格的方法实例
  2. The client-side rendered virtual DOM tree is not matching server-rendered content
  3. 详解navigator对象
  4. Mac OS high Sierra 10.13.6 安装cuda
  5. java计算机毕业设计家用电器销售网站源码+mysql数据库+系统+lw文档+部署
  6. Head First 设计模式笔记 4.工厂模式
  7. WPS Excel表格怎么启用宏功能?
  8. 和数研究院4周年庆,初心不改,笃行致远!
  9. 《路由器开发 - 路由器刷机指南》华硕路由器RT-N66W刷机
  10. 智慧城市大屏可视化(Axure高保真原型)