python实现决策树分类


Posted in Python onAugust 30, 2018

上一篇博客主要介绍了决策树的原理,这篇主要介绍他的实现,代码环境python 3.4,实现的是ID3算法,首先为了后面matplotlib的绘图方便,我把原来的中文数据集变成了英文。

原始数据集:

python实现决策树分类

变化后的数据集在程序代码中体现,这就不截图了

构建决策树的代码如下:

#coding :utf-8
'''
2017.6.25 author :Erin 
   function: "decesion tree" ID3
   
'''
import numpy as np
import pandas as pd
from math import log
import operator 
def load_data():
 
 #data=np.array(data)
 data=[['teenager' ,'high', 'no' ,'same', 'no'],
   ['teenager', 'high', 'no', 'good', 'no'],
   ['middle_aged' ,'high', 'no', 'same', 'yes'],
   ['old_aged', 'middle', 'no' ,'same', 'yes'],
   ['old_aged', 'low', 'yes', 'same' ,'yes'],
   ['old_aged', 'low', 'yes', 'good', 'no'],
   ['middle_aged', 'low' ,'yes' ,'good', 'yes'],
   ['teenager' ,'middle' ,'no', 'same', 'no'],
   ['teenager', 'low' ,'yes' ,'same', 'yes'],
   ['old_aged' ,'middle', 'yes', 'same', 'yes'],
   ['teenager' ,'middle', 'yes', 'good', 'yes'],
   ['middle_aged' ,'middle', 'no', 'good', 'yes'],
   ['middle_aged', 'high', 'yes', 'same', 'yes'],
   ['old_aged', 'middle', 'no' ,'good' ,'no']]
 features=['age','input','student','level']
 return data,features
 
def cal_entropy(dataSet):
 '''
 输入data ,表示带最后标签列的数据集
 计算给定数据集总的信息熵
 {'是': 9, '否': 5}
 0.9402859586706309
 '''
 
 numEntries = len(dataSet)
 labelCounts = {}
 for featVec in dataSet:
  label = featVec[-1]
  if label not in labelCounts.keys():
   labelCounts[label] = 0
  labelCounts[label] += 1
 entropy = 0.0
 for key in labelCounts.keys():
  p_i = float(labelCounts[key]/numEntries)
  entropy -= p_i * log(p_i,2)#log(x,10)表示以10 为底的对数
 return entropy
 
def split_data(data,feature_index,value):
 '''
 划分数据集
 feature_index:用于划分特征的列数,例如“年龄”
 value:划分后的属性值:例如“青少年”
 '''
 data_split=[]#划分后的数据集
 for feature in data:
  if feature[feature_index]==value:
   reFeature=feature[:feature_index]
   reFeature.extend(feature[feature_index+1:])
   data_split.append(reFeature)
 return data_split
def choose_best_to_split(data):
 
 '''
 根据每个特征的信息增益,选择最大的划分数据集的索引特征
 '''
 
 count_feature=len(data[0])-1#特征个数4
 #print(count_feature)#4
 entropy=cal_entropy(data)#原数据总的信息熵
 #print(entropy)#0.9402859586706309
 
 max_info_gain=0.0#信息增益最大
 split_fea_index = -1#信息增益最大,对应的索引号
 
 for i in range(count_feature):
  
  feature_list=[fe_index[i] for fe_index in data]#获取该列所有特征值
  #######################################
  '''
  print('feature_list')
  ['青少年', '青少年', '中年', '老年', '老年', '老年', '中年', '青少年', '青少年', '老年',
  '青少年', '中年', '中年', '老年']
  0.3467680694480959 #对应上篇博客中的公式 =(1)*5/14
  0.3467680694480959
  0.6935361388961918
  '''
  # print(feature_list)
  unqval=set(feature_list)#去除重复
  Pro_entropy=0.0#特征的熵
  for value in unqval:#遍历改特征下的所有属性
   sub_data=split_data(data,i,value)
   pro=len(sub_data)/float(len(data))
   Pro_entropy+=pro*cal_entropy(sub_data)
   #print(Pro_entropy)
   
  info_gain=entropy-Pro_entropy
  if(info_gain>max_info_gain):
   max_info_gain=info_gain
   split_fea_index=i
 return split_fea_index
  
  
##################################################
def most_occur_label(labels):
 #sorted_label_count[0][0] 次数最多的类标签
 label_count={}
 for label in labels:
  if label not in label_count.keys():
   label_count[label]=0
  else:
   label_count[label]+=1
  sorted_label_count = sorted(label_count.items(),key = operator.itemgetter(1),reverse = True)
 return sorted_label_count[0][0]
