1. 程式人生 > >統計學習方法--決策樹 python實現

統計學習方法--決策樹 python實現

決策樹模型與學習

決策樹模型是一種描述對視力進項分類的樹形結構。決策樹由節點和有邊組成,節點有兩種:內部節點和葉節點。內節點表示一個特徵或的戶型,葉節點表示一個類。

用決策樹分類,從根節點開始,對例項的某一特徵進行測試,根據測試結構,將實力分配到其子節點;這時每一個子節點對應著該特徵的一個取值,如此遞迴地對例項進行測試並分配,直到達到葉節點,最後將例項分到葉節點的類中。

決策樹與if——then規則

 可以講決策樹看成一個if-then規則的集合

將決策樹轉換成if-then規則的過程:

由決策樹的根節點到夜間點每一條路徑構建一條規則路徑上內部節點的特徵對應著規則的條件,而葉節點的類對應著規則的結論 。決策樹的路徑或對於飛if-then規則集合具有一個重要的性質互斥 並且完備

每一個例項都被一條路徑活一天規則覆蓋只被一條路徑或一條規則覆蓋

決策樹還表示給定條件下的條件概率分佈

決策樹學習

決策樹學習的目標是根據給定的訓練資料集構建一個決策樹模型,是他能夠對例項進行正確的分類

決策樹學習的本質就是行迅雷資料集中歸納出一組分類規則名譽訓練資料集不想毛段的決策樹,可能有多個  也可能有一個,我們需要的是與訓練資料矛盾較小的決策樹,同時具有很好的泛化能力。從另一個角度看  決策樹學習是由訓練資料估計條件概率模型

我們最後選擇的天津啊概率模型應該不僅負罪訓練資料有很好的擬合,而且對未知資料有很好的預測

決策樹學習用損失函式表示這一目標

通常用正則化的 極大似然函式來估計損失函式   決策樹的學習策略就是以損失函式為目標函式的最小化。

決策樹的學習演算法是採用啟發式方法,近似求解這一最優化問題,所以得到的結果是次最優

決策樹的學習演算法通常是一個遞迴地選擇最優特徵,並根據該特徵對訓練資料進行分割,使得對各個子資料集有一個最好的分類過程,

這一過程對應著對特徵空間的劃分,也對應著決策樹的構建

1,  構建根節點將所有訓練資料都放在根節點

2,  選擇一個最有特徵,按照這一特徵將訓練資料集分割成自己,使得每個子集都有一個在當前條件下最好的分類。

3,  如果這些子集已經能夠被基本正確分類,那麼構建葉節點

4,  如果還有子集沒有被正確分類,那麼就對這些子集選擇新的最有特徵,繼續對其進行分割,直到沒有合適的特徵為止。

5,  最後每個子集都被分到也節點上 就生產了一顆決策樹

上面的決策樹可能對訓練資料有很好的分類能力,但是泛化能力可能很差,即發生了過擬合現象,我們需要對已生產的樹進行修剪

如果特徵數量很多也可以在決策樹學習的開始就對特徵進行選擇,值選擇對訓練資料有足夠分類能力的特徵

決策樹的學習演算法包含特徵選擇,決策樹生成   決策樹修剪三個過程

特徵的選擇:

決策樹學習應用資訊增益準確來選擇特徵,跟定的訓練資料集D和特徵A,經驗熵H(D)表示對資料集D進行分類的不確定性,而經驗條件熵H(D|A)表示在特徵A給定的條件下對資料集進行分類的不確定性。他們的差就是資訊增益,就表示由於特徵A而使對資料集D的分類的不確定性減少的程度

對於資料集D而言,資訊增益依賴於特徵,不同特徵問問具有不同的資訊增益,資訊箱增益大的特徵具有更強的分類能力

方法:對訓練資料集或者其子集,計算沒個特特徵的資訊增益,並比較他們的大小,選擇資訊增益最大的特徵。

 

資訊增益比

資訊增益值的大小是相對於訓練資料集而言的,並沒有絕對的意義,當分類問題困難時也就是訓練資料集的經驗熵大的時候,資訊增益值會偏大,繁殖資訊增益值會偏下,使用資訊增益比可以對這一問題進行校正


決策樹的生成

ID3

核心是在決策樹各個節點上應用資訊增益準則選擇特徵,遞迴地構建決策樹。

具體步驟:從根節點(root node)開始,對節點計算多有可能的特徵的資訊增益,選擇資訊增益最大的特徵作為節點的特徵,對由該特徵的不同取值建立子節點;再對子節點遞迴地呼叫以上方法,構建決策樹;知道所有特徵的資訊增益均很小或沒有特徵可以選擇位置。最後得到一個決策樹。

相對於用極大似然法進行概率模型的選擇


ID3演算法只有數的生成,所以該演算法生成的樹容易產生過擬合。

二、C4.5的生成演算法

C4,5演算法與ID3演算法相似,C4.5演算法對ID3演算法進行了改進。C4.5在生成的過程中,用資訊增益比來選擇特徵

 

