決策樹入門示例(Python)

筆者剛開始接觸數(shù)據(jù)挖掘,入門參考書籍為Peter Harrington編著的《機(jī)器學(xué)習(xí)》励堡,文章代碼亦大量借鑒于書中褐筛。

信息增益

導(dǎo)入模塊:

from math import log
import operator

計(jì)算給定數(shù)據(jù)集的香農(nóng)熵:

def calcShannonEnt(dataSet):
    numEntries = len(dataSet)
    lableCounts = {}
    for featVec in dataSet:
        currentLable = featVec[-1]
        if currentLable not in lableCounts.keys():
            lableCounts[currentLable] = 0
        lableCounts[currentLable] += 1
    shannonEnt = 0
    for key in lableCounts:
        prob = float(lableCounts[key])/numEntries
        shannonEnt -= prob * log(prob,2)
    return shannonEnt

創(chuàng)建簡(jiǎn)單的數(shù)據(jù)集:

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

字段說明

[1,1,0,'fight']

數(shù)值 武器類型 子彈 血量
0 步槍
1 機(jī)槍
行為類別
fight 戰(zhàn)斗
run 逃跑

按行打印數(shù)據(jù)集

def printData(myData):
    for item in myData:
        print '%s' %(item)

用Python命令提示符輸入下列命令:

>>> import tree
>>> myDat,lable = tree.createDataSet()
>>> tree.printData(myDat)
[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']
>>> tree.calcShannonEnt(myDat)
0.863120568566631

得到香農(nóng)熵為0.863120568566631

熵越高,則混合的數(shù)據(jù)也越多。
為數(shù)據(jù)集添加新分類surrender

>>> myDat[0][-1] = 'surrender'
>>> tree.printData(myDat)
[1, 1, 0, 'surrender']
[1, 0, 1, 'fight']
[1, 0, 1, 'fight']
[1, 0, 1, 'fight']
[0, 0, 1, 'run']
[0, 1, 0, 'fight']
[0, 1, 1, 'run']
>>> tree.calcShannonEnt(myDat)
1.3787834934861756

得到香農(nóng)熵為1.3787834934861756

劃分?jǐn)?shù)據(jù)集

按照給定特征劃分?jǐn)?shù)據(jù)集:

def splitDataSet(dataSet,axis,value):
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet

輸入Python命令卧土,分別提取武器類型為1(機(jī)槍)0(步槍)的行為:

>>> reload(tree)
<module 'tree' from 'tree.py'>
>>> myDat,lable = tree.createDataSet()
>>> tree.printData(myDat)
[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']
>>> tree.splitDataSet(myDat,0,1)
[[1, 0, 'fight'], [0, 1, 'fight'], [0, 1, 'fight'], [0, 1, 'fight']]
>>> tree.splitDataSet(myDat,0,0)
[[0, 1, 'run'], [1, 0, 'fight'], [1, 1, 'run']]

選擇最好的數(shù)據(jù)集劃分方式:

def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0
    bestFeature = -1
    for i in range(numFeatures):
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)
        newEntropy = 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

chooseBestFeatureToSplit調(diào)用的數(shù)據(jù)需要滿足的要求:

  1. 數(shù)據(jù)必須是一種由列表元素組成的列表
  2. 所有列表元素都要具有相同的數(shù)據(jù)長(zhǎng)度
  3. 數(shù)據(jù)的最后一列是當(dāng)前數(shù)據(jù)的類別標(biāo)簽

在開始劃分?jǐn)?shù)據(jù)集之前,先計(jì)算整個(gè)數(shù)據(jù)集的原始香農(nóng)熵像樊,保存最初的無(wú)序度量值夸溶,用于與劃分完之后的數(shù)據(jù)集計(jì)算的熵值進(jìn)行比較,從而計(jì)算信息增益凶硅。

遍歷當(dāng)前特征中的所有唯一屬性值缝裁,對(duì)每個(gè)特征劃分一次數(shù)據(jù)集,然后計(jì)算數(shù)據(jù)集的新熵值足绅,并對(duì)所有唯一特征值得到的熵求和捷绑。

最后,比較所有特征中的信息增益氢妈,返回最好特征劃分的索引值粹污。

>>> reload(tree)
<module 'tree' from 'tree.pyc'>
>>> myDat,lable = tree.createDataSet()
>>> tree.printData(myDat)
[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']
>>> tree.chooseBestFeatureToSplit(myDat)
0.469565211115
0.00597771142377
0.16958442967
0

在劃分?jǐn)?shù)據(jù)集之前之后信息發(fā)生的變化稱為信息增益

特征 信息增益
武器類型 0.469565211115
子彈數(shù)量 0.00597771142377
血量 0.16958442967

運(yùn)行結(jié)果告訴我們首量,第0個(gè)特征壮吩,也就是武器類型是最好的用于劃分?jǐn)?shù)據(jù)集的特征。

