手把手生成决策树(dicision tree)

标签: Python 机器学习

主要參考资料:

Peter HARRINGTON.机器学习实战[M].李锐,李鹏,曲亚东,王斌译.北京:人民邮电出版社, 2013.

李航.统计学习方法[M].北京:清华大学出版社, 2012


原文链接:http://blog.csdn.net/xuelabizp/article/details/50979469

1.什么是决策树

决策树是一种主要的分类和回归方法。本文主要解说用于分类的决策树。

决策树就是依据相关的条件进行分类的一种树形结构,比方某高端约会站点针对女客户约会对象见面的安排过程就是一个决策树:

依据给定的数据集创建一个决策树就是机器学习的课程,创建一个决策树可能会花费较多的时间。可是使用一个决策树却很快。

创建决策树时最关键的问题就是选取哪一个特征作为分类特征。好的分类特征能够最大化的把数据集分开,将无序变为有序。

这里就出现了一个问题。怎样描写叙述一个数据集有序的程度?在信息论和概率统计中,表示随机变量不确定性的度量,即有序的程度。

现给出一个集合D。本文全部的讨论都以该集合为例:

序号 不浮出水面能否够生存 是否有脚蹼 是否为鱼类
1
2
3
4
5

创建该集合的代码例如以下:

def create_data_set():
dataSet = [[1,1,'yes'],
[1,1,'yes'],
[1,0,'no'],
[0,1,'no'],
[0,1,'no']]
labels = ['no surfacing', 'flippers'] #不浮出水面能否够生存。是否有脚蹼
return dataSet, labels

2.熵,信息增益和信息增益比

2.1熵(entropy)

博主第一次接触“熵”这个字。是在高中的化学课上,可是感觉“熵”在化学课上的含义和信息论中的含义没什么差别。都是表示混乱的程度,熵越大,越混乱,比方一杯浑浊水的熵就比一杯纯净的水熵大。

在信息论和概率统计中。设X是一个取有限个值的离散随机变量,其概率分布为:

P(X=xi)=pi,i=1,2,3,..,n(1)

则随机变量X的熵定义为:

H(X)=−∑i=1npilog2pi(2)

若pi=0。则规定0log0=0。须要说明的是。熵仅仅依赖于X的分布。而不依赖于X的值。依据(2)式就能够计算出上面给定的集合D的熵:

H(D)=−(−25log225−35log235)=0.971

编写计算熵的函数,当中dataSet是建立决策树的数据集,每行最后一个元素表示类别:

def cal_Ent(dataSet): #依据给定数据集计算熵
num = len(dataSet)
labels = {}
for row in dataSet: #统计全部标签的个数
label = row[-1]
if label not in labels.keys():
labels[label] = 0
labels[label] += 1
Ent = 0.0
for key in labels: #计算熵
prob = float(labels[key]) / num
Ent -= prob * log(prob, 2)
return Ent

2.2信息增益(information gain)

信息增益表示得知特征X的信息而使得类Y的信息的不确定性降低的程度。

换一个角度解释一下。一杯浑浊的水Y,其熵为H1,如今将当中悬浮的一类物质X去除。这杯水的熵下降为H2,则物质X对于这杯水的信息增益就为H1−H2。

特征X对数据集D的信息增益记为g(D,X),计算公式例如以下:

g(D,X)=H(D)−H(D|X)(3)

当中H(D|X)为特征X给定条件下D的经验条件熵。

先解释什么是条件熵:

条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性,定义为X给定条件下Y的条件概率分布的熵对X的数学期望。

条件熵的计算公式例如以下:

H(Y|X)=∑i=1npiH(Y|X=xi)(4)

当熵和条件熵中的概率由数据预计得到时,所相应的熵与条件熵分别称为经验熵经验条件熵

决策树选择某个特征作为其分类特征的依据就是该特征对于集合的信息增益最大,即去除该特征后,集合变得最有序。

仍旧以给定的集合D为例,依据计算信息增益准则选择最优分类特征。

以X1表示“不浮出水面能否够生存”。则

g(D,X1)=H(D)−[35H(D1)+25H(D2)]=0.971−[35(−23log223−13log213)+25(−22log222)]=0.420

当中D1,D2表示D中X1取“是”和“否”的样本子集。

以X2表示“是否有脚蹼”,则

