1. 程式人生 > >通俗地說決策樹演算法(三)sklearn決策樹實戰

通俗地說決策樹演算法(三)sklearn決策樹實戰

前情提要

通俗地說決策樹演算法(一)基礎概念介紹

通俗地說決策樹演算法(二)例項解析

上面兩篇介紹了那麼多決策樹的知識,現在也是時候來實踐一下了。Python有一個著名的機器學習框架,叫sklearn。我們可以用sklearn來執行前面說到的賴床的例子。不過在這之前,我們需要介紹一下sklearn中訓練一顆決策樹的具體引數。

另外sklearn中訓練決策樹的預設演算法是CART,使用CART決策樹的好處是可以用它來進行迴歸和分類處理,不過這裡我們只進行分類處理。

一. sklearn決策樹引數詳解

我們都知道,一個模型中很重要的一步是調參。在sklearn中,模型的引數是通過方法引數來決定的,以下給出sklearn中,決策樹的引數:

DecisionTreeClassifier(criterion="gini",
                 splitter="best",
                 max_depth=None,
                 min_samples_split=2,
                 min_samples_leaf=1,
                 min_weight_fraction_leaf=0.,
                 max_features=None,
                 random_state=None,
                 max_leaf_nodes=None,
                 min_impurity_decrease=0.,
                 min_impurity_split=None,
                 class_weight=None,
                 presort=False)

引數含義:
1.criterion:string, optional (default="gini")
            (1).criterion='gini',分裂節點時評價準則是Gini指數。
            (2).criterion='entropy',分裂節點時的評價指標是資訊增益。
2.max_depth:int or None, optional (default=None)。指定樹的最大深度。
            如果為None,表示樹的深度不限。直到所有的葉子節點都是純淨的,即葉子節點
            中所有的樣本點都屬於同一個類別。或者每個葉子節點包含的樣本數小於min_samples_split。
3.splitter:string, optional (default="best")。指定分裂節點時的策略。
           (1).splitter='best',表示選擇最優的分裂策略。
           (2).splitter='random',表示選擇最好的隨機切分策略。
4.min_samples_split:int, float, optional (default=2)。表示分裂一個內部節點需要的做少樣本數。
           (1).如果為整數,則min_samples_split就是最少樣本數。
           (2).如果為浮點數(0到1之間),則每次分裂最少樣本數為ceil(min_samples_split * n_samples)
5.min_samples_leaf: int, float, optional (default=1)。指定每個葉子節點需要的最少樣本數。
           (1).如果為整數,則min_samples_split就是最少樣本數。
           (2).如果為浮點數(0到1之間),則每個葉子節點最少樣本數為ceil(min_samples_leaf * n_samples)
6.min_weight_fraction_leaf:float, optional (default=0.)
           指定葉子節點中樣本的最小權重。
7.max_features:int, float, string or None, optional (default=None).
           搜尋最佳劃分的時候考慮的特徵數量。
           (1).如果為整數,每次分裂只考慮max_features個特徵。
           (2).如果為浮點數(0到1之間),每次切分只考慮int(max_features * n_features)個特徵。
           (3).如果為'auto'或者'sqrt',則每次切分只考慮sqrt(n_features)個特徵
           (4).如果為'log2',則每次切分只考慮log2(n_features)個特徵。
           (5).如果為None,則每次切分考慮n_features個特徵。
           (6).如果已經考慮了max_features個特徵,但還是沒有找到一個有效的切分,那麼還會繼續尋找
           下一個特徵,直到找到一個有效的切分為止。
8.random_state:int, RandomState instance or None, optional (default=None)
           (1).如果為整數,則它指定了隨機數生成器的種子。
           (2).如果為RandomState例項,則指定了隨機數生成器。
           (3).如果為None,則使用預設的隨機數生成器。
9.max_leaf_nodes: int or None, optional (default=None)。指定了葉子節點的最大數量。
           (1).如果為None,葉子節點數量不限。
           (2).如果為整數,則max_depth被忽略。
