決策樹(shù)

本周學(xué)了一種非要重要也非常基礎(chǔ)的核心分類(lèi)算法——決策樹(shù)嗅榕。下面對(duì)決策樹(shù)算法做一個(gè)總結(jié):)

決策樹(shù)(decision tree)是一種基本的分類(lèi)與回歸方法。這里主要總結(jié)用于分類(lèi)的決策樹(shù)吵聪。決策樹(shù)模型呈樹(shù)形結(jié)構(gòu)凌那,在分類(lèi)問(wèn)題中,表示基于特征對(duì)實(shí)例進(jìn)行分類(lèi)的過(guò)程吟逝。它可以認(rèn)為是if-then規(guī)則的集合帽蝶,也可以認(rèn)為是定義在特征空間與類(lèi)空間上的條件概率分布。主要優(yōu)點(diǎn)是模型具有可讀性块攒,分類(lèi)速度快励稳。學(xué)習(xí)時(shí),利用訓(xùn)練數(shù)據(jù)囱井,根據(jù)損失函數(shù)最小化的原則建立決策樹(shù)驹尼。預(yù)測(cè)時(shí),對(duì)新的數(shù)據(jù)庞呕,利用決策樹(shù)模型進(jìn)行分類(lèi)新翎。決策樹(shù)學(xué)習(xí)通常包括3個(gè)步驟:特征選擇、決策樹(shù)的生成和決策的修建住练。生成決策樹(shù)后就可以根據(jù)它來(lái)進(jìn)行分類(lèi)了地啰。這些決策樹(shù)的思想主要來(lái)源于由Quinlan在1986年提出的ID3算法和1993年提出的C4.5算法,以及由Breiman等人在1984年提出的CART算法讲逛。(其實(shí)這幾種算法的主要區(qū)別就在于采用什么方式選擇最合適的屬性作為分裂準(zhǔn)則亏吝,也叫屬性選擇度量),這里介紹的是基礎(chǔ)的ID3算法盏混,采用的是信息增益最大的屬性進(jìn)行分裂蔚鸥。

選擇根屬性惜论,就好比下面一堆數(shù)據(jù),構(gòu)成的決策樹(shù)


決策樹(shù)

這里看起來(lái)挺正常株茶,但是如果給我們一堆數(shù)據(jù)来涨,我們?cè)趺粗栏鶎傩孕枰獜摹澳挲g”這里字段來(lái)進(jìn)行分裂呢?這就牽涉到一個(gè)信息增益的問(wèn)題启盛,也就是我希望我選擇的這個(gè)屬性可以獲得最大信息增益蹦掐,也就是根據(jù)這個(gè)屬性分出來(lái)的兩個(gè)子樹(shù)中純度比較好,這么說(shuō)吧僵闯,我選擇了“年齡”字段卧抗,如果年齡過(guò)大的直接就Pass了,這就說(shuō)明這個(gè)屬性很給力鳖粟,僅憑這一點(diǎn)就可以判斷是否需要去見(jiàn)面社裆。那么這個(gè)最大信息增益需要怎么來(lái)度量呢?就需要使用一個(gè)叫做香農(nóng)信息熵的概念向图。
香農(nóng)是信息論的奠基人泳秀,大牛,學(xué)會(huì)信息論和數(shù)字信號(hào)處理的都知道榄攀。信息熵的計(jì)算采用如下公式:
信息熵

pi是D中任意屬性元組屬于類(lèi)Ci的概率嗜傅,并用|Ci|/|D|來(lái)估計(jì)。具體來(lái)說(shuō)檩赢,如果數(shù)據(jù)集中有5個(gè)人愿意見(jiàn)面吕嘀,有5個(gè)人不想見(jiàn)面,那么總?cè)藬?shù)就是10個(gè)人贞瞒,這里的pi就等于5/10=0.5偶房,信息熵就等于-0.5log0.5+(-0.5log0.5)。注意:這里是根據(jù)最終分類(lèi)結(jié)果來(lái)計(jì)算的總的信息熵军浆。
下面計(jì)算屬性“年齡”帶來(lái)的信息熵:

