文章目录

  • 一、决策树介绍
    • 利用信息增益选择最优划分属性
  • 二、实现针对西瓜数据集的ID3算法代码,并输出可视化结果。
    • 1、西瓜数据集
    • 2. 代码实现
      • (1)建立决策树
      • (2)绘制决策树
  • 三、C4.5方法建立决策树
  • 四、使用CART算法
  • 五、总结
  • 六、参考链接

一、决策树介绍

决策树是一种基于树结构来进行决策的分类算法,我们希望从给定的训练数据集学得一个模型(即决策树),用该模型对新样本分类。决策树可以非常直观展现分类的过程和结果,一旦模型构建成功,对新样本的分类效率也相当高。

最经典的决策树算法有ID3、C4.5、CART,其中ID3算法是最早被提出的,它可以处理离散属性样本的分类,C4.5和CART算法则可以处理更加复杂的分类问题。

利用信息增益选择最优划分属性

样本有多个属性,该先选哪个样本来划分数据集呢?原则是随着划分不断进行,我们希望决策树的分支节点所包含的样本尽可能属于同一分类,即“纯度”越来越高。先来学习一下“信息熵”和“信息增益”。
信息熵(information entropy)
样本集合D中第k类样本所占的比例(k=1,2,…,|Y|),|Y|为样本分类的个数,则D的信息熵为:

Ent(D)的值越小,则D的纯度越高。直观理解一下:假设样本集合有2个分类,每类样本的比例为1/2,Ent(D)=1;只有一个分类,Ent(D)= 0,显然后者比前者的纯度高。

信息增益(information gain)

使用属性a对样本集D进行划分所获得的“信息增益”的计算方法是,用样本集的总信息熵减去属性a的每个分支的信息熵与权重(该分支的样本数除以总样本数)的乘积,通常,信息增益越大,意味着用属性a进行划分所获得的“纯度提升”越大。因此,优先选择信息增益最大的属性来划分。设属性a有V个可能的取值,则属性a的信息增益为:

增益率(gain ratio)
基于信息增益的最优属性划分原则——信息增益准则
,对可取值数据较多的属性有所偏好。C 4.5 C4.5C4.5算法使用增益率代替信息增益来选择最优划分属性,增益率定义为:

其中

称为属性 a aa 的固有值。属性 a aa 的可能取值数目越多(即V VV越大),则 I V ( a ) IV(a)IV(a) 的值通常会越大。这在一定程度上消除了对可取值数据较多的属性的偏好。
  事实上,增益率准则对可取值数目较少的属性有所偏好,C 4.5 C4.5C4.5 算法并不是直接使用增益率准则,而是先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的。
基尼指数(Gini index)
C A R T CARTCART 决策树算法使用基尼指数(Gini index)来选择划分属性。数据集 D DD 的纯度可用基尼值来度量:

G i n i ( D ) Gini(D)Gini(D) 反应了从数据集 D DD 中随机抽取两个样本,其类别标记不一致的概率。由此,G i n i ( D ) Gini(D)Gini(D) 越小,纯度越高。
  属性 a aa 的基尼指数定义为:

在候选属性集合 A AA 中,选择那个使得划分后基尼指数最小的属性作为最优化分属性。即

二、实现针对西瓜数据集的ID3算法代码,并输出可视化结果。

1、西瓜数据集

青绿 蜷缩 浊响 清晰 凹陷 硬滑 是
乌黑 蜷缩 沉闷 清晰 凹陷 硬滑 是
乌黑 蜷缩 浊响 清晰 凹陷 硬滑 是
青绿 蜷缩 沉闷 清晰 凹陷 硬滑 是
浅白 蜷缩 浊响 清晰 凹陷 硬滑 是
青绿 稍蜷 浊响 清晰 稍凹 软粘 是
乌黑 稍蜷 浊响 稍糊 稍凹 软粘 是
乌黑 稍蜷 浊响 清晰 稍凹 硬滑 是
乌黑 稍蜷 沉闷 稍糊 稍凹 硬滑 否
青绿 硬挺 清脆 清晰 平坦 软粘 否
浅白 硬挺 清脆 模糊 平坦 硬滑 否
浅白 蜷缩 浊响 模糊 平坦 软粘 否
青绿 稍蜷 浊响 稍糊 凹陷 硬滑 否
浅白 稍蜷 沉闷 稍糊 凹陷 硬滑 否
乌黑 稍蜷 浊响 清晰 稍凹 软粘 否
浅白 蜷缩 浊响 模糊 平坦 硬滑 否
青绿 蜷缩 沉闷 稍糊 稍凹 硬滑 否

