'''
Created on Oct 12, 2010
Decision Tree Source Code for Machine Learning in Action Ch. 3
@author: Peter Harrington
'''
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] #遍历数据集合中的最后一列(类别),如果该类别不在字典中,加入字典,如果已经在字典中计数加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): #划分数据集合 axis为特征,value为特征对应的特征值
retDataSet = []
for featVec in dataSet: #遍历数据集合中的每一行,也就是一个样本
if featVec[axis] == value: #选取参数所选定的样本
reducedFeatVec = featVec[:axis] #重新组织划分后的样本,样本中每一个行由 axis为特征,value为特征对应的特征值选定不包括该特征
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet #返回划分后的数据集
def chooseBestFeatureToSplit(dataSet): #根据ID3算法选择最佳特征进行分割
numFeatures = len(dataSet[0]) - 1 #计算一共有多少个特征,保存到numFeatures
baseEntropy = calcShannonEnt(dataSet) #计算总样本集合的熵
bestInfoGain = 0.0; bestFeature = -1
for i in range(numFeatures): #迭代所有的特征,在一次for循环之内,遍历一个特征所对应的值,并统计每个特征值对应样本的数量
featList = [example[i] for example in dataSet] #第i个特征,在整个数据集合内对应的特征值取值放进featList中
uniqueVals = set(featList) #得带第i特征,所有可能的取值情况,set(featList)消除掉featlist中的重复的元素
newEntropy = 0.0
for value in uniqueVals:
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet)) #计算第i个特征,取特征值value的个数在整个数据集合中的概率
newEntropy += prob * calcShannonEnt(subDataSet) #循环n次把对用的值相加,计算出条件熵
infoGain = baseEntropy - newEntropy #信息增益=数据集合的熵-条件熵
if (infoGain > bestInfoGain): #统计出信息增益最大的特征值,并把该特征i作为bestFeature返回
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), reverse=True)
return sortedClassCount[0][0]
def createTree(dataSet,labels): #创建决策树
classList = [example[-1] for example in dataSet] #把整个数据集合中的最后一列(类别)放进一个List
if classList.count(classList[0]) == len(classList): #如果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 = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
key = testVec[featIndex]
valueOfFeat = secondDict[key]
if isinstance(valueOfFeat, dict):
classLabel = classify(valueOfFeat, featLabels, testVec)
else: classLabel = valueOfFeat
return classLabel
def storeTree(inputTree,filename):
import pickle
fw = open(filename,'w')
pickle.dump(inputTree,fw)
fw.close()
def grabTree(filename):
import pickle
fr = open(filename)
return pickle.load(fr)
《机器学习实战》决策树代码详解
最新推荐文章于 2024-03-26 15:47:14 发布