遞歸構(gòu)建決策樹

創(chuàng)建??的函數(shù)代碼:

def createTree(dataSet,lables):
    classList = [example[-1] for example in dataSet]
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    if len(dataSet[0]) == 1:
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    bestFeatLable = lables[bestFeat]
    myTree = {bestFeatLable:{}}
    del(lables[bestFeat])
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
        subLables = lables[:]
        myTree[bestFeatLable][value] = createTree(splitDataSet(dataSet,bestFeat,value),subLables)
    return myTree

遞歸結(jié)束的條件:

  • 遍歷完所有劃分?jǐn)?shù)據(jù)集的屬性
  • 每個(gè)分支下的素有實(shí)力都有相同的分類

所有的類標(biāo)簽完全相同加缘,則返回該類標(biāo)簽鸭叙。如果使用完了所有特征,仍然不能將數(shù)據(jù)集劃分成僅包含唯一類別的分組拣宏,則通過majorityCnt挑選出出現(xiàn)次數(shù)最多的類別標(biāo)簽作為返回值沈贝。

選出出現(xiàn)次數(shù)最多的分類名稱:

def majorityCnt(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.iteritems(),key = operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

為測(cè)試代碼的實(shí)際輸出結(jié)果,在Python命令提示符中輸入下列命令:

>>> reload(tree)
<module 'tree' from 'tree.pyc'>
>>> myDat,lable = tree.createDataSet()
>>> tree.printData(myDat)
[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']
>>> tree.createTree(myDat,lable)
0.469565211115
0.00597771142377
0.16958442967
0.251629167388
0.918295834054
{'weapon': {0: {'blood': {0: 'fight', 1: 'run'}}, 1: 'fight'}}

createTree返回的嵌套字典包含了很多代表樹結(jié)構(gòu)的信息勋乾,從左邊開始宋下,第一個(gè)關(guān)鍵字weapon是第一個(gè)劃分?jǐn)?shù)據(jù)集的特征名稱,該關(guān)鍵字的值也是另一個(gè)數(shù)據(jù)字典。第二個(gè)關(guān)鍵字是weapon特征劃分的數(shù)據(jù)集辑莫,這些關(guān)鍵字的值是weapon節(jié)點(diǎn)的子節(jié)點(diǎn)学歧。這些值可能是類標(biāo)簽,也可能是另一個(gè)數(shù)據(jù)字典各吨。如果值是類標(biāo)簽枝笨,則該節(jié)點(diǎn)是葉子節(jié)點(diǎn);如果值是另一個(gè)數(shù)據(jù)字典,則子節(jié)點(diǎn)是一個(gè)判斷節(jié)點(diǎn)伺帘,這種格式結(jié)構(gòu)不斷重復(fù)就構(gòu)成了整棵??昭躺。該例子中包含了3個(gè)葉子節(jié)點(diǎn)和2個(gè)判斷節(jié)點(diǎn)忌锯。

劃分?jǐn)?shù)據(jù)集時(shí)的數(shù)據(jù)路徑
劃分?jǐn)?shù)據(jù)集時(shí)的數(shù)據(jù)路徑
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末伪嫁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子偶垮,更是在濱河造成了極大的恐慌张咳,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件似舵,死亡現(xiàn)場(chǎng)離奇詭異脚猾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)砚哗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門龙助,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蛛芥,你說我怎么就攤上這事提鸟。” “怎么了仅淑?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵称勋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我涯竟,道長(zhǎng)赡鲜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任庐船,我火速辦了婚禮银酬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筐钟。我一直安慰自己捡硅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布盗棵。 她就那樣靜靜地躺著壮韭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纹因。 梳的紋絲不亂的頭發(fā)上喷屋,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音瞭恰,去河邊找鬼屯曹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的恶耽。 我是一名探鬼主播密任,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼偷俭!你這毒婦竟也來(lái)了浪讳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤涌萤,失蹤者是張志新(化名)和其女友劉穎淹遵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體负溪,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡透揣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了川抡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辐真。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖崖堤,靈堂內(nèi)的尸體忽然破棺而出侍咱,到底是詐尸還是另有隱情,我是刑警寧澤倘感,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布放坏,位于F島的核電站,受9級(jí)特大地震影響老玛,放射性物質(zhì)發(fā)生泄漏淤年。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一蜡豹、第九天 我趴在偏房一處隱蔽的房頂上張望麸粮。 院中可真熱鬧,春花似錦镜廉、人聲如沸弄诲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)齐遵。三九已至,卻和暖如春塔插,著一層夾襖步出監(jiān)牢的瞬間梗摇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工想许, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伶授,地道東北人断序。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像糜烹,于是被迫代替她去往敵國(guó)和親违诗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容