2. 代码实现

(1)建立决策树

计算信息熵函数

#计算信息熵
def calcInformationEntropy(dataSet):#dataSet最后一列是类别,前面是特征dict = {}m = len(dataSet)for i in range(m):#.get()函数:如果没有这个key,就返回默认值;如果有这个key,就返回这个key的valuedict[dataSet[i][-1]] = dict.get(dataSet[i][-1], 0) + 1;ent = 0for key in dict.keys():p = float(dict[key]) / ment = ent - (p * np.math.log(p, 2))return ent

划分数据集函数

#划分数据集
#dataSet:数据集
#axis: 要划分的列下标
#value: 要划分的列的值
def splitDataSet(dataSet, axis, value):splitedDataSet = []for data in dataSet:if(data[axis] == value):reduceFeatureVec = data[: axis]reduceFeatureVec.extend(data[axis + 1 :])splitedDataSet.append(reduceFeatureVec)return splitedDataSet

计算信息增益函数

#计算信息增益,然后选择最优的特征进行划分数据集
#信息增益的计算公式:西瓜书P75
def chooseBestFeatureToSplit(dataSet):#计算整个集合的熵EntD = calcInformationEntropy(dataSet)mD = len(dataSet)  #行featureNumber = len(dataSet[0][:]) - 1 #列maxGain = -1000bestFeatureIndex = -1for i in range(featureNumber):#featureSet = set(dataSet[:][i])  #错误写法:dataSet[:][i]仍然是获取行featureCol = [x[i] for x in dataSet]   #取列表某列的方法!!featureSet = set(featureCol)splitedDataSet = []for av in featureSet:retDataSet = splitDataSet(dataSet, i, av)splitedDataSet.append(retDataSet)gain = EntDfor ds in splitedDataSet:mDv = len(ds)gain = gain - (float(mDv) / mD) * calcInformationEntropy(ds)if(bestFeatureIndex == -1):maxGain = gainbestFeatureIndex = ielif(maxGain < gain):maxGain = gainbestFeatureIndex = ireturn bestFeatureIndex#当所有的特征划分完了之后,如果仍然有叶子节点中的数据不是同一个类别,
# 则把类别最多的作为这个叶子节点的标签
def majorityCnt(classList):dict = {}for label in classList:dict[label] = dict.get(label, 0) + 1sortedDict = sorted(dict, dict.items(), key = operator.itemgetter(1), reversed = True)return sortedDict[0][0]

递归构建决策树

#递归构建决策树
def createTree(dataSet, labels):classList = [x[-1] for x in dataSet]
#    if(len(set(classList)) == 1):
#        return classList[0]if(classList.count(classList[0]) == len(classList)):return classList[0]elif(len(dataSet[0]) == 1):  #所有的属性全部划分完毕return majorityCnt(classList)else:bestFeatureIndex = chooseBestFeatureToSplit(dataSet)bestFeatureLabel = labels[bestFeatureIndex]myTree = {bestFeatureLabel: {}}del(labels[bestFeatureIndex])  #使用完该属性之后,要删除featureList = [x[bestFeatureIndex] for x in dataSet]featureSet = set(featureList)for feature in featureSet:subLabels = labels[:]  #拷贝一份,防止label在递归的时候被修改  (list是传引用调用)tmpDataSet = splitDataSet(dataSet, bestFeatureIndex, feature)  #划分数据集myTree[bestFeatureLabel][feature] = createTree(tmpDataSet, subLabels)return myTree

读取数据

#读取西瓜数据集2.0
def readWatermelonDataSet():ifile = open("西瓜数据集.txt")featureName = ifile.readline()  #表头labels = (featureName.split(' ')[0]).split(',')lines = ifile.readlines()dataSet = []for line in lines:tmp = line.split('\n')[0]tmp = tmp.split(',')dataSet.append(tmp)return dataSet, labels

输出

melonDataSet, melonLabels = readWatermelonDataSet()
print(melonLabels)
melonBestFeature = chooseBestFeatureToSplit(melonDataSet)
tree = createTree(melonDataSet, melonLabels)
print(tree)

