决策树分类器基础代码
注:先提交代码和各行代码的解释,后续完善。参照机器学习实战教材
from math import log
import operator
def createDataSet(): #创建鉴定数据集
dataSet = [[1, 1, 'yes'],
[1, 1, 'yes'],
[1, 0, 'no'],
[0, 1, 'no'],
[0, 1, 'no']]
labels = ['no surfacing','flippers']
return dataSet, labels
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) #log base 2
return shannonEnt #自定义函数返回信息熵
def splitDateSet(dataSet,axis,value):#实现数据集划分,参数:待划分数据集、划分数据集的特征、特征值的返回值
retDataSet=[]#空列表
for featVec in dataSet:#
if featVec[axis]==value:#判断特征值等于特征的返回值
reducedFeatVec=featVec[:axis]#截图某特征之前的特征数据
reducedFeatVec.extend(featVec[axis+1:])#拼接某特征值之后的特征数据,构成新数据
retDataSet.append(reducedFeatVec) #数据集中满足特征值等于特征的返回值的样本
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: #依次遍历某特征的某个值
subDateSet=splitDateSet(dataset,i,value)# 对当前特征的每个特征划分一次数据集
prob=len(subDateSet)/float(len(dataset))# 计算每种划分的信息熵公式
newEntropy +=prob*calcShannonEnt(subDateSet)# 计算每种划分的信息熵公式
infoGain=baseEntropy-newEntropy # 计算每种划分方式的信息增益
if (infoGain>bestInfoGain): #计算最好的信息增益
bestInfoGain=infoGain
bestFeature=i
return bestFeature #返回最好特征划分的索引值
#test=chooseBestFeatureToSplit(dataset)#求得数据集最好的特征划分的索引值
def majorityCnt(classList):#该函数使用分类名称的列表,然后创建键值为classList中唯一值的数据字典,
#字典对象存储了classList中每个类表现出现的次数,并利用operator操作键值排序字典,并返回次数最多的分类名称。
classCount={}
for vote in classList:
if vote not in classCount.keys():classCount[vote]=0
classCount[vote]+=1
sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
def creatTree(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:{}}#得到的返回值插入到字典变量myTree中
del(labels[bestFeat])#对属性标签依次删除已经插入到字典的特征
featValues=[example[bestFeat] for example in dataset]#得到当前用来划分的特征的所有属性值
uniqueVals=set(featValues)#对当前特征的所有属性值去重,得到唯一值
for value in uniqueVals: #遍历当前特征的所有属性的唯一值
subLabels=labels[:]#复制了类标签,并将其储存在新列表变量中,确保不修改原始列表内容
myTree[bestFeatLabel][value]=creatTree(splitDateSet(dataset,bestFeat,value),subLabels)
return myTree
dataset, labels=createDataSet() #得到待划分的数据集和特征
test=creatTree(dataset,labels)#完成决策树的嵌套字典