使用決策樹預測隱形眼鏡類型
說明:
將數據集文件 ‘lenses.txt’ 放在當前文件夾
from math import log
import operator
熵的定義
"""
這部分是在用代碼計算香農熵公式,即用代碼寫公式並計算結果
"""
def calcShannonEnt(dataSet):
#數據集行數
numEntries = len(dataSet)
#創建空字典記錄yes or no的次數
labelCounts = {}
#開始用循環語句統計標籤頻數,該思路和KNN算法是一樣的
#the the number of unique elements and their occurance
for featVec in dataSet:
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
#初始值是0,然後根據公式,用循環語句開始計算
shannonEnt = 0.0
for key in labelCounts:
#公式計算部分
prob = float(labelCounts[key])/numEntries
shannonEnt -= prob * log(prob, 2)
return shannonEnt
劃分數據集: 按照給定特徵劃分數據集
#這個函數後面用的上,先看懂代碼。後一個函數會讓你看懂它的真正作用。
def splitDataSet(dataSet, axis, value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
#去掉axis特徵
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
選擇最好的數據集劃分方式
#該函數選取最優的特徵,並返回最優特徵的索引值
def chooseBestFeatureToSplit(dataSet):
#特徵數量
#the last column is used for the labels
numFeatures = len(dataSet[0]) - 1
#計算數據集的香農熵
baseEntropy = calcShannonEnt(dataSet)
#信息增益
bestInfoGain = 0.0
#最優特徵的索引值,-1是隨便設置的值,便於後續更新值
bestFeature = -1
#遍歷所有特徵
for i in range(numFeatures):
#獲取dataSet的第i個所有特徵
featList = [example[i] for example in dataSet]
#創建set集合{},元素不可重複
uniqueVals = set(featList)
#經驗條件熵
newEntropy = 0.0
#計算信息增益
for value in uniqueVals:
#subDataSet劃分後的子集
subDataSet = splitDataSet(dataSet, i, value)
#計算子集的概率
prob = len(subDataSet)/float(len(dataSet))
#根據公式計算經驗條件熵
newEntropy += prob * calcShannonEnt(subDataSet)
#信息增益。calculate the info gain; ie reduction in entropy
infoGain = baseEntropy - newEntropy
#計算信息增益。compare this to the best gain so far
if (infoGain > bestInfoGain):
#更新信息增益,找到最大的信息增益。if better than current best, set to best
bestInfoGain = infoGain
#記錄信息增益最大的特徵的索引值
bestFeature = i
return bestFeature
多數表決法決定該葉子節點的分類
#這個函數是在下一個函數裏面第二個停止條件時候用上的
"""
代碼與第2章classify0部分的投票表決代碼非常類似
"""
def majorityCnt(classList):
classCount={}
#統計classList中每個元素出現的次數
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1
#最後利用operator操作鍵值排序字典,並返回出現次數最多的分類名稱
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
#返回classList中出現次數最多的元素
return sortedClassCount[0][0]
遞歸構建決策樹
#核心程序,創建樹
def createTree(dataSet, labels):
#取出所有分類標籤,yes or no
classList = [example[-1] for example in dataSet]
#如果類別完全相同,則停止繼續劃分。這是第一個停止條件。
if classList.count(classList[0]) == len(classList):
return classList[0]
#stop splitting when there are no more features in dataSe
#如果特徵都遍歷完了,還是沒有劃分的很純淨,那麼就取數量多一點的那個類別。這是第二個停止條件
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)
#遍歷特徵,創建決策樹。
"""
代碼遍歷當前選擇特徵包含的所有屬性值,在每個數據集劃分上遞歸調用函數,
createTree(),得到的返回值將被插入到字典變量myTree中,因此函數終止執行時,字典中將會嵌套很多代表葉子節點信息的字典數據。
"""
for value in uniqueVals:
#copy all of labels, so trees don't mess up existing labels
subLabels = labels[:]
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
return myTree
使用決策樹執行分類
def classify(inputTree, featLabels, testVec):
#獲取決策樹結點
firstStr = list(inputTree)[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
使用決策樹預測隱形眼鏡類型
#打開文本數據
fr = open('lenses.txt')
#解析數據
lenses = [inst.strip().split('\t') for inst in fr.readlines()]
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
#訓練算法,根據creatTree函數建樹
lensesTree = createTree(lenses,lensesLabels)
print(lensesTree)
{'tearRate': {'reduced': 'no lenses', 'normal': {'astigmatic': {'yes': {'prescript': {'myope': 'hard', 'hyper': {'age': {'pre': 'no lenses', 'presbyopic': 'no lenses', 'young': 'hard'}}}}, 'no': {'age': {'pre': 'soft', 'presbyopic': {'prescript': {'myope': 'no lenses', 'hyper': 'soft'}}, 'young': 'soft'}}}}}}
使用決策樹模型進行預測
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
classify(lensesTree, lensesLabels, lenses[0][:-1])
'no lenses'
對 lenses 數據集所有數據進行決策樹分類預測
preds = []
for i in range(len(lenses)):
pred = classify(lensesTree, lensesLabels, lenses[i][:-1])
preds.append(pred)
print(preds)
['no lenses', 'soft', 'no lenses', 'hard', 'no lenses', 'soft', 'no lenses', 'hard', 'no lenses', 'soft', 'no lenses', 'hard', 'no lenses', 'soft', 'no lenses', 'no lenses', 'no lenses', 'no lenses', 'no lenses', 'hard', 'no lenses', 'soft', 'no lenses', 'no lenses']