声明:本文根据李航博士的《统计学校方法》中的决策树章节的原理:最大熵信息增益、信息增益比进行决策树的实现。在可视化方面主要参考的这篇博文。
决策树算法是一类在数据挖掘中应用的特别多的符号学派分类器,并在集成学习中被大大采用。经典的c4.5和id3以及后来的cart是了解诸如GBDT等集成学校算法的基础,因此笔者尝试自己实现一次(重复造轮子)。
model
决策树的定义:
strategy
决策数学习的关键就是特征选择。特征选择主要就在熵的计算和选择信息增益最大的特征。
熵的定义:
信息增益的定义为:
algorithm
算法的python实现:
def calcShannonEnt(dataSet):
"""
计算训练数据集中的Y随机变量的香农熵
:param dataSet:
:return:
"""
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) # log base 2
return shannonEnt
def calcConditionalEntropy(dataSet, i, featList, uniqueVals):
'''
计算X_i给定的条件下,Y的条件熵
:param dataSet:数据集
:param i:维度i
:param featList: 数据集特征列表
:param uniqueVals: 数据集特征集合
:return:条件熵
'''
ce = 0.0
for value in uniqueVals:
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet) / float(len(dataSet)) # 极大似然估计概率
ce += prob * calcShannonEnt(subDataSet) # ∑pH(Y|X=xi) 条件熵的计算
return ce
def calcInformationGain(dataSet, baseEntropy, i):
"""
计算信息增益
:param dataSet:数据集
:param baseEntropy:数据集中Y的信息熵
:param i: 特征维度i
:return: 特征i对数据集的信息增益g(dataSet|X_i)
"""
featList = [example[i] for example in dataSet] # 第i维特征列表
uniqueVals = set(featList) # 转换成集合
newEntropy = calcConditionalEntropy(dataSet, i, featList, uniqueVals)
infoGain = baseEntropy - newEntropy # 信息增益,就是熵的减少,也就是不确定性的减少
return infoGain
def calcInformationGainRate(dataSet, baseEntropy, i):
"""
计算信息增益比
:param dataSet:数据集
:param baseEntropy:数据集中Y的信息熵
:param i: 特征维度i
:return: 特征i对数据集的信息增益g(dataSet|X_i)
"""
return calcInformationGain(dataSet, baseEntropy, i) / baseEntropy
ID3算法是实现:
def chooseBestFeatureToSplitByID3(dataSet):
"""
选择最好的数据集划分方式
:param dataSet:
:return:
"""
numFeatures = len(dataSet[0]) - 1 # 最后一列是分类
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeatures): # 遍历所有维度特征
infoGain = calcInformationGain(dataSet, baseEntropy, i)
if (infoGain > bestInfoGain): # 选择最大的信息增益
bestInfoGain = infoGain
bestFeature = i
return bestFeature # 返回最佳特征对应的维度
创建书上的数据样本:
代码:
def createDataSet():
"""
创建数据集
:return:
"""
dataSet = [[u'青年', u'否', u'否', u'一般', u'拒绝'],
[u'青年', u'否', u'否', u'好', u'拒绝'],
[u'青年', u'是', u'否', u'好', u'同意'],
[u'青年', u'是', u'是', u'一般', u'同意'],
[u'青年', u'否', u'否', u'一般', u'拒绝'],
[u'中年', u'否', u'否', u'一般', u'拒绝'],
[u'中年', u'否', u'否', u'好', u'拒绝'],
[u'中年', u'是', u'是', u'好', u'同意'],
[u'中年', u'否', u'是', u'非常好', u'同意'],
[u'中年', u'否', u'是', u'非常好', u'同意'],
[u'老年', u'否', u'是', u'非常好', u'同意'],
[u'老年', u'否', u'是', u'好', u'同意'],
[u'老年', u'是', u'否', u'好', u'同意'],
[u'老年', u'是', u'否', u'非常好', u'同意'],
[u'老年', u'否', u'否', u'一般', u'拒绝'],
]
labels = [u'年龄', u'有工作', u'有房子', u'信贷情况']
# 返回数据集和每个维度的名称
return dataSet, labels
调用ID3算法
import sys
from tree import *
reload(sys)
sys.setdefaultencoding('utf-8')
# 测试决策树的构建
myDat, labels = createDataSet()
myTree = createTree(myDat, labels)
对于C4.5算法,则是将ID3中的信息增益比换为信息增益。因此就不再重复了。