[‘色泽’, ‘根蒂’, ‘敲声’, ‘纹理’, ‘脐部’, ‘触感’, ‘好瓜’]
{‘纹理’: {‘稍糊’: {‘触感’: {‘软粘’: ‘是’, ‘硬滑’: ‘否’}}, ‘模糊’: ‘否’, ‘清晰’: {‘根蒂’: {‘蜷缩’: ‘是’, ‘稍蜷’: {‘色泽’: {‘乌黑’: {‘触感’: {‘软粘’: ‘否’, ‘硬滑’: ‘是’}}, ‘青绿’: ‘是’}}, ‘硬挺’: ‘否’}}}}

(2)绘制决策树

#使用Matlotlib绘制决策树
import matplotlib.pyplot as plt#设置文本框和箭头格式
decisionNode = dict(boxstyle = "sawtooth", fc = "0.8")
leafNode = dict(boxstyle = "round4", fc = "0.8")
arrow_args = dict(arrowstyle = "<-")
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['font.family'] = 'sans-serif'#画节点
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)#获取决策树的叶子节点数
def getNumLeafs(myTree):leafNumber = 0firstStr = list(myTree.keys())[0]secondDict = myTree[firstStr]for key in secondDict.keys():if(type(secondDict[key]).__name__ == 'dict'):leafNumber = leafNumber + getNumLeafs(secondDict[key])else:leafNumber += 1return leafNumber#获取决策树的高度(递归)
def getTreeDepth(myTree):maxDepth = 0firstStr = list(myTree.keys())[0]secondDict = myTree[firstStr]for key in secondDict.keys():#test to see if the nodes are dictonaires, if not they are leaf nodesif type(secondDict[key]).__name__=='dict':thisDepth = 1 + getTreeDepth(secondDict[key])else:   thisDepth = 1if thisDepth > maxDepth: maxDepth = thisDepthreturn maxDepth#在父子节点添加信息
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)#画树
def plotTree(myTree, parentPt, nodeTxt):#if the first key tells you what feat was split onnumLeafs = getNumLeafs(myTree)  #this determines the x width of this treedepth = getTreeDepth(myTree)firstStr = list(myTree.keys())[0]     #the text label for this node should be thiscntrPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)plotMidText(cntrPt, parentPt, nodeTxt)plotNode(firstStr, cntrPt, parentPt, decisionNode)secondDict = myTree[firstStr]plotTree.yOff = plotTree.yOff - 1.0/plotTree.totalDfor key in secondDict.keys():if type(secondDict[key]).__name__=='dict':plotTree(secondDict[key],cntrPt,str(key))        #recursionelse:   #it's a leaf node print the leaf nodeplotTree.xOff = plotTree.xOff + 1.0/plotTree.totalWplotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD#画布初始化
def createPlot(inTree):fig = plt.figure(1, facecolor='white')fig.clf()axprops = dict(xticks=[], yticks=[])createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)    #no ticks#createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropsesplotTree.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()

输出结果:

三、C4.5方法建立决策树

相关数据:

编号 色泽 根蒂 敲声 纹理 脐部 触感 好瓜
1 青绿 蜷缩 浊响 清晰 凹陷 硬滑 是
2 乌黑 蜷缩 沉闷 清晰 凹陷 硬滑 是
3 乌黑 蜷缩 浊响 清晰 凹陷 硬滑 是
4 青绿 蜷缩 沉闷 清晰 凹陷 硬滑 是
5 浅白 蜷缩 浊响 清晰 凹陷 硬滑 是
6 青绿 稍蜷 浊响 清晰 稍凹 软粘 是
7 乌黑 稍蜷 浊响 稍糊 稍凹 软粘 是
8 乌黑 稍蜷 浊响 清晰 稍凹 硬滑 是
9 乌黑 稍蜷 沉闷 稍糊 稍凹 硬滑 否
10 青绿 硬挺 清脆 清晰 平坦 软粘 否
11 浅白 硬挺 清脆 模糊 平坦 硬滑 否
12 浅白 蜷缩 浊响 模糊 平坦 软粘 否
13 青绿 稍蜷 浊响 稍糊 凹陷 硬滑 否
14 浅白 稍蜷 沉闷 稍糊 凹陷 硬滑 否
15 乌黑 稍蜷 浊响 清晰 稍凹 软粘 否
16 浅白 蜷缩 浊响 模糊 平坦 硬滑 否
17 青绿 蜷缩 沉闷 稍糊 稍凹 硬滑 否

