提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、什么是决策树?
所谓决策树,顾名思义,是一种树,一种依托于策略抉择而建立起来的树。机器学习中,决策树是一个预测模型;它代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表的是某个可能的属性值,而每个叶子节点则对应根节点到该叶子节点所经历的路径所表示的对象的值。决策树仅有单一输出,若欲有复数输出,可以建立独立的决策树以处理不同的输出。
二、ID3算法
1.算法介绍
ID3(Iterative Dichotomiser 3)是一种经典的决策树算法,用于解决分类问题。它是由Ross Quinlan在1986年提出的。
ID3算法通过选择最佳的特征来构建决策树。在每个节点上,ID3根据信息增益(Information Gain)来评估特征的重要性。信息增益衡量了特征在划分数据集后对于减少不确定性的贡献程度。
2.原理
ID3算法以信息论为基础,其核心是“信息熵”。ID3算法通过计算每个属性的信息增益,认为信息增益高的是好属性,每次划分选取信息增益最高的属性为划分标准,重复这个过程,直至生成一个能完美分类训练样例的决策树。
1.信息熵(Information Entropy)
熵度量了信息的不确定性,事物的不确定性越大,它的熵越高。 表达式如下:
H(x)=−∑ni=1p(xi)log2p(xi)
其中,p(xi)
表示xi
出现的概率,n表示x的不同取值
2.条件熵(Conditional Entropy)
条件熵类似于条件概率,它度量了X在知道Y以后剩下的不确定性,表达式如下 :
H(X|Y)=∑ni=1p(yi)H(X|yi)=−∑ni=1p(yi)∑mj=1p(xj|yi
log p\left ( x_{j}|y_{i}\right ))
特征Y取值为yj,
3.信息增益(Information Gain)
它度量了X在知道Y以后不确定性减少程度,信息论中称作互信息(Mutual Information),记为I(X;Y)。
I(X;Y)=H(x)−H(X|Y)=H(x)−∑t∈Tp(t)H(t)
t表示划分之后的分支集合,p(t)表示该分支集合在原本的父集合中出现的概率,H(t)表示该子集合的信息熵
3.python代码实现**
# -*- coding: utf-8 -*-
__author__ = 'Wsine'
from math import log
import operator
import treePlotter
def calcShannonEnt(dataSet):
"""
输入:数据集
输出:数据集的香农熵
描述:计算给定数据集的香农熵
"""
numEntries = len(dataSet)
labelCounts = {}
for featVec in dataSet:
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries
shannonEnt -= prob * log(prob, 2)
return shannonEnt
def splitDataSet(dataSet, axis, value):
"""
输入:数据集,选择维度,选择值
输出:划分数据集
描述:按照给定特征划分数据集;去除选择维度中等于选择值的项
"""
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
reduceFeatVec = featVec[:axis]
reduceFeatVec.extend(featVec[axis+1:])
retDataSet.append(reduceFeatVec)
return retDataSet
def chooseBestFeatureToSplit(dataSet):
"""
输入:数据集
输出:最好的划分维度
描述:选择最好的数据集划分维度
"""
numFeatures = len(dataSet[0]) - 1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeatures):
featList = [example[i] for example in dataSet]
uniqueVals = set(featList)
newEntropy = 0.0
for value in uniqueVals:
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy
if (infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature
def majorityCnt(classList):
"""
输入:分类类别列表
输出:子节点的分类
描述:数据集已经处理了所有属性,但是类标签依然不是唯一的,
采用多数判决的方法决定该子节点的分类
"""
classCount = {}
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reversed=True)
return sortedClassCount[0][0]
def createTree(dataSet, labels):
"""
输入:数据集,特征标签
输出:决策树
描述:递归构建决策树,利用上述的函数
"""
classList = [example[-1] for example in dataSet]
if classList.count(classList[0]) == len(classList):
# 类别完全相同,停止划分
return classList[0]
if len(dataSet[0]) == 1:
# 遍历完所有特征时返回出现次数最多的
return majorityCnt(classList)
bestFeat = chooseBestFeatureToSplit(dataSet)
bestFeatLabel = labels[bestFeat]
myTree = {bestFeatLabel:{}}
del(labels[bestFeat])
# 得到列表包括节点所有的属性值
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels[:]
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
return myTree
def classify(inputTree, featLabels, testVec):
"""
输入:决策树,分类标签,测试数据
输出:决策结果
描述:跑决策树
"""
firstStr = list(inputTree.keys())[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
for key in secondDict.keys():
if testVec[featIndex] == key:
if type(secondDict[key]).__name__ == 'dict':
classLabel = classify(secondDict[key], featLabels, testVec)
else:
classLabel = secondDict[key]
return classLabel
def classifyAll(inputTree, featLabels, testDataSet):
"""
输入:决策树,分类标签,测试数据集
输出:决策结果
描述:跑决策树
"""
classLabelAll = []
for testVec in testDataSet:
classLabelAll.append(classify(inputTree, featLabels, testVec))
return classLabelAll
def storeTree(inputTree, filename):
"""
输入:决策树,保存文件路径
输出:
描述:保存决策树到文件
"""
import pickle
fw = open(filename, 'wb')
pickle.dump(inputTree, fw)
fw.close()
def grabTree(filename):
"""
输入:文件路径名
输出:决策树
描述:从文件读取决策树
"""
import pickle
fr = open(filename, 'rb')
return pickle.load(fr)
def createDataSet():
"""
outlook-> 0: sunny | 1: overcast | 2: rain
temperature-> 0: hot | 1: mild | 2: cool
humidity-> 0: high | 1: normal
windy-> 0: false | 1: true
"""
dataSet = [[0, 0, 0, 0, 'N'],
[0, 0, 0, 1, 'N'],
[1, 0, 0, 0, 'Y'],
[2, 1, 0, 0, 'Y'],
[2, 2, 1, 0, 'Y'],
[2, 2, 1, 1, 'N'],
[1, 2, 1, 1, 'Y']]
labels = ['outlook', 'temperature', 'humidity', 'windy']
return dataSet, labels
def createTestSet():
testSet = [[0, 1, 0, 0],
[0, 2, 1, 0],
[2, 1, 1, 0],
[0, 1, 1, 1],
[1, 1, 0, 1],
[1, 0, 1, 0],
[2, 1, 0, 1]]
return testSet
def main():
dataSet, labels = createDataSet()
labels_tmp = labels[:]
desicionTree = createTree(dataSet, labels_tmp)
print('desicionTree:\n', desicionTree)
treePlotter.createPlot(desicionTree)
testSet = createTestSet()
print('classifyResult:\n', classifyAll(desicionTree, labels, testSet))
if __name__ == '__main__':
main()
运行结果如下:
二、C4.5算法
1.算法介绍
C4.5算法与ID3类似,C4.5算法对ID3算法进行了改进,C4.5在生产的过程中,用信息增益比来选择特征。
2.代码实现
C4.5使用信息增益比作为特征选择的度量,与ID3相比较,没有差多少,就是把信息增益改成信息增益率,即在ID3算法基础上,根据信息增益的公式修改 chooseBestFeatureToSplit() 函数
def chooseBestFeatureToSplit2(dataSet):
"""
输入:数据集
输出:最好的划分维度
描述:选择最好的数据集划分维度
"""
numFeatures = len(dataSet[0]) - 1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGainRatio = 0.0
bestFeature = -1
for i in range(numFeatures):
featList = [example[i] for example in dataSet]
uniqueVals = set(featList)
newEntropy = 0.0
splitInfo = 0.0
for value in uniqueVals:
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
splitInfo += -prob * log(prob, 2)
infoGain = baseEntropy - newEntropy
if (splitInfo == 0): # fix the overflow bug
continue
infoGainRatio = infoGain / splitInfo
if (infoGainRatio > bestInfoGainRatio):
bestInfoGainRatio = infoGainRatio
bestFeature = i
return bestFeature
4.ID3与C4.5对比
ID3算法:
ID3算法核心就是“最大信息熵增益” 原则选择划分当前数据集的最好特征。
而且对于连续型特征,比如长度,密度都是连续值,无法在ID3运用,因为一开始我用的鸢尾花实例数据,ID3不能判断连续型量。
前面也说到了,利用信息熵划分属性,会对倾向于可取值数目较多的属性。 没有考虑过拟合的问题。
C4.5算法:
C4.5算法流程与ID3算法相类似,只不过将信息增益改为信息增益率,以解决偏向取值较多的属性的问题。
可以处理属性变量为连续型的,将连续的特征离散化。
5.决策树优缺点
优点:
1.易于理解和解释。由于决策树模型基于树形结构,因此可以直观地展示特征属性之间的关系,易于解释。
2.适用于多种类型的数据。决策树模型可以处理分类、回归等不同类型的数据。
3.能够处理非线性关系。与线性模型不同,决策树模型可以处理非线性关系,适用于复杂的问题。
缺点:
1.容易过拟合。当决策树过于复杂时,容易出现过拟合现象,影响模型的泛化能力。
2.对噪声敏感。样本数据中存在异常值或噪声时,会影响决策树的划分效果。
3.不稳定。当样本数据发生变化时,决策树模型可能会发生较大的变化,导致模型不稳定。