def build_decesion_tree(dataSet,featnames):
 '''
 字典的键存放节点信息,分支及叶子节点存放值
 '''
 featname = featnames[:]    ################
 classlist = [featvec[-1] for featvec in dataSet] #此节点的分类情况
 if classlist.count(classlist[0]) == len(classlist): #全部属于一类
  return classlist[0]
 if len(dataSet[0]) == 1:   #分完了,没有属性了
  return Vote(classlist)  #少数服从多数
 # 选择一个最优特征进行划分
 bestFeat = choose_best_to_split(dataSet)
 bestFeatname = featname[bestFeat]
 del(featname[bestFeat])  #防止下标不准
 DecisionTree = {bestFeatname:{}}
 # 创建分支,先找出所有属性值,即分支数
 allvalue = [vec[bestFeat] for vec in dataSet]
 specvalue = sorted(list(set(allvalue))) #使有一定顺序
 for v in specvalue:
  copyfeatname = featname[:]
  DecisionTree[bestFeatname][v] = build_decesion_tree(split_data(dataSet,bestFeat,v),copyfeatname)
 return DecisionTree

绘制可视化图的代码如下:

def getNumLeafs(myTree):
 '计算决策树的叶子数'
 
 # 叶子数
 numLeafs = 0
 # 节点信息
 sides = list(myTree.keys()) 
 firstStr =sides[0]
 # 分支信息
 secondDict = myTree[firstStr]
 
 for key in secondDict.keys(): # 遍历所有分支
  # 子树分支则递归计算
  if type(secondDict[key]).__name__=='dict':
   numLeafs += getNumLeafs(secondDict[key])
  # 叶子分支则叶子数+1
  else: numLeafs +=1
  
 return numLeafs
 
 
def getTreeDepth(myTree):
 '计算决策树的深度'
 
 # 最大深度
 maxDepth = 0
 # 节点信息
 sides = list(myTree.keys()) 
 firstStr =sides[0]
 # 分支信息
 secondDict = myTree[firstStr]
 
 for key in secondDict.keys(): # 遍历所有分支
  # 子树分支则递归计算
  if type(secondDict[key]).__name__=='dict':
   thisDepth = 1 + getTreeDepth(secondDict[key])
  # 叶子分支则叶子数+1
  else: thisDepth = 1
  
  # 更新最大深度
  if thisDepth > maxDepth: maxDepth = thisDepth
  
 return maxDepth
 
import matplotlib.pyplot as plt
 
decisionNode = dict(boxstyle="sawtooth", fc="0.8")
leafNode = dict(boxstyle="round4", fc="0.8")
arrow_args = dict(arrowstyle="<-")
 
# ==================================================
# 输入:
#  nodeTxt:  终端节点显示内容
#  centerPt: 终端节点坐标
#  parentPt: 起始节点坐标
#  nodeType: 终端节点样式
# 输出:
#  在图形界面中显示输入参数指定样式的线段(终端带节点)
# ==================================================
def plotNode(nodeTxt, centerPt, parentPt, nodeType):
 '画线(末端带一个点)'
  
 createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction', xytext=centerPt, textcoords='axes fraction', va="center", ha="center", bbox=nodeType, arrowprops=arrow_args )
 
# =================================================================
# 输入:
#  cntrPt:  终端节点坐标
#  parentPt: 起始节点坐标
#  txtString: 待显示文本内容
# 输出:
#  在图形界面指定位置(cntrPt和parentPt中间)显示文本内容(txtString)
# =================================================================
def plotMidText(cntrPt, parentPt, txtString):
 '在指定位置添加文本'
 
 # 中间位置坐标
 xMid = (parentPt[0]-cntrPt[0])/2.0 + cntrPt[0]
 yMid = (parentPt[1]-cntrPt[1])/2.0 + cntrPt[1]
 
 createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30)
 
# ===================================
# 输入:
#  myTree: 决策树
#  parentPt: 根节点坐标
#  nodeTxt: 根节点坐标信息
# 输出:
#  在图形界面绘制决策树
# ===================================
def plotTree(myTree, parentPt, nodeTxt):
 '绘制决策树'
 
 # 当前树的叶子数
 numLeafs = getNumLeafs(myTree)
 # 当前树的节点信息
 sides = list(myTree.keys()) 
 firstStr =sides[0]
 
 # 定位第一棵子树的位置(这是蛋疼的一部分)
 cntrPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)
 
 # 绘制当前节点到子树节点(含子树节点)的信息
 plotMidText(cntrPt, parentPt, nodeTxt)
 plotNode(firstStr, cntrPt, parentPt, decisionNode)
 
 # 获取子树信息
 secondDict = myTree[firstStr]
 # 开始绘制子树,纵坐标-1。  
 plotTree.yOff = plotTree.yOff - 1.0/plotTree.totalD
  
 for key in secondDict.keys(): # 遍历所有分支
  # 子树分支则递归
  if type(secondDict[key]).__name__=='dict':
   plotTree(secondDict[key],cntrPt,str(key))
  # 叶子分支则直接绘制
  else:
   plotTree.xOff = plotTree.xOff + 1.0/plotTree.totalW
   plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)
   plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))
  
 # 子树绘制完毕,纵坐标+1。
 plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD
 