导入相关库

#导入相关库
import pandas as pd
import graphviz
from sklearn.model_selection import train_test_split
from sklearn import tree

导入数据

f = open('water.csv','r')
data = pd.read_csv(f)x = data[["色泽","根蒂","敲声","纹理","脐部","触感"]].copy()
y = data['好瓜'].copy()
print(data)

将特征值数值化

#将特征值数值化
x = x.copy()
for i in ["色泽","根蒂","敲声","纹理","脐部","触感"]:for j in range(len(x)):if(x[i][j] == "青绿" or x[i][j] == "蜷缩" or data[i][j] == "浊响" \or x[i][j] == "清晰" or x[i][j] == "凹陷" or x[i][j] == "硬滑"):x[i][j] = 1elif(x[i][j] == "乌黑" or x[i][j] == "稍蜷" or data[i][j] == "沉闷" \or x[i][j] == "稍糊" or x[i][j] == "稍凹" or x[i][j] == "软粘"):x[i][j] = 2else:x[i][j] = 3y = y.copy()
for i in range(len(y)):if(y[i] == "是"):y[i] = int(1)else:y[i] = int(-1) 

将数据转换为DataFrame数据类型

#需要将数据x,y转化好格式,数据框dataframe,否则格式报错
x = pd.DataFrame(x).astype(int)
y = pd.DataFrame(y).astype(int)
print(x)
print(y)


将80%数据用于训练,20%数据用于测试

 x_train, x_test, y_train, y_test = train_test_split(x,y,test_size=0.2)
print(x_train)


建立模型并训练

sklearn.tree.DecisionTreeClassifier(criterion=’gini’,\splitter=’best’, \max_depth=None, \min_samples_split=2, \min_samples_leaf=1,\min_weight_fraction_leaf=0.0, \max_features=None, \max_leaf_nodes=None, \min_impurity_decrease=0.0,\min_impurity_split=None, \class_weight=None, \presort=False)

可视化决策树

feature_name = ["色泽","根蒂","敲声","纹理","脐部","触感"]
dot_data = tree.export_graphviz(clf                          ,feature_names= feature_name                                ,class_names=["好瓜","坏瓜"]                                ,filled=True                                ,rounded=True,out_file =None  )
graph = graphviz.Source(dot_data)
graph

四、使用CART算法

只需要将DecisionTreeClassifier函数的参数criterion的值改为gini:

clf = tree.DecisionTreeClassifier(criterion="gini")  #实例化
clf = clf.fit(x_train, y_train)
score = clf.score(x_test, y_test)
print(score)

画决策树:

# 加上Graphviz2.38绝对路径
import os
os.environ["PATH"] += os.pathsep + 'D:/workspace/wrater'feature_name = ["色泽","根蒂","敲声","纹理","脐部","触感"]
dot_data = tree.export_graphviz(clf ,feature_names= feature_name,class_names=["好瓜","坏瓜"],filled=True,rounded=True,out_file =None)
graph = graphviz.Source(dot_data)
graph

五、总结

决策树作为经典分类算法,具有计算复杂度低、结果直观、分类效率高等优点。
学习通过用sk-learn库对西瓜数据集,分别进行ID3、C4.5和CART的算法代码实现。
这次的西瓜数据集较小,测试集和训练集的划分对模型精度的影响较大。

六、参考链接

ID3算法流程
西瓜书中ID3决策树的实现
https://blog.csdn.net/leaf_zizi/article/details/82848682