g(D,X2)=H(D)−[45H(D1)+15H(D2)]=0.971−[45(−24log224−24log224)+15(−11log211)]=0.171

当中D1,D2表示D中X2取“是”和“否”的样本子集。

比較各个特征的信息增益。X1的信息增益较大,所以选择X1作为分类的最优特征。

编写选择最佳决策特征的函数,当中dataSet是建立决策树的数据集,每行最后一个元素表示类别:

#依照给定特征划分数据集,返回第axis个特征的值为value的全部数据
def split_data_set(dataSet, axis, value):
retDataSet = []
for row in dataSet:
if (row[axis]) == value:
reducedRow = row[:axis]
reducedRow.extend(row[axis+1:])
retDataSet.append(reducedRow)
return retDataSet #选择最佳决策特征
def choose_best_feature(dataSet):
num = len(dataSet[0]) - 1 #特征数
baseEnt = cal_Ent(dataSet)
bestInfoGain = 0.0
bestFeature = -1
for i in range(num):
featlist = [example[i] for example in dataSet] #按列遍历数据集,选取一个特征的全部值
uniqueVals = set(featlist) #一个特征能够取的值
newEnt = 0.0
for value in uniqueVals:
subDataSet = split_data_set(dataSet, i, value)
prob = len(subDataSet) / float(len(dataSet))
newEnt += prob * cal_Ent(subDataSet)
infoGain = baseEnt - newEnt #信息增益
if (infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature

ID3决策树在生成的过程中。依据信息增益来选择特征。

2.3信息增益比(information gain ratio)

以信息增益作为划分训练数据集的特征。存在偏向于选择取值较多的特征的问题,使用信息增益比能够对这一问题进行校正。

特征X对训练数据集D的信息增益比gR(D,X)定义为其信息增益g(D,X)与训练数据集D关于特征X的值的熵HX(D)之比。

信息增益比计算公式例如以下:

gR(D,X)=g(D,X)HX(D)(5)

当中

HX(D)=−∑i=1n|Di||D|log2|Di||D|(6)

以给定的集合D为例,计算信息增益比。

HX1(D)=−(−35log235−25log225)=0.971
gR(D,X1)=g(D,X1)HX1(D)=0.4200.971=0.433
HX2(D)=−(−45log245−15log215)=0.722
gR(D,X2)=g(D,X2)HX2(D)=0.1710.722=0.237

依据信息增益比,选择X1作为分类的最优特征。

C4.5决策树在生成的过程中。依据信息增益比来选择特征。

3.实现一个决策树

3.1创建或加载数据集

首先须要创建或加载训练的数据集,第一节用的是创建数据集的方法,只是更经常使用的是利用open()函数打开文件,加载一个数据集。

3.2生成决策树

决策树一般使用递归的方法生成。

编写递归函数有一个好习惯。就是先考虑结束条件。

生成决策树结束的条件有两个:其一是划分的数据都属于一个类,其二是全部的特征都已经使用了。在另外一种结束情况中。划分的数据有可能不全属于一个类,这个时候须要依据多数表决准则确定这个子数据集的分类。

在非结束的条件下。首先选择出信息增益最大的特征,然后依据其分类。

分类開始时,记录分类的特征到决策树中。然后在特征标签集中删除该特征。表示已经使用过该特征。依据选中的特征将数据集分为若干个子数据集,然后将子数据集作为參数递归创建决策树,终于生成一棵完整的决策树。

#多数表决法则
def majorityCnt(classList):
print classList
classCount = {}
for vote in classList: #统计数目
if vote not in classCount.keys(): classCount[vote] = 0
classCount += 1
sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return classCount[0][0] # 生成决策树
def create_tree(dataSet, labels):
labelsCloned = labels[:]
classList = [example[-1] for example in dataSet] #[yes,yes,no,no,no]
if classList.count(classList[0]) == len(classList): #仅仅有一种类别,则停止划分
return classList[0]
if len(dataSet[0]) == 1: #没有特征,则停止划分
return majorityCnt(classList)
#print dataSet
bestFeat = choose_best_feature(dataSet)
bestFeatLabel = labelsCloned[bestFeat] #最佳特征的名字
myTree = {bestFeatLabel:{}}
del(labelsCloned[bestFeat])
featValues = [example[bestFeat] for example in dataSet] #获取最佳特征的全部属性
uniqueVals = set(featValues)
for value in uniqueVals: #建立子树
subLabels = labelsCloned[:] #深拷贝,不能改变原始列表的内容,由于每个子树都要使用
myTree[bestFeatLabel][value] = create_tree(split_data_set(dataSet, bestFeat, value), subLabels)
return myTree

生成的决策树例如以下所看到的:

3.3使用决策树

使用决策树对输入进行分类的函数也是一个递归函数。

分类函数须要三个參数:决策树。特征列表,待分类数据。特征列表是联系决策树和待分类数据的桥梁,决策树的特征通过特征列表获得其索引,再通过索引訪问待分类数据中该特征的值。

def classify(tree, featLabels, testVec):
firstJudge = tree.keys()[0]
secondDict = tree[firstJudge]
featIndex = featLabels.index(firstJudge) #获得特征索引
for key in secondDict: #进入相应的分类集合
if key == testVec[featIndex]: #按特征分类
if type(secondDict[key]).__name__ == 'dict': #假设分类结果是一个字典,则说明还要继续分类
classLabel = classify(secondDict[key], featLabels, testVec)
else: #分类结果不是字典。则分类结束
classLabel = secondDict[key]
return classLabel

3.4保存或者加载决策树

生成决策树是比較花费时间的,所以决策树生成以后存储起来。等要用的时候直接读取就可以。

def store_tree(tree, fileName): #保存树
import pickle
fw = open(fileName, 'w')
pickle.dump(tree, fw)
fw.close() def grab_tree(fileName): #读取树
import pickle
fr = open(fileName)
return pickle.load(fr)

4.决策树可视化

使用字典的形式表示决策树对于人类来说还是有点抽象,假设能以图像的方式呈现就很方便了。很幸运,matplotlib中有模块能够使决策树可视化。这里就不解说了,直接“拿来使用”。将treePlotter.py复制到我们文件的根文件夹。直接导入treePlotter,然后调用treePlotter.createPlot()函数就可以:

import treePlotter
treePlotter.createPlot(tree)

如上面的决策树可视化后例如以下:

5.使用决策树预測隐形眼镜类型

隐形眼镜数据集包括患者的眼睛状况以及医生推荐的隐形眼镜类型。患者信息有4维,分别表示年龄,视力类型,是否散光,眼睛状况。隐形眼镜类型有3种,各自是软材质,硬材质和不适合带隐形眼镜。

想要把我们编写的脚本应用于别的数据集?没问题,仅仅要改动加载数据集的函数就可以,其它的函数不须要改变,详细例如以下:

#加载数据
def file2matrix():
file = open("lenses.data.txt")
allLines = file.readlines()
row = len(allLines)
dataSet = []
for line in allLines:
line = line.strip()
listFromLine = line.split()
dataSet.append(listFromLine)
labels = ['age', 'prescription', 'astigmatic', 'tear rate'] #年龄,视力类型,是否散光。眼睛状况
return dataSet, labels

生成的决策树可视化后例如以下:

事实上博主还尝试了其它的数据集,只是决策树实在是太复杂了。太大了。密密麻麻根本看不清楚。谁有兴趣能够尝试一下别的数据集。

6.总结

  • 源代码在我的GitHub中。包括了可视化脚本以及数据集
  • MachineLearningAction仓库里面有常见的机器学习算法处理常见数据集的各种实例。欢迎訪问
  • 决策树的长处
    • 决策树易于理解和解释,尤其是可视化后的决策树很直观
    • 决策树分类很快
  • 决策树的缺点
    • easy过拟合
    • 对缺失数据的数据集处理困难
    • 忽略数据集中特征的相互关联
  • 常见的决策树有ID3,C4.5和CART决策树
    • C4.5较之ID3更优。信息增益比能够解决信息增益选取取值较多的特征的问题
    • C4.5决策树生成的过程中有剪枝。能够降低决策树的拟合度
    • C4.5能够处理数值型数据,而ID3仅仅能处理标称型数据
  • 决策树能够应用在贷款发放,约会见面等方面

手把手生成决策树(dicision tree)的更多相关文章

  1. 机器学习算法实践:决策树 (Decision Tree)(转载)

    前言 最近打算系统学习下机器学习的基础算法,避免眼高手低,决定把常用的机器学习基础算法都实现一遍以便加深印象.本文为这系列博客的第一篇,关于决策树(Decision Tree)的算法实现,文中我将对决 ...

  2. 数据挖掘 决策树 Decision tree

    数据挖掘-决策树 Decision tree 目录 数据挖掘-决策树 Decision tree 1. 决策树概述 1.1 决策树介绍 1.1.1 决策树定义 1.1.2 本质 1.1.3 决策树的组 ...

  3. 决策树 Decision Tree

    决策树是一个类似于流程图的树结构:其中,每个内部结点表示在一个属性上的测试,每个分支代表一个属性输出,而每个树叶结点代表类或类分布.树的最顶层是根结点.  决策树的构建 想要构建一个决策树,那么咱们 ...

  4. 用于分类的决策树(Decision Tree)-ID3 C4.5

    决策树(Decision Tree)是一种基本的分类与回归方法(ID3.C4.5和基于 Gini 的 CART 可用于分类,CART还可用于回归).决策树在分类过程中,表示的是基于特征对实例进行划分, ...

  5. (ZT)算法杂货铺——分类算法之决策树(Decision tree)

    https://www.cnblogs.com/leoo2sk/archive/2010/09/19/decision-tree.html 3.1.摘要 在前面两篇文章中,分别介绍和讨论了朴素贝叶斯分 ...

  6. 决策树decision tree原理介绍_python sklearn建模_乳腺癌细胞分类器(推荐AAA)

    sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频) https://study.163.com/course/introduction.htm?courseId=1005269003& ...

  7. 机器学习方法(四):决策树Decision Tree原理与实现技巧

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入. 前面三篇写了线性回归,lass ...

  8. 决策树Decision Tree 及实现

    Decision Tree 及实现 标签: 决策树熵信息增益分类有监督 2014-03-17 12:12 15010人阅读 评论(41) 收藏 举报  分类: Data Mining(25)  Pyt ...

  9. 【转载】决策树Decision Tree学习

    本文转自:http://www.cnblogs.com/v-July-v/archive/2012/05/17/2539023.html 最近在研究规则引擎,需要学习决策树.决策表等算法.发现篇好文对 ...