其中棕洋,|Dj|/|D|充當(dāng)權(quán)重值,在這里就是年齡屬性的權(quán)重乒融,假設(shè)年齡大于35歲的有4個(gè)人拍冠,小于等于35歲的有6個(gè)人,先看年齡大于35歲的4個(gè)人簇抵,這里|Dj|/|D|=4/10=0.4庆杜,Info(Dj)就是在年齡35以上這些人里面有多少人獲得了見(jiàn)面機(jī)會(huì)的,顯然機(jī)會(huì)為零碟摆,因此Info(Dj)=0晃财;繼續(xù)來(lái)看年齡小于等于35歲的6個(gè)人,假設(shè)有3個(gè)人獲得見(jiàn)面機(jī)會(huì),那么|Dj|/|D|=6/10=0.6,pj=3/6=0.5,所以Info(Dj)=0+(-0.5log0.5)=0.5断盛,因此最終“年齡”屬性的信息增益是0.60.5=0.3罗洗。
屬性“年齡”的信息增益就是:Gain(年齡)=Info-Info(年齡)=1-0.3=0.7
同樣可以求得其他幾個(gè)屬性的信息增益,選擇信息增益最大的屬性作為分裂的屬性钢猛,這就是ID3算法伙菜。

項(xiàng)目案例和實(shí)際代碼編寫(xiě)

根據(jù)以下 2 個(gè)特征,將動(dòng)物分成兩類(lèi):魚(yú)類(lèi)和非魚(yú)類(lèi)命迈。
特征:
不浮出水面是否可以生存
是否有腳蹼


1.選擇根屬性(也就是分裂的屬性)

首先贩绕,我們需要把數(shù)據(jù)讀入到一個(gè)數(shù)據(jù)集中去:

from math import log

original_labels = []

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

其實(shí),根據(jù)我們上面的算法思路計(jì)算數(shù)據(jù)集的整體信息熵壶愤,這里可以進(jìn)行測(cè)試一下

def calcShannonEnt(dataSet):
    # 求list的長(zhǎng)度淑倾,表示計(jì)算參與訓(xùn)練的數(shù)據(jù)量
    numEntries = len(dataSet)
    # 計(jì)算分類(lèi)標(biāo)簽label出現(xiàn)的次數(shù)
    labelCounts = {}

    for featVec in dataSet:
        # 每行的最后一列元素就是分類(lèi)標(biāo)簽
        currentLabel = featVec[-1]
        # 更新標(biāo)簽的計(jì)數(shù)
        labelCounts[currentLabel] = labelCounts.get(currentLabel,0)+1

    # 根據(jù)標(biāo)簽的占比求出香農(nóng)熵
    shannonEnt = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key])/numEntries
        # 計(jì)算香農(nóng)熵,以2為底征椒,求對(duì)數(shù)
        shannonEnt -= prob*log(prob,2)
    return shannonEnt

dataSet,labels = createDataSet()
shannonEnt = calcShannonEnt(dataSet)
print("shannonEnt = %s"%shannonEnt)

得到:shannonEnt = 0.9709505944546686娇哆,也就是這個(gè)數(shù)據(jù)集的整體信息熵為0.97*****
獲取數(shù)據(jù)子集,也就是某一屬性等于某一個(gè)具體值時(shí)的數(shù)據(jù)子集勃救,計(jì)算某一屬性的信息熵時(shí)需要用到:

'''將dataSet數(shù)據(jù)集分開(kāi)碍讨,遍歷dataSet的行,當(dāng)index列的值等于value時(shí)蒙秒,把這行數(shù)據(jù)劃分進(jìn)我們新的數(shù)據(jù)集中勃黍,同時(shí)要把index列的元素去掉'''
def splitDataSet(dataSet,index,value):
    retDataSet = []
    for featVect in dataSet:
        if(featVect[index]==value):
            reducedFeatVect = featVect[:index]
            reducedFeatVect.extend(featVect[index+1:]) # 其實(shí)這里就是去掉了index列的數(shù)據(jù),并把這一行單獨(dú)留下來(lái)放到新的數(shù)據(jù)集中去了
            retDataSet.append(reducedFeatVect)
            #retDataSet.append(featVect) # 其實(shí)這里這樣就可以了税肪,沒(méi)必要非要把比較的index列去掉
    return retDataSet

temp = splitDataSet(dataSet,2,'yes')
print(temp)

接下來(lái)溉躲,分別計(jì)算各個(gè)屬性的信息熵榜田,選擇分裂屬性

