- 树以代表训练样本的单个结点开始(步骤1)。
- 如果样本都在同一个类,则该结点成为树叶,并用该类标号(步骤2 和3)。
- 否则,算法使用称为信息增益的基于熵的度量作为启发信息,选择能够最好地将样本分类的属性(步骤6)。该属性成为该结点的“测试”或“判定”属性(步骤7)。在算法的该版本中,
- 所有的属性都是分类的,即离散值。连续属性必须离散化。
- 对测试属性的每个已知的值,创建一个分枝,并据此划分样本(步骤8-10)。
- 算法使用同样的过程,递归地形成每个划分上的样本判定树。一旦一个属性出现在一个结点上,就不必该结点的任何后代上考虑它(步骤13)。
- 递归划分步骤仅当下列条件之一成立停止:
- (a) 给定结点的所有样本属于同一类(步骤2 和3)。
- (b) 没有剩余属性可以用来进一步划分样本(步骤4)。在此情况下,使用多数表决(步骤5)。
- 这涉及将给定的结点转换成树叶,并用样本中的多数所在的类标记它。替换地,可以存放结
- 点样本的类分布。
- © 分枝
- test_attribute = a i 没有样本(步骤11)。在这种情况下,以 samples 中的多数类
- 创建一个树叶(步骤12)
# coding=utf-8
# 导入模块
from math import log
import operator
# 创建简单数据集
def createDataSet():
dataSet = [[1, 1, 0, 'fight'], [1, 0, 1, 'fight'], [1, 0, 1, 'fight'],
[1, 0, 1, 'fight'], [0, 0, 1, 'run'], [0, 1, 0, 'fight'],
[0, 1, 1, 'run']]
lables = ['weapon', 'bullet', 'blood']
return dataSet, lables
# 计算数据集的信息熵
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 # 当前标签实例数+1
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key]) / numEntries
shannonEnt -= prob * log(prob, 2) # 计算信息熵
return shannonEnt
# 划分属性,获得去掉axis位置的属性value剩下的样本
def splitDataSet(dataSet, axis, value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
reduceFeatVec = featVec[:axis]
# extend()方法接受一个列表作为参数,并将该参数的每个元素都添加到原有的列表中
reduceFeatVec.extend(featVec[axis + 1:])
# append()方法向列表的尾部添加一个新的元素,只接受一个参数。
retDataSet.append(reduceFeatVec)
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
# 计算最大所属类别
def mahorityCnt(classList):
classCount = {}
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1
sortedClassCount = sorted(classCount.items(), key=operator.getitem(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 mahorityCnt(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
data, label = createDataSet()
myTree = createTree(data, label)
print(myTree)
运行结果
运行结果示意图