四亚情、使用決策樹執(zhí)行分類
依靠訓(xùn)練數(shù)據(jù)構(gòu)造了決策樹之后摊腋,我們可以將它用于實(shí)際數(shù)據(jù)的分類沸版。在執(zhí)行數(shù)據(jù)分類時(shí),需要決策樹以及用于構(gòu)造樹的標(biāo)簽向量兴蒸。然后视粮,程序比較測(cè)試數(shù)據(jù)與決策樹上的數(shù)值,遞歸執(zhí)行該過程直到進(jìn)入葉子結(jié)點(diǎn)橙凳;最后將測(cè)試數(shù)據(jù)定義為葉子結(jié)點(diǎn)所屬的類型蕾殴。在構(gòu)建決策樹的代碼笑撞,可以看到,有個(gè)featLabels參數(shù)钓觉。它是用來干什么的茴肥?它就是用來記錄各個(gè)分類結(jié)點(diǎn)的,在用決策樹做預(yù)測(cè)的時(shí)候荡灾,我們按順序輸入需要的分類結(jié)點(diǎn)的屬性值即可炉爆。舉個(gè)例子,比如我用上述已經(jīng)訓(xùn)練好的決策樹做分類卧晓,那么我只需要提供這個(gè)人是否有房子,是否有工作這兩個(gè)信息即可赴捞,無需提供冗余的信息逼裆。
用決策樹做分類的代碼很簡(jiǎn)單,編寫代碼如下:
# -*- coding: UTF-8 -*-
from math import log
import operator
"""
函數(shù)說明:計(jì)算給定數(shù)據(jù)集的經(jīng)驗(yàn)熵(香農(nóng)熵)
Parameters:
? ? dataSet - 數(shù)據(jù)集
Returns:
? ? shannonEnt - 經(jīng)驗(yàn)熵(香農(nóng)熵)
Author:
? ? Jack Cui
Modify:
? ? 2017-07-24
"""
def calcShannonEnt(dataSet):
? ? numEntires = len(dataSet)? ? ? ? ? ? ? ? ? ? ? ? #返回?cái)?shù)據(jù)集的行數(shù)
? ? labelCounts = {}? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #保存每個(gè)標(biāo)簽(Label)出現(xiàn)次數(shù)的字典
? ? for featVec in dataSet:? ? ? ? ? ? ? ? ? ? ? ? ? ? #對(duì)每組特征向量進(jìn)行統(tǒng)計(jì)
? ? ? ? currentLabel = featVec[-1]? ? ? ? ? ? ? ? ? ? #提取標(biāo)簽(Label)信息
? ? ? ? if currentLabel not in labelCounts.keys():? ? #如果標(biāo)簽(Label)沒有放入統(tǒng)計(jì)次數(shù)的字典,添加進(jìn)去
? ? ? ? ? ? labelCounts[currentLabel] = 0
? ? ? ? labelCounts[currentLabel] += 1? ? ? ? ? ? ? ? #Label計(jì)數(shù)
? ? shannonEnt = 0.0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #經(jīng)驗(yàn)熵(香農(nóng)熵)
? ? for key in labelCounts:? ? ? ? ? ? ? ? ? ? ? ? ? ? #計(jì)算香農(nóng)熵
? ? ? ? prob = float(labelCounts[key]) / numEntires? ? #選擇該標(biāo)簽(Label)的概率
? ? ? ? shannonEnt -= prob * log(prob, 2)? ? ? ? ? ? #利用公式計(jì)算
? ? return shannonEnt? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #返回經(jīng)驗(yàn)熵(香農(nóng)熵)
"""
函數(shù)說明:創(chuàng)建測(cè)試數(shù)據(jù)集
Parameters:
? ? 無
Returns:
? ? dataSet - 數(shù)據(jù)集
? ? labels - 特征標(biāo)簽
Author:
? ? Jack Cui
Modify:
? ? 2017-07-20
"""
def createDataSet():
? ? dataSet = [[0, 0, 0, 0, 'no'],? ? ? ? ? ? ? ? ? ? ? ? #數(shù)據(jù)集
? ? ? ? ? ? [0, 0, 0, 1, 'no'],
? ? ? ? ? ? [0, 1, 0, 1, 'yes'],
? ? ? ? ? ? [0, 1, 1, 0, 'yes'],
? ? ? ? ? ? [0, 0, 0, 0, 'no'],
? ? ? ? ? ? [1, 0, 0, 0, 'no'],
? ? ? ? ? ? [1, 0, 0, 1, 'no'],
? ? ? ? ? ? [1, 1, 1, 1, 'yes'],
? ? ? ? ? ? [1, 0, 1, 2, 'yes'],
? ? ? ? ? ? [1, 0, 1, 2, 'yes'],
? ? ? ? ? ? [2, 0, 1, 2, 'yes'],
? ? ? ? ? ? [2, 0, 1, 1, 'yes'],
? ? ? ? ? ? [2, 1, 0, 1, 'yes'],
? ? ? ? ? ? [2, 1, 0, 2, 'yes'],
? ? ? ? ? ? [2, 0, 0, 0, 'no']]
? ? labels = ['年齡', '有工作', '有自己的房子', '信貸情況']? ? ? ? #特征標(biāo)簽
? ? return dataSet, labels? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#返回?cái)?shù)據(jù)集和分類屬性
"""
函數(shù)說明:按照給定特征劃分?jǐn)?shù)據(jù)集
Parameters:
? ? dataSet - 待劃分的數(shù)據(jù)集
? ? axis - 劃分?jǐn)?shù)據(jù)集的特征
? ? value - 需要返回的特征的值
Returns:
? ? 無
Author:
? ? Jack Cui
Modify:
? ? 2017-07-24
"""
def splitDataSet(dataSet, axis, value):? ? ? ?
? ? retDataSet = []? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #創(chuàng)建返回的數(shù)據(jù)集列表
? ? for featVec in dataSet:? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#遍歷數(shù)據(jù)集
? ? ? ? if featVec[axis] == value:
? ? ? ? ? ? reducedFeatVec = featVec[:axis]? ? ? ? ? ? ? ? #去掉axis特征
? ? ? ? ? ? reducedFeatVec.extend(featVec[axis+1:])? ? ?#將符合條件的添加到返回的數(shù)據(jù)集
? ? ? ? ? ? retDataSet.append(reducedFeatVec)
? ? return retDataSet? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #返回劃分后的數(shù)據(jù)集
"""
函數(shù)說明:選擇最優(yōu)特征
Parameters:
? ? dataSet - 數(shù)據(jù)集
Returns:
? ? bestFeature - 信息增益最大的(最優(yōu))特征的索引值
Author:
? ? Jack Cui
Modify:
? ? 2017-07-20
"""
def chooseBestFeatureToSplit(dataSet):
? ? numFeatures = len(dataSet[0]) - 1? ? ? ? ? ? ? ? ? ? #特征數(shù)量
? ? baseEntropy = calcShannonEnt(dataSet)? ? ? ? ? ? ? ? ?#計(jì)算數(shù)據(jù)集的香農(nóng)熵
? ? bestInfoGain = 0.0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #信息增益
? ? bestFeature = -1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #最優(yōu)特征的索引值
? ? for i in range(numFeatures):? ? ? ? ? ? ? ? ? ? ? ? ?#遍歷所有特征
? ? ? ? #獲取dataSet的第i個(gè)所有特征
? ? ? ? featList = [example[i] for example in dataSet]
? ? ? ? uniqueVals = set(featList)? ? ? ? ? ? ? ? ? ? ? ? ?#創(chuàng)建set集合{},元素不可重復(fù)
? ? ? ? newEntropy = 0.0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #經(jīng)驗(yàn)條件熵
? ? ? ? for value in uniqueVals:? ? ? ? ? ? ? ? ? ? ? ? ?#計(jì)算信息增益
? ? ? ? ? ? subDataSet = splitDataSet(dataSet, i, value)? ? ? ? ?#subDataSet劃分后的子集
? ? ? ? ? ? prob = len(subDataSet) / float(len(dataSet))? ? ? ? ? ?#計(jì)算子集的概率
? ? ? ? ? ? newEntropy += prob * calcShannonEnt(subDataSet)? ? ?#根據(jù)公式計(jì)算經(jīng)驗(yàn)條件熵
? ? ? ? infoGain = baseEntropy - newEntropy? ? ? ? ? ? ? ? ? ? ?#信息增益
? ? ? ? # print("第%d個(gè)特征的增益為%.3f" % (i, infoGain))? ? ? ? ? ? #打印每個(gè)特征的信息增益
? ? ? ? if (infoGain > bestInfoGain):? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#計(jì)算信息增益
? ? ? ? ? ? bestInfoGain = infoGain? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#更新信息增益赦政,找到最大的信息增益
? ? ? ? ? ? bestFeature = i? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#記錄信息增益最大的特征的索引值
? ? return bestFeature? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#返回信息增益最大的特征的索引值
"""
函數(shù)說明:統(tǒng)計(jì)classList中出現(xiàn)此處最多的元素(類標(biāo)簽)
Parameters:
? ? classList - 類標(biāo)簽列表
Returns:
? ? sortedClassCount[0][0] - 出現(xiàn)此處最多的元素(類標(biāo)簽)
Author:
? ? Jack Cui
Modify:
? ? 2017-07-24
"""
def majorityCnt(classList):
? ? classCount = {}
? ? for vote in classList:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #統(tǒng)計(jì)classList中每個(gè)元素出現(xiàn)的次數(shù)
? ? ? ? if vote not in classCount.keys():classCount[vote] = 0? ?
? ? ? ? classCount[vote] += 1
? ? sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)? ? ? ? #根據(jù)字典的值降序排序
? ? return sortedClassCount[0][0]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #返回classList中出現(xiàn)次數(shù)最多的元素
"""
函數(shù)說明:創(chuàng)建決策樹
Parameters:
? ? dataSet - 訓(xùn)練數(shù)據(jù)集
? ? labels - 分類屬性標(biāo)簽
? ? featLabels - 存儲(chǔ)選擇的最優(yōu)特征標(biāo)簽
Returns:
? ? myTree - 決策樹
Author:
? ? Jack Cui
Modify:
? ? 2017-07-25
"""
def createTree(dataSet, labels, featLabels):
? ? classList = [example[-1] for example in dataSet]? ? ? ? ? ? #取分類標(biāo)簽(是否放貸:yes or no)
? ? if classList.count(classList[0]) == len(classList):? ? ? ? ? ? #如果類別完全相同則停止繼續(xù)劃分
? ? ? ? return classList[0]
? ? if len(dataSet[0]) == 1 or len(labels) == 0:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #遍歷完所有特征時(shí)返回出現(xiàn)次數(shù)最多的類標(biāo)簽
? ? ? ? return majorityCnt(classList)
? ? bestFeat = chooseBestFeatureToSplit(dataSet)? ? ? ? ? ? ? ? #選擇最優(yōu)特征
? ? bestFeatLabel = labels[bestFeat]? ? ? ? ? ? ? ? ? ? ? ? ? ? #最優(yōu)特征的標(biāo)簽
? ? featLabels.append(bestFeatLabel)
? ? myTree = {bestFeatLabel:{}}? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #根據(jù)最優(yōu)特征的標(biāo)簽生成樹
? ? del(labels[bestFeat])? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #刪除已經(jīng)使用特征標(biāo)簽
? ? featValues = [example[bestFeat] for example in dataSet]? ? ? ? #得到訓(xùn)練集中所有最優(yōu)特征的屬性值
? ? uniqueVals = set(featValues)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #去掉重復(fù)的屬性值
? ? for value in uniqueVals:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #遍歷特征胜宇,創(chuàng)建決策樹。? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), labels, featLabels)
? ? return myTree
"""
函數(shù)說明:使用決策樹分類
Parameters:
? ? inputTree - 已經(jīng)生成的決策樹
? ? featLabels - 存儲(chǔ)選擇的最優(yōu)特征標(biāo)簽
? ? testVec - 測(cè)試數(shù)據(jù)列表恢着,順序?qū)?yīng)最優(yōu)特征標(biāo)簽
Returns:
? ? classLabel - 分類結(jié)果
Author:
? ? Jack Cui
"""
def classify(inputTree, featLabels, testVec):
? ? firstStr = next(iter(inputTree))? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #獲取決策樹結(jié)點(diǎn)
? ? secondDict = inputTree[firstStr]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #下一個(gè)字典
? ? 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
if __name__ == '__main__':
? ? dataSet, labels = createDataSet()
? ? featLabels = []
? ? myTree = createTree(dataSet, labels, featLabels)
? ? testVec = [0,1]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #測(cè)試數(shù)據(jù)
? ? result = classify(myTree, featLabels, testVec)
? ? if result == 'yes':
? ? ? ? print('放貸')
? ? if result == 'no':
? ? ? ? print('不放貸')
這里只增加了classify函數(shù)桐愉,用于決策樹分類。輸入測(cè)試數(shù)據(jù)[0,1]掰派,它代表沒有房子从诲,但是有工作,分類結(jié)果如下所示:
看到這里靡羡,細(xì)心的朋友可能就會(huì)問了系洛,每次做預(yù)測(cè)都要訓(xùn)練一次決策樹?這也太麻煩了吧略步?有什么好的解決嗎描扯?
五、決策樹的存儲(chǔ)
構(gòu)造決策樹是很耗時(shí)的任務(wù)趟薄,即使處理很小的數(shù)據(jù)集绽诚,如前面的樣本數(shù)據(jù),也要花費(fèi)幾秒的時(shí)間杭煎,如果數(shù)據(jù)集很大恩够,將會(huì)耗費(fèi)很多計(jì)算時(shí)間。然而用創(chuàng)建好的決策樹解決分類問題岔帽,則可以很快完成玫鸟。因此,為了節(jié)省計(jì)算時(shí)間犀勒,最好能夠在每次執(zhí)行分類時(shí)調(diào)用已經(jīng)構(gòu)造好的決策樹屎飘。為了解決這個(gè)問題妥曲,需要使用Python模塊pickle序列化對(duì)象。序列化對(duì)象可以在磁盤上保存對(duì)象钦购,并在需要的時(shí)候讀取出來檐盟。
假設(shè)我們已經(jīng)得到?jīng)Q策樹{'有自己的房子': {0: {'有工作': {0: 'no', 1: 'yes'}}, 1: 'yes'}},使用pickle.dump存儲(chǔ)決策樹押桃。
# -*- coding: UTF-8 -*-
import pickle
"""
函數(shù)說明:存儲(chǔ)決策樹
Parameters:
? ? inputTree - 已經(jīng)生成的決策樹
? ? filename - 決策樹的存儲(chǔ)文件名
Returns:
? ? 無
Author:
? ? Jack Cui
Modify:
? ? 2017-07-25
"""
def storeTree(inputTree, filename):
? ? with open(filename, 'wb') as fw:
? ? ? ? pickle.dump(inputTree, fw)
if __name__ == '__main__':
? ? myTree = {'有自己的房子': {0: {'有工作': {0: 'no', 1: 'yes'}}, 1: 'yes'}}
? ? storeTree(myTree, 'classifierStorage.txt')
運(yùn)行代碼葵萎,在該P(yáng)ython文件的相同目錄下,會(huì)生成一個(gè)名為classifierStorage.txt的txt文件,這個(gè)文件二進(jìn)制存儲(chǔ)著我們的決策樹。我們可以使用sublime txt打開看下存儲(chǔ)結(jié)果桨武。
看不懂痕慢?沒錯(cuò),因?yàn)檫@個(gè)是個(gè)二進(jìn)制存儲(chǔ)的文件,我們也無需看懂里面的內(nèi)容,會(huì)存儲(chǔ),會(huì)用即可漫雕。那么問題來了。將決策樹存儲(chǔ)完這個(gè)二進(jìn)制文件峰鄙,然后下次使用的話浸间,怎么用呢?
很簡(jiǎn)單使用pickle.load進(jìn)行載入即可吟榴,編寫代碼如下:
# -*- coding: UTF-8 -*-
import pickle
"""
函數(shù)說明:讀取決策樹
Parameters:
? ? filename - 決策樹的存儲(chǔ)文件名
Returns:
? ? pickle.load(fr) - 決策樹字典
Author:
? ? Jack Cui
Modify:
? ? 2017-07-25
"""
def grabTree(filename):
? ? fr = open(filename, 'rb')
? ? return pickle.load(fr)
if __name__ == '__main__':
? ? myTree = grabTree('classifierStorage.txt')
? ? print(myTree)
如果在該P(yáng)ython文件的相同目錄下魁蒜,有一個(gè)名為classifierStorage.txt的文件,那么我們就可以運(yùn)行上述代碼吩翻,運(yùn)行結(jié)果如下圖所示:
從上述結(jié)果中梅惯,我們可以看到,我們順利加載了存儲(chǔ)決策樹的二進(jìn)制文件仿野。免費(fèi)視頻教程:www.mlxs.top? ??