# ==============================
# 输入:
#  myTree: 决策树
# 输出:
#  在图形界面显示决策树
# ==============================
def createPlot(inTree):
 '显示决策树'
 
 # 创建新的图像并清空 - 无横纵坐标
 fig = plt.figure(1, facecolor='white')
 fig.clf()
 axprops = dict(xticks=[], yticks=[])
 createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)
 
 # 树的总宽度 高度
 plotTree.totalW = float(getNumLeafs(inTree))
 plotTree.totalD = float(getTreeDepth(inTree))
 
 # 当前绘制节点的坐标
 plotTree.xOff = -0.5/plotTree.totalW; 
 plotTree.yOff = 1.0;
 
 # 绘制决策树
 plotTree(inTree, (0.5,1.0), '')
 
 plt.show()
 
if __name__ == '__main__':
 data,features=load_data()
 split_fea_index=choose_best_to_split(data)
 newtree=build_decesion_tree(data,features)
 print(newtree)
 createPlot(newtree)
 '''
 {'age': {'old_aged': {'level': {'same': 'yes', 'good': 'no'}}, 'teenager': {'student': {'no': 'no', 'yes': 'yes'}}, 'middle_aged': 'yes'}}
 '''

结果如下:

python实现决策树分类

怎么用决策树分类,将会在下一章。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在Python中用keys()方法返回字典键的教程
May 21 Python
python判断一个集合是否包含了另外一个集合中所有项的方法
Jun 30 Python
Python的Django框架中的数据库配置指南
Jul 17 Python
Python的Django框架中的数据过滤功能
Jul 17 Python
Python 爬虫学习笔记之多线程爬虫
Sep 21 Python
Python读取excel指定列生成指定sql脚本的方法
Nov 28 Python
python爬虫URL重试机制的实现方法(python2.7以及python3.5)
Dec 18 Python
python适合人工智能的理由和优势
Jun 28 Python
django数据模型(Model)的字段类型解析
Dec 25 Python
Python urllib库如何添加headers过程解析
Oct 05 Python
pycharm激活码2020最新分享适用pycharm2020最新版亲测可用
Nov 22 Python
python_tkinter弹出对话框创建
Mar 20 Python
python实现多人聊天室
Mar 31 #Python
Python实现将数据写入netCDF4中的方法示例
Aug 30 #Python
Python使用爬虫抓取美女图片并保存到本地的方法【测试可用】
Aug 30 #Python
Python使用一行代码获取上个月是几月
Aug 30 #Python
Python实现的读取/更改/写入xml文件操作示例
Aug 30 #Python
python实现录音小程序
Oct 26 #Python
Python图像处理之简单画板实现方法示例
Aug 30 #Python
You might like
PHP中使用cURL实现Get和Post请求的方法
2013/03/13 PHP
Yii2结合Workerman的websocket示例详解
2018/09/10 PHP
完整显示当前日期和时间的JS代码
2007/09/17 Javascript
JQuery表格内容过滤的实现方法
2013/07/05 Javascript
JS 作用域与作用域链详解
2015/04/07 Javascript
使用JavaScript制作一个简单的计数器的方法
2015/07/07 Javascript
Javascript之String对象详解
2016/06/08 Javascript
原生js的RSA和AES加密解密算法
2016/10/08 Javascript
jQuery validate 验证radio实例
2017/03/01 Javascript
JS设计模式之惰性模式(二)
2017/09/29 Javascript
关于react-router/react-router-dom v4 history不能访问问题的解决
2018/01/08 Javascript
jQuery实现ajax回调函数带入参数的方法示例
2018/06/26 jQuery
详解基于Vue-cli搭建的项目如何和后台交互
2018/06/29 Javascript
微信小程序mpvue点击按钮获取button值的方法
2019/05/29 Javascript
vue中添加与删除关键字搜索功能
2019/10/12 Javascript
Vue如何循环提取对象数组中的值
2020/11/18 Vue.js
[01:05:00]2018国际邀请赛 表演赛 Pain vs OpenAI
2018/08/24 DOTA
Python 读写文件和file对象的方法(推荐)
2016/09/12 Python
python 读写txt文件 json文件的实现方法
2016/10/22 Python
django数据库migrate失败的解决方法解析
2018/02/08 Python
python调用API实现智能回复机器人
2018/04/10 Python
tensorflow实现简单的卷积神经网络
2018/05/24 Python
Python简单过滤字母和数字的方法小结
2019/01/09 Python
Pytorch根据layers的name冻结训练方式
2020/01/06 Python
python实现扫雷小游戏
2020/04/24 Python
python爬虫基础知识点整理
2020/06/02 Python
Selenium+BeautifulSoup+json获取Script标签内的json数据
2020/12/07 Python
浅谈html5 video 移动端填坑记
2018/01/15 HTML / CSS
工作失误检讨书范文大全
2014/01/13 职场文书
室内拓展活动方案
2014/02/13 职场文书
班级安全教育实施方案
2014/02/23 职场文书
外语系毕业生求职自荐信
2014/04/12 职场文书
学生检讨书怎么写
2014/10/09 职场文书
党支部创先争优公开承诺书
2015/04/30 职场文书
2019思想汇报范文
2019/05/21 职场文书
一定要知道的 25 个 Vue 技巧
2021/11/02 Vue.js