数据源
不浮出水面可以生存 | 是否有脚蹼 | 是否属于鱼类 |
---|---|---|
是 | 是 | 是 |
是 | 是 | 是 |
是 | 否 | 否 |
否 | 是 | 否 |
否 | 是 | 否 |
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
#以2为底求对数log2(下)prob(上),计算香农熵
shannonEnt-=prob* log(prob,2)
return shannonEnt
在这复习一下信息增益和香农熵的概念
- 熵:集合信息的度量方式。熵越高,混合的数据越多。
下面的代码做一个验证:
myDat, labels = createDataSet()
print(calcShannonEnt(myDat))
print(11111111111111111111111111111111)
myDat[0][-1] = 'maybe'
print(calcShannonEnt(myDat))
print(22222222222222222222222222222222)
#
#0.9287712379549449
#11111111111111111111111111111111
#1.3931568569324173
#22222222222222222222222222222222
#
如果给myDat加一个不同的数据,熵的值更高。
划分数据及
#
# 按照指定特征划分数据集合
# dataset 等待划分的数据集合
# axis 划分数据集的特征
# value 需要返回的的特征的值
#
#返回的是
#
def splitDataSet(dataSet, axis, value):
# ❶ 创建新的list对象
#创建这个list对象的原因是为了不修改原始数据集合,因为splitDataSet函数在同一数据上多次引用
retDataSet=[];
for featVec in dataSet:
if featVec[axis] ==value:
# ❷ (以下三行)抽取
reducedFeatVec = featVec[:axis]
#如果使用a.append(n),[1,2,3,[4,5,6,]];而a.extend(b)==[1,2,3,4,5,6]
reducedFeatVec.extend(featVec[axis + 1:])
retDataSet.append(reducedFeatVec)
return retDataSet
我再做一个验证
myDat, labels = createDataSet()
print(myDat)
print(11111111111111111111111111111111)
r1=splitDataSet(myDat,0,1)
r2=splitDataSet(myDat,0,0)
print(r1)
print(r2)
print(33333333333333333333333333333333333333333333333333333)
#
#[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
#11111111111111111111111111111111
#[[1, 'yes'], [1, 'yes'], [0, 'no']]
#[[1, 'no'], [1, 'no']]
#33333333333333333333333333333333333333333333333333333
#
可以先理解为将数据源的第一项进行了区分,将1,0的值进行了返回。
获取最佳的数据划分方式
#
# 选取特征,划分数据集合,计算出最好的划分数据集特征
#要求:
# 1,数据必须是一种由列表元素组成的列表,而且所有列表元素都具有相同的数据长度
# 2,数据的最后一列,或者每个实例最后一个元祖是当前实例的类别的标签
#
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1
#计算了整个数据集的原始香农熵,保存最初的无序度量值,用于与划分完之后的数据集计算的熵值进行比较。
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0; bestFeature = -1
#第一个for循环遍历了所有特征
for i in range(numFeatures):
#❶ (以下两行)创建唯一的分类标签列表,
#创建新的列表,将数据集中所有第i个特征值写入这个新列表
featList = [example[i] for example in dataSet]
uniqueVals = set(featList)
newEntropy = 0.0
#❷ (以下五行)计算每种划分方式的信息熵
#遍历当前特征中的唯一属性值,对每一个特征划分一次数据集2
for value in uniqueVals:
subDataSet = splitDataSet(dataSet, i, value)
#len计算元素个数
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy
#信息增益是熵的减少或者数据无须度的减少
if (infoGain > bestInfoGain):
#❸ 计算最好的信息增益
bestInfoGain = infoGain
bestFeature = i
return bestFeature
## set 是集合数据类型,从列表中从创建集合是python语言中得到列表中唯一元素值的最快方法
遍历当前特征中的唯一属性值,对每个特征划分一次数据集合,计算这个集合的熵,比较信息增益(即熵的减少),返回最好的索引值。
myDat, labels = trees.createDataSet()
print(chooseBestFeatureToSplit(myDat))
上述代码返回的是0,也就是说明这是最好用于划分数据集合的特征。