'''選擇最好的數(shù)據(jù)劃分方式劃分?jǐn)?shù)據(jù)'''
def chooseBestFeatureToSplit(dataSet):
    # 一共有多少列屬性益兄,最后一列是標(biāo)簽列所以要減掉
    numberOfFeatures = len(dataSet[0])-1
    # 數(shù)據(jù)集的原始信息熵
    baseEntropy = calcShannonEnt(dataSet)
    # 初始化信息增益和最佳的屬性列
    bestInfoGain,bestFeature = 0.0,-1
    # 遍歷所有的屬性
    for i in range(numberOfFeatures):
        # 獲取該屬性的所有數(shù)據(jù)
        featureList = [example[i] for example in dataSet] # 這個(gè)寫(xiě)法是遍歷數(shù)據(jù)集中的每一行,把其中的第i個(gè)數(shù)據(jù)取出來(lái)組合成一個(gè)列表
        featureList = set(featureList) # 屬性值去重
        newEntropy = 0.0 # 新的臨時(shí)的信息熵
        # 根據(jù)屬性值進(jìn)行分割數(shù)據(jù)集
        for value in featureList:
            subData = splitDataSet(dataSet,i,value)
            prob = len(subData)/float(len(dataSet)) # 計(jì)算該屬性值等于value的數(shù)據(jù)在總數(shù)據(jù)集中的比例
            newEntropy += prob*calcShannonEnt(subData) # 計(jì)算新的信息熵
        infoGain = baseEntropy - newEntropy # 計(jì)算出該屬性的信息增益
        if(infoGain>bestInfoGain): # 如果信息增益變大了箭券,就把當(dāng)前屬性作為最好的劃分?jǐn)?shù)據(jù)净捅,繼續(xù)遍歷
            bestInfoGain = infoGain
            bestFeature = i
    # 返回最好的劃分屬性
    return bestFeature

bestF = chooseBestFeatureToSplit(dataSet)
print("The best feature is %s"%bestF)

2.構(gòu)造決策樹(shù)

有了最好的分裂屬性后,我們就可以構(gòu)建決策樹(shù)了:

# 創(chuàng)建決策樹(shù)
def createTree(dataSet,labels):
    classList = [example[-1] for example in dataSet] # 類(lèi)別列表辩块,這是一種快速獲取某列屬性值的方法
    # 第一個(gè)停止條件:如果所有標(biāo)簽分類(lèi)都相同則返回
    if classList.count(classList[0])==len(classList):
        return classList[0]
    # 第二個(gè)停止條件:如果數(shù)據(jù)集只有一列蛔六,那么最初出現(xiàn)label最多的一類(lèi)作為結(jié)果返回
    if(len(dataSet[0])==1):
        return majorityCnt(classList)
    # 選擇最優(yōu)的分裂的類(lèi)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    # 獲取label的名稱(chēng)
    bestFeatLabel = labels[bestFeat]
    # 初始化樹(shù),樹(shù)采用字典存儲(chǔ)
    myTree = {bestFeatLabel:{}}
    del(labels[bestFeat]) # 從屬性列表中刪除這個(gè)屬性,因?yàn)橐呀?jīng)分類(lèi)了废亭,接下來(lái)要從剩下的這些屬性中進(jìn)行子樹(shù)的構(gòu)建了
    # 取出最優(yōu)列国章,然后他的分支做分類(lèi),如“年齡”屬性取出后豆村,剩下的子樹(shù)就是>35歲的和<=35歲的
    featValues = [example[bestFeat] for example in dataSet]
    uniqueValues = set(featValues) # 去重
    for value in uniqueValues:
        # 剩余的標(biāo)簽label
        subLabels = labels[:]
        # 遍歷當(dāng)前選擇特征包含的所有屬性值液兽,在每個(gè)數(shù)據(jù)集劃分上遞歸調(diào)用函數(shù)createTree()
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
    return myTree

注意,決策樹(shù)的物理存儲(chǔ)就是一個(gè)字典掌动,以鍵值對(duì)形式存儲(chǔ)數(shù)據(jù)四啰。

3.使用決策樹(shù)進(jìn)行分類(lèi)

分類(lèi)函數(shù)

# 使用決策樹(shù)進(jìn)行分類(lèi)
def classify(inputTree,featLabels,testVec):
    # 獲取樹(shù)根節(jié)點(diǎn)對(duì)于Key的值
    firstStr = list(inputTree.keys())[0]
    # 獲取對(duì)應(yīng)的值宁玫,其實(shí)也是一個(gè)字典
    secondDict = inputTree[firstStr]
    # 獲取根節(jié)點(diǎn)對(duì)應(yīng)在標(biāo)簽中的序號(hào)
    featIndex = featLabels.index(firstStr)
    # 獲取測(cè)試數(shù)據(jù)集中該標(biāo)簽的值
    key = testVec[featIndex]
    # 獲取值,看看有沒(méi)有子樹(shù)
    valueOfFeat = secondDict[key]
    print("+++"+firstStr+"xxx"+secondDict+"---"+key+">>>"+valueOfFeat)
    # 如果還有子樹(shù)就繼續(xù)往下分類(lèi)
    if(isinstance(valueOfFeat,dict)):
        classLabel = classify(valueOfFeat,featLabels,testVec)
    # 否則就把標(biāo)簽值作為分類(lèi)標(biāo)簽
    else:
        classLabel = valueOfFeat
    return classLabel

