決策樹(decision tree)

版權聲明:本文出自胖喵~的博客,轉載必須註明出處。html

   轉載請註明出處:http://www.javashuo.com/article/p-eecdrjlp-cy.html算法

 

前言

以前在測試建模分析中講過決策樹的概念,這裏要說的機器學習的決策樹在構建上和最終目的與以前的決策樹是有一些不一樣的,可是同時他們又有不少的類似性,具體能夠往下看。
機器學習能夠分爲四大塊:
  classification (分類),
  regression (迴歸),
  clustering (聚類),
  dimensionality reduction (降維)json

前面咱們已經講過利用最小二乘解決線性迴歸的問題,而這裏講的決策樹是能夠解決分類的問題。app

 

使用場景

這裏舉個實際的例子來講明決策樹的使用場景。
例如中關村某商家記錄了以前消費者購買電腦的記錄,以下:dom

ID 年齡 收入 學生 芝麻信譽等級 最終是否買了電腦
 1  年輕
 2  年輕 高  否  否 
 3  中年 高  否  是 
 4  老年  中  否  低  是 
 5  老年 低  是  低  是 
 6  老年 低  是  好  否 
 7  中年 低  是  是 
 8  年輕 否  低  否 
 9  年輕  低  是  低  是 
 10  老年  中  是  低  是 
 11  年輕  中  是  是 
 12  中年  中  否  好  是 
 13  中年  高  低  是 
 14  老年  中  否  好 

這裏他已經有了一些歷史的數據,他但願根據這些歷史的數據來預測當有一我的已經他的一些基本狀況,可否預測出他是否要買電腦。假如咱們根據以前的經驗畫出了這個決策數。以下:機器學習

固然這個是咱們本身憑感受去畫的這顆決策樹,可是也算是一顆比較完整的決策樹了,當有一個新的用戶來了後,咱們就能夠按照上面劃分,從跟節點一直遍歷到子節點,最終到達葉子節點最底端,從而獲得結論。看到這裏有些人可能就會有疑問了,那麼我究竟應該怎麼選取跟節點呢?也就是說,我第一步究竟用「年齡」「收入」或者其餘條件哪一個作爲跟節點先進行分離的話,我構造的決策樹越簡單明瞭呢? 往下看學習

 

信息增益

前面咱們介紹過信息熵(entropy)的概念,信息熵大小表明信息的不肯定的大小,信息熵越大,信息不肯定性越高,信息熵越小,不肯定性越小。測試

這裏咱們就用這個概念來決定使用哪一個條件做爲咱們的跟節點,具體的思路是:首先根據已有的數據算出用戶是否會購買電腦的信息熵,而後加入一個條件,例如年齡,計算出不一樣年齡的人購買電腦的信息熵,而後用以前的信息熵減去這個信息熵,這裏獲得的差值的意義是:年齡這個條件的引入帶來的信息混亂程度的大小。這裏咱們須要思考下,咱們首選的跟節點確定但願是劃分以後,可以很是明顯的區分開這兩類東西,而很是明顯的區分開也就是分開以後信息熵須要變小,那麼咱們就須要尋找一個目前這幾個條件中對信息混亂程度影響最大的那一個。這個差值就叫作信息增益,而咱們的目的其實就是找到信息增益最大的那一個。編碼

$信息增益_{年齡} = Info - Info_{年齡}  $ spa

上式中的Info表明的就是信息熵。這裏咱們實際計算一下年齡的信息增益。首先購買電腦的信息熵是(上面一共14我的,9我的買了,5我的沒買):

$Info = -\sum\limits_{i=1}^{n} P(X_{i})\log_{2}P(X_{i} ) = -\frac{9}{14}\log_{2}\frac{9}{14} - \frac{5}{14}\log_{2}\frac{5}{14} = 0.940bits$

不一樣年齡下的信息熵(5個年輕人中2個買3個不買,4箇中年人都買,5個老年人3個買2個不買)是:

$Info_{年齡} = \frac{5}{14}(-\frac{2}{5}\log_{2}\frac{2}{5}-\frac{3}{5}\log_{2}\frac{3}{5})+\frac{4}{14}(-\frac{4}{4}\log_{2}\frac{4}{4} - \frac{0}{4}\log_{2}\frac{0}{4})+\frac{5}{14}(-\frac{3}{5}\log_{2}\frac{3}{5} - \frac{2}{5}\log_{2}\frac{2}{5}) = 0.694bits$

以此類推咱們算出其餘幾個條件的信息增益爲:Gain(收入)=0.029  Gain(學生)=0.151  Gain(信譽)=0.048$

所以根據按照信息增益最大進行分裂,咱們就選擇了年齡來作爲跟節點進行劃分。

連續型變量

有些細心的人可能已經發現,這裏個人全部的條件(其實應該叫features)都是能夠枚舉的,也就是有限的,但實際過程當中其實像年齡這樣的字段頗有多是1七、1八、20、26等這樣的值,那麼這種狀況下,咱們確定不能在劃分決策樹的時候將全部的年齡都看成一個分枝來劃分開,這樣的話就會過擬合。所以咱們須要選一些關鍵的分割點將年齡劃分開,那麼這個又是怎麼劃分的呢?其實也是求信息熵,具體就是咱們須要找到一個分割點m,當m點的信息熵比m+1和m-1兩邊的信息熵都小的時候咱們就將這個點作爲切分點來劃分。一般作法多是經過二分法來找這個點。求熵的過程我這裏就再也不贅述了。

 