随机推荐

  1. Dos图像复制成序列

    rem 输入1.png,在当前文件下复制.0000.png--0002.png rem 注:way2是不等待0001.png运行完就開始运行下一个了. rem 假设要等待上一个运行完后,再往下顺弃运行 ...

  2. js36---函数嵌套

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  3. STL中向量vector笔记

    vector的本质是:数组的封装 特点:读取能在常数时间内完成 Vector成员函数 函数 表述 c.assign(beg,end) c.assign(n,elem) 将[beg; end)区间中的数 ...

  4. 读阮一峰《ECMAScript 6 入门》小结

    读阮一峰<ECMAScript 6 入门>小结,http://es6.ruanyifeng.com/ 1. ES6简介 Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转 ...

  5. Codeforces Round #277.5 解题报告

    又熬夜刷了cf,今天比正常多一题.比赛还没完但我知道F过不了了,一个半小时贡献给F还是没过--应该也没人Hack.写写解题报告吧= =. 解题报告例如以下: A题:选择排序直接搞,由于不要求最优交换次 ...

  6. Node.js笔记(九)Nodejs与shell

    众所周知.Nodejs是单进程异步执行的.但不光是单进程,Nodejs也提供了多进程方面的支持 其创始人应该还是比較重视这一块的,最有力的证据就是child_process是Nodejs核心模块之中的 ...

  7. java 之 wait, notify, park, unpark , synchronized, Condition

    1. wait notify /** * 解释: 唤醒一个等待monitor的线程, 如果有多个线程在等待,会唤醒一个. * 一个线程在等待monitor是由Object.wait引起的 * 获取一个 ...

  8. 一些常用JS函数和技巧总结

    1.JS原生函数parseInt(),返回字符串的第一个数字,默认是十进制. 2.!!data.success  //强制转换成布尔类型

  9. node.js服务器核心http和文件读写

    使用htpp给客服端的数据,把数据交给浏览器渲染.利用 http创建服务器,如客户端请求为:127.0.0.1:3000或127.0.0.1:3000/xxx.html时 ,判断www文件夹中,文件  ...

  10. 人工智能计算器AI Calculator 3.3.0 具体破解思路&amp;教程

    人工智能计算器AI Calculator 3.3.0 具体破解思路&教程 [文章标题]:人工智能计算器AI Calculator 3.3.0 具体破解思路&教程 [文章作者]: Eri ...