10.min_impurity_decrease:float, optional (default=0.)
         如果節點的分裂導致不純度的減少(分裂後樣本比分裂前更加純淨)大於或等於min_impurity_decrease,則分裂該節點。
         加權不純度的減少量計算公式為:
         min_impurity_decrease=N_t / N * (impurity - N_t_R / N_t * right_impurity
                            - N_t_L / N_t * left_impurity)
         其中N是樣本的總數,N_t是當前節點的樣本數,N_t_L是分裂後左子節點的樣本數,
         N_t_R是分裂後右子節點的樣本數。impurity指當前節點的基尼指數,right_impurity指
         分裂後右子節點的基尼指數。left_impurity指分裂後左子節點的基尼指數。
11.min_impurity_split:float
         樹生長過程中早停止的閾值。如果當前節點的不純度高於閾值,節點將分裂,否則它是葉子節點。
         這個引數已經被棄用。用min_impurity_decrease代替了min_impurity_split。
12.class_weight:dict, list of dicts, "balanced" or None, default=None
         類別權重的形式為{class_label: weight}
         (1).如果沒有給出每個類別的權重,則每個類別的權重都為1。
         (2).如果class_weight='balanced',則分類的權重與樣本中每個類別出現的頻率成反比。
         計算公式為:n_samples / (n_classes * np.bincount(y))
         (3).如果sample_weight提供了樣本權重(由fit方法提供),則這些權重都會乘以sample_weight。
13.presort:bool, optional (default=False)
        指定是否需要提前排序資料從而加速訓練中尋找最優切分的過程。設定為True時,對於大資料集
        會減慢總體的訓練過程;但是對於一個小資料集或者設定了最大深度的情況下,會加速訓練過程。

雖然看起來引數眾多,但通常引數都會有預設值,我們只需要調整其中較為重要的幾個引數就行。

通常來說,較為重要的引數有:

  1. criterion:用以設定用資訊熵還是基尼係數計算。
  2. splitter:指定分支模式
  3. max_depth:最大深度,防止過擬合
  4. min_samples_leaf:限定每個節點分枝後子節點至少有多少個數據,否則就不分枝

二. sklearn決策樹實戰

2.1 準備資料及讀取

資料就是上次說到的賴床特徵,
季節 | 時間已過 8 點 | 風力情況 | 要不要賴床
---|---|---|---
spring|no|breeze|yes
winter|no|no wind|yes

autumn|yes|breeze|yes
winter|no|no wind|yes
summer|no|breeze|yes
winter|yes|breeze|yes
winter|no|gale|yes
winter|no|no wind|yes
spring|yes|no wind|no
summer|yes|gale|no
summer|no|gale|no
autumn|yes|breeze|no

將它儲存成 csv 檔案

spring,no,breeze,yes
winter,no,no wind,yes
autumn,yes,breeze,yes
winter,no,no wind,yes
summer,no,breeze,yes
winter,yes,breeze,yes
winter,no,gale,yes
winter,no,no wind,yes
spring,yes,no wind,no
summer,yes,gale,no
summer,no,gale,no
autumn,yes,breeze,no

2.2 決策樹的特徵向量化DictVectorizer

sklearn的DictVectorizer能對字典進行向量化。什麼叫向量化呢?比如說你有季節這個屬性有[春,夏,秋,冬]四個可選值,那麼如果是春季,就可以用[1,0,0,0]表示,夏季就可以用[0,1,0,0]表示。不過在呼叫DictVectorizer它會將這些屬性打亂,不會按照我們的思路來執行,但我們也可以一個方法檢視,我們看看程式碼就明白了。

import pandas as pd
from sklearn.feature_extraction import DictVectorizer
from sklearn import tree
from sklearn.model_selection import train_test_split

#pandas 讀取 csv 檔案,header = None 表示不將首行作為列
data = pd.read_csv('data/laic.csv',header =None)
#指定列
data.columns = ['season','after 8','wind','lay bed']

