2. 代码实现

2.1 计算熵

```from math import log

# 计算给定数据集的熵
def calcShannonEnt(dataSet):
numEntries = len(dataSet)
labelCounts = {}
for featVec in dataSet: #the the number of unique elements and their occurance
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 createDataSet():
dataSet = [[1, 1, 'yes'],
[1, 1, 'yes'],
[1, 0, 'no'],
[0, 1, 'no'],
[0, 1, 'no']]
labels = ['no surfacing','flippers']
#change to discrete values
return dataSet, labels

myDat,labels = createDataSet()
print 'myDat:',myDat
print 'entropy_myDat:',calcShannonEnt(myDat)```

```myDat: [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
entropy_myDat: 0.970950594455```

2.2 分裂数据集

```# 根据指定的特征来分裂数据集
# dataSet:数据集（MxN），axis：特征的索引，即第几个特征：，value：所选特征的取值
# 返回一个数据集，该数据集以axis索引表示的特征为分裂特征，并且该分裂特征的值为value时得到的。
def splitDataSet(dataSet, axis, value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis]     #chop out axis used for splitting
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet```

```print '以第0个特征为分裂特征进行分裂数据集，'
print '分裂特征值为1的子集合：',splitDataSet(myDat,0,1)
print '分裂特征值为0的子集合：',splitDataSet(myDat,0,0)```

```以第0个特征为分裂特征进行分裂数据集，

```# 返回分裂特征的索引
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1# 数据集中元素的最后一列为类别标签，所以需减1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0;bestFeature = -1# 初始化

for i in range(numFeatures):
featList = [element[i] for element in dataSet]# 得到数据集中第i个特征的所有取值
uniqueVals = set(featList)# 对featList去重,得到第i个特征的特征值集合
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```

1)数据必须是由列表元素组成的列表，且所有的列表元素都必须具有相同的数据长度

2)数据的最后一列或者每个实例的最后一个元素是当前实例的类别标签。

`print '分裂特征的索引为：',chooseBestFeatureToSplit(myDat)`

```print '分裂特征的索引为：',chooseBestFeatureToSplit(myDat)

```

2.3 递归构建决策树

```import operator

#多数表决
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]
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[:]   #copy all of labels, so trees don't mess up existing labels
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
return myTree ```

```myTree= createTree(myDat,labels)
print myTree```

`{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}`

2.4 使用决策树进行分类

```#使用决策树执行分类
def classify(inputTree, featLabels, testVec):
firstStr = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)   #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 ```

```myDat,labels = createDataSet()
print 'myTree:',myTree
print 'labels:',labels
print classify(myTree,labels,[1,0])
print classify(myTree,labels,[1,1])```

classify也可以这么实现：

```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```

2.5  存储决策树

```#决策树的存储
def storeTree(inputTree,filename):
import pickle
fw = open(filename,'w')
pickle.dump(inputTree,fw)
fw.close()

def grabTree(filename):
import pickle
fr = open(filename)
```storeTree(myTree,'mytree.txt')
`{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}`