博客有没保存,记性差到已经忘了写了什么。
python相关知识
pikcle:
通过序列号实现持久化,在计算的时候可以把树进行持久化。
相关文章:https://www.cnblogs.com/tkqasn/p/6005025.html
# pickle:暂时持久化的set 与 get
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)
测试
分类器
#
# inputTree 树
# featLabels 显示的种类
# testVec ,就是判断的依据
#
def classify(inputTree, featLabels, testVec):
# 获取第一个标签字符串
firstStr = list(inputTree.keys())[0]
# 根据标签字符串取得该标签下的树的数据数据
secondDict = inputTree[firstStr]
# ❶将标签字符串转换为索引
featIndex = featLabels.index(firstStr)
# 遍历改标签下树的key
for key in secondDict.keys():
# 如果testVec[索引]==key的时候,说明得到判断的依据,例子为0,1
if testVec[featIndex] == key:
if type(secondDict[key]).__name__ == 'dict':
classLabel = classify(secondDict[key], featLabels, testVec)
else:
classLabel = secondDict[key]
# 最后的classLabel就是判断依据的key 得到的值
return classLabel
#打开文件
fr=open('lenses.txt')
#获得lenses的矩阵,即之前使用的myDat
lenses=[inst.strip().split('\t') for inst in fr.readlines()]
print(lenses)
#获得lenses的矩阵,即之前使用的labels
lensesLabels = [ 'tearRate','age', 'prescript', 'astigmatic']
lensesTree =createTree(lenses, lensesLabels)
print(lensesTree)
#创建
createPlot(lensesTree)
运行后得到了错误的结果。
关于这个错,如何定位就成了问题。
1,我先对比了lenses和tree在正确版本和我做的版本中的区别,结果发现原始数据的结果一样,tree出现了问题。
那只能回到createTree中去看看了,追踪一下错误
错误1:def calcShannonEnt(dataSet)
for featVec in dataSet:
# 创建一个数据字典,它的键值是最后一列的数
currentLabel = featVec[-1]
# 如果当前键值不存在,则扩展字典并将当前键值加入字典
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
正确的代码应该是,当前分类,也就是结果在labelCounts中不存在添加,如果存在将+1,
最后得到应该是这个分类和出现个数的键值,如下:
{‘no lenses’: 15, ‘soft’: 5, ‘hard’: 4}
for featVec in dataSet:
# 创建一个数据字典,它的键值是最后一列的数
currentLabel = featVec[-1]
# 如果当前键值不存在,则扩展字典并将当前键值加入字典
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
错误1:def hooseBestFeatureToSplit(dataSet):
根据数据集合选择组好的分类特征
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1
# 计算了整个数据集的原始香农熵,保存最初的无序度量值,用于与划分完之后的数据集计算的熵值进行比较。
baseEntropy = calcShannonEnt(dataSet)
print(baseEntropy)
bestInfoGain = 0.0;
bestFeature = -1
# 第一个for循环遍历了所有特征
for i in range(numFeatures):
# ❶ (以下两行)创建唯一的分类标签列表,
# 创建新的列表,将数据集中所有第i个特征值写入这个新列表
# 获得所有数据第i个特征组成给一个列表,在uniquevals进行去重
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
# 信息增益是熵的减少或者数据无须度的减少,所以infoGain越大说明新的enwEntropy越小,数据越好。
if (infoGain > bestInfoGain):
# ❸ 计算最好的信息增益
bestInfoGain = infoGain
bestFeature = i
return bestFeature
正确的代码应该是
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1
# 计算了整个数据集的原始香农熵,保存最初的无序度量值,用于与划分完之后的数据集计算的熵值进行比较。
baseEntropy = calcShannonEnt(dataSet)
print(baseEntropy)
bestInfoGain = 0.0;
bestFeature = -1
# 第一个for循环遍历了所有特征
for i in range(numFeatures):
# ❶ (以下两行)创建唯一的分类标签列表,
# 创建新的列表,将数据集中所有第i个特征值写入这个新列表
# 获得所有数据第i个特征组成给一个列表,在uniquevals进行去重
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
# 信息增益是熵的减少或者数据无须度的减少,所以infoGain越大说明新的enwEntropy越小,数据越好。
if (infoGain > bestInfoGain):
# ❸ 计算最好的信息增益
bestInfoGain = infoGain
bestFeature = i
return bestFeature
这个地方再次出现了缩进问题,通过这个特征(i是他的index),求出的各个子集的新的熵值,熵越小说明数据越整合,也就是说infoGain越大越好。这样我们抽出最好的特征来逐层级判断。
结果如下:
看起来这棵树好多了。