决策树挑出好西瓜(基于ID3、C4.6、CART实现)相关推荐

  1. 决策树挑出好西瓜(基于ID3、CART)

    决策树挑出好西瓜(基于ID3.CART) 一.决策树 1. 介绍 2. 决策树事件处理流程 3. 理论基础 二.ID3决策树及Python实现 1. 数据处理 2. 步骤 3. 决策树实现 4. 分析 ...

  2. 决策树数学原理(ID3,c4.5,cart算法)

    上面这个图就是一棵典型的决策树.我们在做决策树的时候,会经历两个阶段:构造和剪枝. 构造 简单来说,构造的过程就是选择什么属性作为节点的过程,那么在构造过程中,会存在三种节点: 根节点:就是树的最顶端 ...

  3. 【机器学习】通过ID3,C4.5,CART算法构建决策树

    决策树 (一).决策树的简介 (二).构造决策树的三种构造方法 1.基于信息增益生成决策树(ID3算法) 2.基于信息增益率生成决策树(C4.5算法) 3.基于基尼指数生成决策树(CART算法) 总结 ...

  4. 通过实例理解决策树算法(ID3,C4.5,Cart算法)

    (一)实例:使用ID3算法给出"好苹果"的决策树 (二)决策树的工作原理 我们在做决策树的时候,会经历两个阶段:构造和剪枝. 构造原理--构造的过程就是选择什么属性作为节点的过程, ...

  5. 决策树 基于python实现ID3,C4.5,CART算法

    实验目录 实验环境 简介 决策树(decision tree) 信息熵 信息增益(应用于ID3算法) 信息增益率(在C4.5算法中使用) 基尼指数(被用于CART算法) 实验准备 数据集 算法大体流程 ...

  6. 【机器学习】 ID3,C4.5,CART决策树

    决策树模型在监督学习中非常常见,可用于分类(二分类.多分类)和回归.虽然将多棵弱决策树的Bagging.Random Forest.Boosting等tree ensembel 模型更为常见,但是&q ...

  7. cart算法_【统计学】决策树模型大比拼!ID3/C4.5/CART算法哪个更好用?

    - 点击上方"中国统计网"订阅我吧!- 决策树模型在监督学习中非常常见,可用于分类(二分类.多分类)和回归.虽然将多棵弱决策树的Bagging.Random Forest.Boos ...

  8. 机器学习:决策树及ID3,C4.5,CART算法描述

    文章目录 概念理解 熵: 条件熵: 信息增益,互信息: 信息增益比 基尼指数 ID3算法描述 C4.5算法描述 CART (Classification and Regression Tree)算法描 ...

  9. 决策树模型(ID3/C4.5/CART)原理和底层代码解读 学习笔记

    本文作者:合肥工业大学 管理学院 钱洋 email:1563178220@qq.com 内容可能有不到之处,欢迎交流. 未经本人允许禁止转载 如下为个人的学习笔记,使用latex编写,再写成文本太麻烦 ...

最新文章

  1. 如何用Python实现多任务版的udp聊天器
  2. hdu 5512 Pagodas
  3. ecs服务器配置git_阿里云 ECS服务器(CentOS 7)安装和使用Gitlab教程
  4. php代码冗余度检查插件,合并ThinkPHP配置文件以消除代码冗余的实现方法
  5. imx6 板卡移植官方yocto版本(1_安装环境)
  6. FCKeditor的开发精简
  7. 删除顺序表中指定值的所有元素(C++,vector)
  8. sharepoint webpart
  9. 新iPhone同款?谷歌Pixel 4渲染图曝光:“浴霸”相机模组抢眼
  10. 有意思的《致招商银行的公开信》行动!
  11. Clojure 学习入门(12)- map/pmap
  12. HCIE Security 防火墙NAT技术 备考笔记(幕布)
  13. linux教程,linux视频教程,linux…
  14. 《产品结构设计》——黎恢来,笔记
  15. 一、博客首页搭建搭建《iVX低代码仿CSDN个人博客制作》
  16. 禁用EnableViewState和启用EnableViewStat时请注意
  17. Kelihos荣升恶意软件之王
  18. 获取文件名,文件名后缀以及elementui多张图片回显
  19. python turtle 乌龟赛跑_海龟快跑,turtle碰撞检测小游戏
  20. jquery option selected 无效

热门文章

  1. 阿里云账号选择个人认证还是企业认证好?企业实名认证有什么优惠政策?
  2. 简述常用人工神经网络方法的基本原理
  3. Jquery通过submitHandler 实现验证后跳转到别的页面
  4. 外星人装linux系统,alienware-area-51m win10+ubuntu18.04安装教程
  5. 单片AR眼镜Monocle揭秘:基于反射棱镜,重15g续航1小时
  6. 寻找锦鲤|总价值超过2万元的大奖获得者,到底是不是你?
  7. PB中TriggerEvent用法详解
  8. FIR 滤波器四种结构形式的MATLAB 实现
  9. Python代码实现猜数字游戏随机生成数字进行比对
  10. Easy AR通过Http协议上传本地图片至云图库