第一章 决策树
1.1 ID3决策树
1.1.1 Python实现ID3决策树
1. 加载数据集与计算信息熵
代码如下:
import numpy as np
import pandas as pd
#定义加载数据集的综合函数
def loadDataSet():
#函数功能:读取存放样本数据的csv文件,返回样本数据集和划分属性集
#对数据进行处理
dataSet = pd.read_csv('/Users/yanhe/Desktop/loan.csv', delimiter=',')
dataSet = dataSet.replace('yes', 1).replace('no', 0)
labelSet = list(dataSet.columns)[:-1] #得到划分属性集
dataSet = dataSet.values #得到样本数据集
return dataSet, labelSet
#下面定义计算给定样本数据集dataSet的信息熵的函数calcShannonEnt(dataSet)。
def calcShannonEnt(dataSet):
#dataSet的每个元素是一个存放样本的属性值的列表
numEntries = len(dataSet) #获取样本集的行数,
labelCounts = {} #保存每个类别出现次数的字典
for featVec in dataSet: #对每个样本进行统计
currentLabel = featVec[-1] #取得最后一列数据,即类别信息
# 如果当前类别没有放入统计次数的字典,添加进去
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0 #添加字典元素,键的值为0
labelCounts[currentLabel] += 1 #类别数计数
shannonEnt = 0.0 #计算信息熵
for key in labelCounts.keys():
#keys()以列表返回一个字典所有的键
prob = float(labelCounts[key]) / numEntries #计算一个类别的概率
shannonEnt -= prob*np.log2(prob)
return shannonEnt
#main函数
if __name__=='__main__':
dataSet, labelSet = loadDataSet()
print(dataSet)
print('数据集的信息熵:',calcShannonEnt(dataSet))
输出结果如下:
2. 计算信息增益
代码如下:
#定义按照给定特征划分数据集的函数
def splitDataSet(dataSet,axis,value):
# dataSet为待划分的数据集,axis为划分数据集的特征,value划分特征的某个值
retDataSet=[]
for featVec in dataSet: #dataSet的每个元素是一个样本,以列表表示
#将相同特征值value的样本提取出来
if featVec[axis]==value:
reducedFeatVec=list(featVec[:axis])
#extend()在列表list末尾一次性追加序列中的所有元素
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet #返回不含划分特征的子集
#定义按照最大信息增益划分数据集的函数
def chooseBestFeatureToSplit(dataSet):
#为数据集选择最优的划分属性
numofFeatures = len(dataSet[0])-1 #获取划分属性的个数
baseEntroy = calcShannonEnt(dataSet) #计算数据集的信息熵
bestInfoGain = 0.0 #信息增益
bestFeature = -1 #最优划分属性的索引值
for i in range(numofFeatures): #遍历所有划分属性,这里划分属性用数字表示
#获取dataSet的第i个特征下所有值
featureList = [example[i] for example in dataSet]
uniqueVals = set(featureList) #创建set集合{},目的去除重复值
newEntropy = 0.0
for value in uniqueVals: #计算划分属性划分数据集的熵
#subDataSet划分后的子集
subDataSet = splitDataSet(dataSet, i, value)
#计算子集的概率
prob = len(subDataSet) / float(len(dataSet))
#根据公式计算属性划分数据集的熵
newEntropy += prob *calcShannonEnt(subDataSet)
inforGain = baseEntroy - newEntropy #计算信息增益
#打印每个划分属性的信息增益
print("第%d个划分属性的信息增益为%.3f" % (i, inforGain))
#获取最大信息增益
if (inforGain > bestInfoGain):
bestInfoGain = inforGain #更新信息增益,找到最大的信息增益
bestFeature = i #记录信息增益最大的特征的索引值
return bestFeature #返回信息增益最大特征的索引值
#main函数
if __name__=='__main__':
dataSet, labelSet=loadDataSet()
print("最优索引值:"+str(chooseBestFeatureToSplit(dataSet)))
输出结果如下:
第0个划分属性的信息增益为0.083
第1个划分属性的信息增益为0.324
第2个划分属性的信息增益为0.420
第3个划分属性的信息增益为0.363
最优索引值:2
3.决策树的构建
代码如下:
def majorityCnt(classList):
"""
函数功能:统计classList中出现次数最多的元素(类标签)
参数classList: 类别列表
return sortedClassCount[0][0]: 返回出现次数最多的类别
"""
classCount = {}
for vote in classList:
#统计classList中每个元素出现的次数
if vote not in classCount.keys():
classCount[vote] = 0
classCount += 1
# 根据字典的值降序排列,items()返回字典的键值对所组成的(键, 值)元组列表
sortedClassCount = sorted(classCount.items(), key=lambda x:x[1], reverse=True)
# 返回出现次数最多的类别
return sortedClassCount[0][0]
def createTree(dataSet, labels):
"""
函数功能:构造决策树
参数dataSet:训练数据集
参数labels:划分属性集
return myTree: 返回决策树
"""
classList = [example[-1] for example in dataSet] #取分类标签(是否放贷:yes or no)
# 当类别与属性完全相同,则停止继续划分
if classList.count(classList[-1]) == len(classList):
return classList[-1]
# 遍历完所有特征时返回出现次数最多的类标签
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
#main函数
if __name__ =