#sparse=False意思是不產生稀疏矩陣
vec=DictVectorizer(sparse=False)
#先用 pandas 對每行生成字典,然後進行向量化
feature = data[['season','after 8','wind']]
X_train = vec.fit_transform(feature.to_dict(orient='record'))
#列印各個變數
print('show feature\n',feature)
print('show vector\n',X_train)
print('show vector name\n',vec.get_feature_names())

我們來看看列印的結果:

show feature
     season after 8     wind
0   spring      no   breeze
1   winter      no  no wind
2   autumn     yes   breeze
3   winter      no  no wind
4   summer      no   breeze
5   winter     yes   breeze
6   winter      no     gale
7   winter      no  no wind
8   spring     yes  no wind
9   summer     yes     gale
10  summer      no     gale
11  autumn     yes   breeze
show vector
 [[1. 0. 0. 1. 0. 0. 1. 0. 0.]
 [1. 0. 0. 0. 0. 1. 0. 0. 1.]
 [0. 1. 1. 0. 0. 0. 1. 0. 0.]
 [1. 0. 0. 0. 0. 1. 0. 0. 1.]
 [1. 0. 0. 0. 1. 0. 1. 0. 0.]
 [0. 1. 0. 0. 0. 1. 1. 0. 0.]
 [1. 0. 0. 0. 0. 1. 0. 1. 0.]
 [1. 0. 0. 0. 0. 1. 0. 0. 1.]
 [0. 1. 0. 1. 0. 0. 0. 0. 1.]
 [0. 1. 0. 0. 1. 0. 0. 1. 0.]
 [1. 0. 0. 0. 1. 0. 0. 1. 0.]
 [0. 1. 1. 0. 0. 0. 1. 0. 0.]]
show vector name
 ['after 8=no', 'after 8=yes', 'season=autumn', 'season=spring', 'season=summer', 'season=winter', 'wind=breeze', 'wind=gale', 'wind=no wind']

通過DictVectorizer,我們就能夠把字元型的資料,轉化成0 1的矩陣,方便後面進行運算。額外說一句,這種轉換方式其實就是one-hot編碼。

2.4 決策樹訓練

可以發現在向量化的時候,屬性都被打亂了,但我們也可以通過get_feature_names()這個方法檢視對應的屬性值。有了資料後,就可以來訓練一顆決策樹了,用sklearn很方便,只需要很少的程式碼

#劃分成訓練集,交叉集,驗證集,不過這裡我們資料量不夠大,沒必要
#train_x, test_x, train_y, test_y = train_test_split(X_train, Y_train, test_size = 0.3)
#訓練決策樹
clf = tree.DecisionTreeClassifier(criterion='gini')
clf.fit(X_train,Y_train)

#儲存成 dot 檔案,後面可以用 dot out.dot -T pdf -o out.pdf 轉換成圖片
with open("out.dot", 'w') as f :
    f = tree.export_graphviz(clf, out_file = f,
            feature_names = vec.get_feature_names())

2.5 決策樹視覺化

當完成一棵樹的訓練的時候,我們也可以讓它視覺化展示出來,不過sklearn沒有提供這種功能,它僅僅能夠讓訓練的模型儲存到dot檔案中。但我們可以藉助其他工具讓模型視覺化,先看儲存到dot的程式碼:

from sklearn import tree
with open("out.dot", 'w') as f :
    f = tree.export_graphviz(clf, out_file = f,
            feature_names = vec.get_feature_names())

決策樹視覺化我們用Graphviz這個東西。當然需要先用pip安裝對應的庫類。然後再去官網下載它的一個發行版本,用以將dot檔案轉化成pdf圖片。

官網下載方式如下:

然後進入到上面儲存好的dot所在目錄,開啟cmd執行dot out.dot -T pdf -o out.pdf 命令,pdf 圖片就會出現了。

小結:

今天我們介紹了sklearn,決策樹模型的各個引數,並且使用sklearn模型對上一節中的例子訓練出一個決策樹模型,然後用Graphviz讓決策樹模型視覺化。到此,決策樹演算法算是講完啦。