構造決策樹

其實經過前面的講述,咱們已經基本掌握瞭如何去構造一顆決策樹,這裏我再列一下這個過程:

一、全部記錄看做一個節點;
二、遍歷每種特徵的分隔方式,找到最好的分隔點;
三、將數據分隔爲兩個節點部分N1和N2;
四、對N1和N2分別繼續執行2-3步,直到每一個節點中的項知足中止條件:

決策樹算法的中止條件:

一、當每一個子節點只有一種類型的時候中止構建;
二、當前節點中記錄數小於某個閥值,同時迭代次數達到給定值時,中止構建過程;

咱們在實際構造決策樹的過程當中很容易形成樹枝過多,過擬合的問題。好比上面提到的第一中止的方法。通常會採起剪枝法對生成的決策樹進行剪枝。剪枝分爲「前剪枝」和「後剪枝」。前剪枝是在決策樹構造的時候就開始進行,例如上面提到的第二種中止的方法,後剪枝是在決策樹生成完成以後進行的剪枝,具體這裏也先暫時不展開討論了,有興趣的同窗能夠再查閱相關的資料。

常見的決策樹模型有:ID三、C4.五、CART。其實咱們上面講到的利用信息增益來生成決策樹就是ID3模型,另外兩個模型和ID3都是貪心的思路,區別就是使用的是其餘條件來決定跟節點的選取,這裏不敢再展開討論了,不然感受這篇文章寫不完了。後面我能夠單獨再針對這兩個算法看有沒有時間單獨再寫個文章。

最後咱們說一下決策樹的優缺點

優勢:

一、決策樹算法中學習簡單的決策規則創建決策樹模型的過程很是容易理解;
二、決策樹模型能夠可視化,很是直觀;
三、應用範圍廣,可用於分類和迴歸(CART),並且很是容易作多類別的分類;
四、可以處理數值型和連續的樣本特徵

缺點:

一、很容易在訓練數據中生成複雜的樹結構,形成過擬合(overfitting)。(剪枝能夠緩解過擬合的負做用,經常使用方法是限制樹的高度、葉子節點中的最少樣本數量。)
二、決策樹是基於啓發式的貪心算法創建的,這種算法不能保證創建全局最優的決策樹。(隨機森林Random Forest 引入隨機能緩解這個問題。)

 

代碼

若是理解了上面的過程去實現一個決策樹的算法代碼其實並非很難,可是這裏我不打算說這個代碼的事情,由於有不少優秀的三方庫已經幫咱們作好了這個的封裝。例如scikit-learn,安裝過程能夠自行搜索,我這裏也先不說了。我說下在程序處理過程當中的一個小步驟。

one-hot編碼

咱們在使用三方庫調用的時候,在傳入參數的時候不能直接傳入青年,中年這樣的內容,由於機器是沒法識別的,那麼針對枚舉這樣的類型須要怎麼來搞呢?特徵工程中講到咱們能夠將年齡劃分爲青年、中年、老年那麼青年的表示方法就是100,中年是010,老年是001。也就是將以前是一個字段的裂變成來三個字段以0、1的形式傳遞給算法去進行處理。好看代碼:

# -×- encoding=utf-8 -*-
from sklearn.feature_extraction import DictVectorizer
import csv
from sklearn import preprocessing
from sklearn import tree
from sklearn.externals.six import StringIO

# 從csv中將上面例子中的數據讀出來
allElectronicsData = open('play.csv','rb')
reader = csv.reader(allElectronicsData)
header=reader.next()

print(header)

featureList=[]
labelList=[]

for row in reader:
    labelList.append(row[len(row)-1])
    rowDict={}
    for i in range(1,len(row)-1):
        rowDict[header[i]]=row[i]
        
    featureList.append(rowDict)
# featureList 構造出來是一個相似jsonArray的東西
print(featureList)

# 轉爲one-hot編碼
vec = DictVectorizer()
dumpyX = vec.fit_transform(featureList).toarray()

print("dunmpyX "+ str(dumpyX) )
print("feature_name"+str(vec.get_feature_names()))

print("labelList "+ str(labelList))

#vectorize class lables
lb = preprocessing.LabelBinarizer()
dummyY = lb.fit_transform(labelList)
print("dummyY:" +str(dummyY))


# 注意這裏entropy就是表明使用信息增益來構造決策樹
clf = tree.DecisionTreeClassifier(criterion='entropy')
clf = clf.fit(dumpyX,dummyY) #構造決策樹

# 打印構造決策樹採用的參數
print("clf : "+str(clf))


# 驗證數據,取一行數據,修改幾個屬性預測結果
oneRowX=dumpyX[0,:]
print("oneRowX: "+str(oneRowX))

newRowX = oneRowX
newRowX[0]=1
newRowX[2]=0
print("newRowX:"+str(newRowX))

predictedY = clf.predict(newRowX)
print("predictedY:"+str(predictedY))

在寫本篇文章的時候,越寫愈加現裏面的東西比較多,若是所有展開講可能會有很是多的內容,因此不少地方都是簡略帶過,因此若是想了解細節知識的讀者能夠下來再單獨研究~

相關文章
相關標籤/搜索