决策树是一种基于树形结构来进行决策的算法,它可以被用来解决分类和回归问题。决策树通过一系列的判断来对于输入的数据进行分类或者预测。
它的构建过程通常会基于数据集中的各种属性和属性值来设置各种不同的分支和叶子节点。通过比对输入数据集和决策树的各种分支和叶子节点之间的差异性,决策树能够得出最终的分类或预测结果。
决策树算法相对来说比较容易理解和实现,非常适合处理一些较小的数据集。但如果数据集过于庞大,建模过程就会变得非常耗时和昂贵。但决策树也比较容易出现过拟合的问题。
海洋动物分类
不浮出水面是否可以生存(no surfacing) | 是否有脚蹼(flippers) | 属于鱼类 | |
---|---|---|---|
1 | 是 | 是 | 是 |
2 | 是 | 是 | 是 |
3 | 是 | 否 | 否 |
4 | 否 | 是 | 否 |
5 | 否 | 是 | 否 |
学习如何计算信息增益来划分数据集,集合信息的度量方式称为香农熵或简称为熵(Entropy)。
如果待分类的事务可能划分在多个分类之中,则熵的计算公式为
H(X)表示随机变量X的熵,pi表示X取第i个取值的概率,n表示X可能取值的总数。
具体代码复现
from math import log
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)
return shannonEnt
该函数用于计算熵,是上诉公式的代码实现
def creatDataset():
dataset = [[1,1,'yes'],
[1,1,'yes'],
[1,0,'no'],
[0,1,'no'],
[0,1,'no']]
labels = ['no surfacing','flippers']
return dataset,labels
创建数据集
def splitDataset(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:
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
通过计算信息增益来选择最好的数据集划分方式,本次使用的数据集有两个特征值,通过与原始数据集的熵做差来进行对比。
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[:]
myTree[bestFeatLabel][value]= createTree(splitDataset(dataset,bestFeat,value),subLabels)
return myTree
以上是树的递归创建过程,当所有类的标签完全相同时,则直接返回该类标签;或是使用完所有特征仍然不能将数据集划分成仅包含唯一类别的分组。
def classify(inputTree,featLabels,testVec):
firstStr = list(inputTree.keys())[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.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
最后使用决策树的分类函数,分类结果如下