決策樹的剪枝

決策樹生成演算法遞迴地產生決策樹,直到不能繼續下去為止。這樣產生的樹往往對訓練資料的分類很準確,但是對位置的測試資料的分類卻沒有那麼準確,即出現過擬合現象,過擬合的原因在於學習時過多地考慮如何提高訓練資料的正確分類,從而構建出過於複雜的決策樹。解決這個問題的辦法就是考慮決策樹的複雜度,對已生成的決策樹進行簡化,

在決策樹學習中將已生成決策資料的簡化過程稱為剪枝pruning。

剪枝從已生成的樹上裁掉一些子樹或葉節點,並將其根節點或父節點作為新的葉節點,從而簡化分類樹模型。

決策樹的剪枝往往通過及消化決策樹整體的而損失函式LOSS FUNCTION或代價函式cost function來實現,設樹T的葉節點個數為|T|,t是樹T的葉節點,該葉節點有個樣本點,其中K類的樣本點有個,k=1,2,…K,其中為葉節點t上的經驗熵,α≥0為引數,則決策樹學習的損失函式可以定義為

C(T)表示模型對訓練資料的預測誤差,即模型與訓練資料的擬合程度,|T|表示模型複雜度,引數α≥0控制兩種之間的影響,較大的α促使選擇較簡單的樹,較小的α促使選擇較複雜的樹。α=0意味著只考慮模型與訓練資料的擬合程度,不考慮模型的複雜度。

剪枝就是當α確定時,選擇損失函式最小的模型,即損失函式最小的子樹。當α值確定時,子樹越大,往往與訓練資料的擬合越好,但是模型的複雜度就越高;相反,子樹越小,模型的複雜度就越低,但是往往與訓練資料的擬合不好,損失函式正好表示了對兩者的平衡。

決策樹生成只考慮了通過提高資訊增益或者資訊增益比對訓練資料進行更好的擬合。而決策樹剪枝通過優化損失函式還考慮了見笑模型複雜度。決策樹生成學習區域性的模型,而決策樹剪枝學習整體的模型。

公式1和4定義的損失函式的極小化等價於正則化的極大似然估計。所以,利用損失函式最小化原則進行剪枝就是用正則化的極大似然估計進行模型選擇。

樹的剪枝演算法

輸入:生成演算法產生的整個樹T,單數α;

輸出:修剪後的子樹


三、CART演算法

分類classification與迴歸樹regression tree模型是一種廣泛的決策樹學習方法們CART同樣由特種選擇、樹的生成及剪枝組成,既可以用於分類也可以用於迴歸

CART是在給定輸入隨機變數C條件下輸出隨機變數Y的條件概率分佈的學習方法。CART假設決策樹是二分叉,內部節點特種的取值為“是”“否,左側分支是趨勢為“是”的分支,,有分支是取值為“否”的分支。這樣的決策樹等價於遞迴地微分每個特徵,將輸入控制元件即特徵空間劃分為有限個單元,並在這些單元上確定預測的概率分佈,也就是在輸入給定的條件下輸出的條件概率分佈

CART演算法由兩步組成:

1決策樹的生成  基於訓練資料及生成決策樹,生成 的決策樹要儘量大;

2決策樹剪枝:用驗證資料及對已生成的樹進行剪枝並選擇最優子樹,這是用損失函式最小作為剪枝的標準

CART生成

決策樹的生成就是遞迴地構建二叉決策樹的過程。對迴歸樹用平方誤差最小化準則,對分類樹用基尼指數GINI Index最小化準則,進行特徵選擇,生成二叉樹,

選擇第j個變數和他的取值作為切分變數和切分點,並定義兩個區域,


劃分為兩個區域。接著,對每個區域重複上述劃分過程,直到滿足停止條件為止,這樣就生產了一顆迴歸樹。這樣的迴歸樹通常稱為最小二乘法迴歸樹。

演算法敘述(最小二乘迴歸樹生產演算法)如下:

 

2分類樹的生成

分類樹使用基尼指數選擇最優特徵,同時決定該特徵的最優二值切分點。

什麼是基尼係數?

分類問題中,假設有K個類,樣本點屬於第K類的概率為,則概率分佈的基尼係數定義為:


對於二分類問題,若樣本點屬於第1個類的概率為P,則概率分佈的基尼係數為


對於給定的樣本集合D,其基尼指數為


這裡是D中屬於第K類的樣本集,K是類的個數。


上圖顯示二分類問題中基尼係數Gini(p)、熵之半和二分類誤差率的關係,基尼係數與熵之半的曲線很接近。

CART生成演算法

輸入:訓練資料集D,停止計算的條件

輸出:CART決策樹

CART剪枝

CART的剪枝演算法從“完全生長”的決策樹的底端減去一些子樹,是決策樹變小,從而能夠對位置資料有更準確的預測。

CART剪枝演算法分兩步:1 從生成演算法產生的決策樹的底端開始不斷剪枝,知道其根節點形成一個子樹序列;2通過交叉驗證法在獨立的驗證資料集上對子樹序列進行測試,從而選擇最優子樹