4.使用決策樹(shù)進(jìn)行分類(lèi)

dataSet,labels = createDataSet()
for label in labels:
    # 這里用到original_labels就是因?yàn)閘abels調(diào)用label方法后會(huì)被刪除柑晒,無(wú)法在classify方法中使用欧瘪,因此需要另外使用一個(gè)變量保存原始label
    original_labels.append(label) 
inputTree = createTree(dataSet,labels)
print("決策樹(shù)------->%s"%inputTree)
testVec = [0,0]
lb = classify(inputTree,original_labels,testVec)
print("lb=%s"%lb)

我們可以看到最終輸出為:

The best feature is 0
決策樹(shù)------->{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
lb=no

可以看到?jīng)Q策樹(shù),最后就是一個(gè)字典匙赞。最好的分類(lèi)就是屬性'no surfacing'佛掖。[0,0]這個(gè)測(cè)試向量得到的分類(lèi)是no,這個(gè)也符合我們的常識(shí)罚屋,一個(gè)動(dòng)物既不能在水下生存也沒(méi)有腳蹼苦囱,那就肯定不是魚(yú)類(lèi)了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脾猛,一起剝皮案震驚了整個(gè)濱河市撕彤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌猛拴,老刑警劉巖羹铅,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異愉昆,居然都是意外死亡职员,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)跛溉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)焊切,“玉大人,你說(shuō)我怎么就攤上這事芳室∽ǚ荆” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵堪侯,是天一觀的道長(zhǎng)嚎尤。 經(jīng)常有香客問(wèn)我,道長(zhǎng)伍宦,這世上最難降的妖魔是什么芽死? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮次洼,結(jié)果婚禮上关贵,老公的妹妹穿的比我還像新娘。我一直安慰自己卖毁,他們只是感情好揖曾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般翩肌。 火紅的嫁衣襯著肌膚如雪模暗。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天念祭,我揣著相機(jī)與錄音兑宇,去河邊找鬼。 笑死粱坤,一個(gè)胖子當(dāng)著我的面吹牛隶糕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播站玄,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼枚驻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了株旷?” 一聲冷哼從身側(cè)響起再登,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晾剖,沒(méi)想到半個(gè)月后锉矢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡齿尽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年沽损,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片循头。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绵估,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卡骂,到底是詐尸還是另有隱情国裳,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布偿警,位于F島的核電站躏救,受9級(jí)特大地震影響唯笙,放射性物質(zhì)發(fā)生泄漏螟蒸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一崩掘、第九天 我趴在偏房一處隱蔽的房頂上張望七嫌。 院中可真熱鬧,春花似錦苞慢、人聲如沸诵原。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)绍赛。三九已至蔓纠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吗蚌,已是汗流浹背腿倚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚯妇,地道東北人敷燎。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像箩言,于是被迫代替她去往敵國(guó)和親硬贯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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

  • 決策樹(shù)理論在決策樹(shù)理論中陨收,有這樣一句話饭豹,“用較少的東西,照樣可以做很好的事情务漩。越是小的決策樹(shù)墨状,越優(yōu)于大的決策樹(shù)”。...
    制杖灶灶閱讀 5,851評(píng)論 0 25
  • 前言: 通過(guò)第前面的學(xué)習(xí)介紹了機(jī)器學(xué)習(xí)回歸模型創(chuàng)建的流程菲饼,并且知道了機(jī)器學(xué)習(xí)要做的事情是找到目標(biāo)函數(shù)肾砂,優(yōu)化它,通過(guò)...
    飄涯閱讀 6,394評(píng)論 4 83
  • 轉(zhuǎn)自算法雜貨鋪--決策樹(shù)決策樹(shù)和隨機(jī)森林學(xué)習(xí)筆記-歡迎補(bǔ)充 http://www.cnblogs.com/fion...
    明翼閱讀 10,742評(píng)論 1 6
  • 決策樹(shù)ID3、C4.5 如需轉(zhuǎn)載饼煞,請(qǐng)注明作者及出處. 作者:Treant 出處:http://www.cnblog...
    小小少年Boy閱讀 1,269評(píng)論 2 9
  • /*在E盤(pán)新建一個(gè)文件夾mc,數(shù)據(jù)集放在E盤(pán)的mc文件夾中源葫。*/ /* 建立數(shù)據(jù)庫(kù)cps1,其物理地址為E:\mc...
    meychang閱讀 214評(píng)論 0 0