# -*- coding: utf-8 -*-
"""
Created on Mon Oct 23 16:24:07 2017

@author: lizheng
"""

# 引入必要的模型和庫
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree

from sklearn.externals.six import StringIO
import pydotplus

    
    
   
with open('D:\Iris.txt', 'r') as f:  
    iris = [inst.strip().split(',') for inst in f.readlines()]  
    lenses_target = []
    lenses_data = []
    for line in iris:  
        lenses_target.append(line[-1])
        lenses_data.append(line[:3])
from sklearn.cross_validation import train_test_split  #這裡是引用了交叉驗證          
X_train,X_test, y_train, y_test = train_test_split(lenses_data,lenses_target, random_state=1)#將資料隨機分成訓練集和測試集  
# =============================================================================
# print(X_train)  
# print(X_test)
# print(y_train)  
# print(y_test)
# =============================================================================
# 解析資料,獲得 features 資料
#clf = DecisionTreeClassifier()

clf = DecisionTreeClassifier()  
clf = clf.fit(X_train, y_train)  
dot_data = StringIO()
tree.export_graphviz(clf, out_file = dot_data,                            #繪製決策樹
                   
                    class_names = clf.classes_,
                    filled=True, rounded=True,
                    special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
graph.write_pdf("D:\\MLiA_SourceCode\\machinelearninginaction\\Ch03\\tree2.pdf")

from sklearn.model_selection import cross_val_score#交叉驗證模組
scores =cross_val_score(clf,X_test, y_test,cv=10)#驗證評估  cv 迭代次數 
print(scores.mean())#平均精確度

# =============================================================================
# pre_labels=clf.predict(X_test)  
# print(pre_labels)
# =============================================================================
#手動計算正確率
import numpy  as np
CorrectNnumber = 0

for i in  range(len(X_test)):
    if clf.predict(np.array(X_test[i]).reshape((1,-1))) == y_test[i]:
# =============================================================================
#  此處predict()引數要求是陣列,所繫需要把列別predictions轉換成陣列,
#  然後把把一維陣列通過reshape改造 ,否則會有報警     
# =============================================================================
        CorrectNnumber+=1
        
print("正確率為:",CorrectNnumber/len(X_test))

import numpy  as np
CorrectNnumberX = 0
for j in  range(len(lenses_data)):
    if clf.predict(np.array(lenses_data[j]).reshape((1,-1))) == lenses_target[j]:
        CorrectNnumberX+=1
print("正確率為:",CorrectNnumberX/len(lenses_data))
# =============================================================================
# recall_score
# 召回率 =提取出的正確資訊條數 /樣本中的資訊條數。通俗地說,就是所有準確的條目有多少被檢索出來了。
# 形式:
# klearn.metrics.recall_score(y_true, y_pred, labels=None, pos_label=1,average='binary', sample_weight=None)
# 引數average : string, [None, ‘micro’, ‘macro’(default), ‘samples’, ‘weighted’]
# 將一個二分類matrics拓展到多分類或多標籤問題時,我們可以將資料看成多個二分類問題的集合,每個類都是一個二分類。接著,我們可以通過跨多個分類計算每個二分類metrics得分的均值,這在一些情況下很有用。你可以使用average引數來指定。
# macro:計算二分類metrics的均值,為每個類給出相同權重的分值。當小類很重要時會出問題,因為該macro-averging方法是對效能的平均。另一方面,該方法假設所有分類都是一樣重要的,因此macro-averaging方法會對小類的效能影響很大。
# weighted:對於不均衡數量的類來說,計算二分類metrics的平均,通過在每個類的score上進行加權實現。
# micro:給出了每個樣本類以及它對整個metrics的貢獻的pair(sample-weight),而非對整個類的metrics求和,它會每個類的metrics上的權重及因子進行求和,來計算整個份額。Micro-averaging方法在多標籤(multilabel)問題中設定,包含多分類,此時,大類將被忽略。
# samples:應用在multilabel問題上。它不會計算每個類,相反,它會在評估資料中,通過計算真實類和預測類的差異的metrics,來求平均(sample_weight-weighted)
# average:average=None將返回一個數組,它包含了每個類的得分. 
# =============================================================================
from sklearn.metrics import recall_score
recall_score(y_train, clf.predict(X_train),average='macro')  
# =============================================================================
# accuracy_score
# 分類準確率分數是指所有分類正確的百分比。分類準確率這一衡量分類器的標準比較容易理解,但是它不能告訴你響應值的潛在分佈,並且它也不能告訴你分類器犯錯的型別。
# 形式:
# sklearn.metrics.accuracy_score(y_true, y_pred, normalize=True, sample_weight=None)
# normalize:預設值為True,返回正確分類的比例;如果為False,返回正確分類的樣本數
# =============================================================================
from sklearn import metrics
print(metrics.accuracy_score(y_test, clf.predict(X_test)))