決策樹分類的實例

谷歌、百度或許搜到了很多關(guān)于決策樹的文章(回歸又可以分類的)。好吧,不喜歡看那些公式的朋友請看這里:


這就是一個決策樹,一顆可以根據(jù)策略將數(shù)據(jù)集分成類別的樹。。。。。。(這個解釋是low點哈)

附上一個簡單實例的代碼實現(xiàn):

from sklearn.datasets import load_iris,load_breast_cancer

from sklearn.tree import DecisionTreeClassifier

from sklearn.tree import export_graphviz

import pydotplus

iris = load_iris( )

clf = DecisionTreeClassifier( )

clf_iris = clf.fit(iris.data,iris.target)

dot_Data = export_graphviz(clf_iris,out_file=None)

graph_iris = pydotplus.graph_from_dot_data(dot_Data)

graph_iris.write_pdf("./load_iris.pdf")

結(jié)果如下:

決策樹比較官方的解釋是:決策樹是廣泛用于分類和回歸任務的模型。本質(zhì)上,它從一層層的if/else問題中進行學習,并得出結(jié)論。決策樹有兩個優(yōu)點:一是得到的模型很容易可視化,非專家也很容易理解(至少對于較小的樹而言)。二是算法完全不受數(shù)據(jù)縮放的影響。由于每個特征被單獨處理,而且數(shù)據(jù)的劃分也不依賴于縮放,因此決策樹算法不需要特征預處理,比如歸一化或標準化。特別是特征的尺度完全不一樣時或者二元特征和連續(xù)特征同時存在時,決策樹的效果很好。決策樹的主要缺點在于,即使做了預剪枝,它也經(jīng)常會過擬合,泛化性能很差。因此,在大多數(shù)應用中,往往使用集成方法來替代單棵決策樹。下面解釋過擬合和預剪枝。

過擬合:通俗的理解就是生成的決策樹(模型)對訓練數(shù)據(jù)集的依賴性很高,當這樣一個完全針對某一訓練集而生成的模型面對訓練數(shù)據(jù)時的準確度是完全可以達到100%的,但是如果面對其他測試集可能錯誤率也會很高,比如下圖:


上面的模型確實可以非常完美的將圓形和三角形完全的分開(模型其實就是那些直線),但是這種模型很顯然是對訓練數(shù)據(jù)依賴性很高的。再看另外一幅圖片。


很顯然這個模型并沒有把所有的數(shù)據(jù)完美的區(qū)分開,但是對于其它測試數(shù)據(jù)而言,錯誤率可能要比第一個模型要小很多了,也就是說第二個模型泛化能力更好。

那么我們怎們能更好的讓模型的泛化能力更強呢?答案是預剪枝。預剪枝的限制條件可能包括限制樹的最大深度、限制葉結(jié)點的最大數(shù)目, 或者規(guī)定一個結(jié)點中數(shù)據(jù)點的最小數(shù)目來防止繼續(xù)劃分等,這些在DecisionTreeClassifier的參數(shù)中就可以選擇。下面就是介紹DecisionTreeClassifier參數(shù)嘍~

在sklearn的官網(wǎng)中有給出,如下:

class?sklearn.tree.DecisionTreeClassifier(criterion='gini',?splitter='best',?max_depth=None,?min_samples_split=2,min_samples_leaf =1,?min_weight_fraction_leaf=0.0,?max_features=None,?random_state=None,?max_leaf_nodes=None,class_weight=None,?presort=False)

特征選擇標準criterion:string類型,可以使用"gini"或者"entropy",前者代表基尼系數(shù),后者代表信息增益。一般說使用默認的基尼系數(shù)"gini"就可以了,即CART算法。除非你更喜歡類似ID3, C4.5的最優(yōu)特征選擇方法。

特征劃分點選擇標準splitter:string類型,可以使用"best"或者"random"。前者在特征的所有劃分點中找出最優(yōu)的劃分點。后者是隨機的在部分劃分點中找局部最優(yōu)的劃分點。默認的"best"適合樣本量不大的時候,而如果樣本數(shù)據(jù)量非常大,此時決策樹構(gòu)建推薦"random"?

劃分時考慮的最大特征數(shù)max_features:int,float,string or None??梢允褂煤芏喾N類型的值,默認是"None"意味著劃分時考慮所有的特征數(shù);如果是"log2"意味著劃分時最多考慮log2N個特征;如果是"sqrt"或者"auto"意味著劃分時最多考慮N^(1/2)個特征。如果是整數(shù),代表考慮的特征絕對數(shù)。如果是浮點數(shù),代表考慮特征百分比,即考慮(百分比xN)取整后的特征數(shù)。其中N為樣本總特征數(shù)。一般來說,如果樣本特征數(shù)不多,比如小于50,我們用默認的"None"就可以了,如果特征數(shù)非常多,我們可以靈活使用剛才描述的其他取值來控制劃分時考慮的最大特征數(shù),以控制決策樹的生成時間。

??? 1.如果是int,在每次分類是都要考慮max_features個特征。

??? 2.如果是float,那么max_features是一個百分率并且分類時需要考慮的特征數(shù)是int(max_features*n_features,其中n_features是訓練完成時發(fā)特征數(shù))。

??? 3.如果是auto,max_features=auto(n_features)

??? 4.如果是sqrt,max_features=sqrt(n_features)

??? 5.如果是log2,max_features=log2(n_features)

??? 6.如果是None,max_features=n_features

決策樹最大深max_depth:int or None。決策樹的最大深度,默認可以不輸入,如果不輸入的話,決策樹在建立子樹的時候不會限制子樹的深度。一般來說,數(shù)據(jù)少或者特征少的時候可以不管這個值。如果模型樣本量多,特征也多的情況下,推薦限制這個最大深度,具體的取值取決于數(shù)據(jù)的分布。常用的可以取值50-100之間。

內(nèi)部節(jié)點再劃分所需最小樣本數(shù)min_samples_spli:int,float。這個值限制了子樹繼續(xù)劃分的條件,如果某節(jié)點的樣本數(shù)少于min_samples_split,則不會繼續(xù)再嘗試選擇最優(yōu)特征來進行劃分。?默認是2.如果樣本量不大,不需要管這個值。如果樣本量數(shù)量級非常大,則推薦增大這個值。我之前的一個項目例子,有大概10萬樣本,建立決策樹時,可以選擇min_samples_split=10。

葉子節(jié)點最少樣本數(shù)min_samples_leaf:int,float。這個值限制了葉子節(jié)點最少的樣本數(shù),如果某葉子節(jié)點數(shù)目小于樣本數(shù),則會和兄弟節(jié)點一起被剪枝。?默認是1,可以輸入最少的樣本數(shù)的整數(shù),或者最少樣本數(shù)占樣本總數(shù)的百分比。如果樣本量不大,不需要管這個值。如果樣本量數(shù)量級非常大,則推薦增大這個值。之前的10萬樣本項目使用min_samples_leaf的值為5。

葉子節(jié)點最小的樣本權(quán)重和min_weight_fraction_lea:float。這個值限制了葉子節(jié)點所有樣本權(quán)重和的最小值,如果小于這個值,則會和兄弟節(jié)點一起被剪枝。?默認是0,就是不考慮權(quán)重問題。一般來說,如果我們有較多樣本有缺失值,或者分類樹樣本的分布類別偏差很大,就會引入樣本權(quán)重,這時我們就要注意這個值。

最大葉子節(jié)點數(shù)max_leaf_nodes:int,None。通過限制最大葉子節(jié)點數(shù),可以防止過擬合,默認是"None”,即不限制最大的葉子節(jié)點數(shù)。如果加了限制,算法會建立在最大葉子節(jié)點數(shù)內(nèi)最優(yōu)的決策樹。如果特征不多,可以不考慮這個值,但是如果特征分成多的話,可以加以限制,具體的值可以通過交叉驗證得到。

類別權(quán)重class_weight:dict,list of dicts,"Banlanced" or None。指定樣本各類別的的權(quán)重,主要是為了防止訓練集某些類別的樣本過多,導致訓練的決策樹過于偏向這些類別。這里可以自己指定各個樣本的權(quán)重,或者用“balanced”,如果使用“balanced”,則算法會自己計算權(quán)重,樣本量少的類別所對應的樣本權(quán)重會高。當然,如果你的樣本類別分布沒有明顯的偏倚,則可以不管這個參數(shù),選擇默認的"None"

節(jié)點劃分最小不純度min_impurity_split:這個值限制了決策樹的增長,如果某節(jié)點的不純度(基尼系數(shù),信息增益,均方差,絕對差)小于這個閾值,則該節(jié)點不再生成子節(jié)點,即為葉子節(jié)點?。

數(shù)據(jù)是否預排序presort:這個值是布爾值,默認是False不排序。一般來說,如果樣本量少或者限制了一個深度很小的決策樹,設置為true可以讓劃分點選擇更加快,決策樹建立的更加快。如果樣本量太大的話,反而沒有什么好處。問題是樣本量少的時候,我速度本來就不慢。所以這個值不處理就可以了。

除了這些參數(shù)要注意以外,其他在調(diào)參時的注意點有:

    1)當樣本少數(shù)量但是樣本特征非常多的時候,決策樹很容易過擬合,一般來說,樣本數(shù)比特征數(shù)多一些會比較容易建立健壯的模型

    2)如果樣本數(shù)量少但是樣本特征非常多,在擬合決策樹模型前,推薦先做維度規(guī)約,比如主成分分析(PCA),特征選擇(Losso)或者獨立成分分析(ICA)。這樣特征的維度會大大減小。再來擬合決策樹模型效果會好。

    3)推薦多用決策樹的可視化,同時先限制決策樹的深度,這樣可以先觀察下生成的決策樹里數(shù)據(jù)的初步擬合情況,然后再決定是否要增加深度。

    4)在訓練模型先,注意觀察樣本的類別情況(主要指分類樹),如果類別分布非常不均勻,就要考慮用class_weight來限制模型過于偏向樣本多的類別。

    5)決策樹的數(shù)組使用的是numpy的float32類型,如果訓練數(shù)據(jù)不是這樣的格式,算法會先做copy再運行。

    6)如果輸入的樣本矩陣是稀疏的,推薦在擬合前調(diào)用csc_matrix稀疏化,在預測前調(diào)用csr_matrix稀疏化。

下面以乳腺癌數(shù)據(jù)集寫一個簡單的實例并每個特征的重要程度以及模型打印成pdf:

from sklearn.model_selection import train_test_split

from sklearn.datasets import load_iris,load_breast_cancer

from sklearn.tree import DecisionTreeClassifier

from sklearn.tree import export_graphviz

import numpy as np

import matplotlib.pyplot as plt

import pydotplus

import graphviz

iris = load_iris()

cancer = load_breast_cancer()

clf = DecisionTreeClassifier(max_depth=7)

clf_iris = clf.fit(iris.data,iris.target)

clf_cancer = clf.fit(cancer.data,cancer.target)

#print("cancer.keys(): \n{}".format(cancer.keys()))

#print(cancer.target)

#print("{}".format({n:v for n,v in zip(cancer.target_names,np.bincount(cancer.target))}))

x_train,x_test,y_train,y_test = train_test_split(cancer.data,cancer.target,test_size=0.3,random_state=1)

clf_DT??= clf.fit(x_train,y_train)

print("{:.3f}".format(clf_DT.score(x_train,y_train)))

print("{:.3f}".format(clf_DT.score(x_test,y_test)))

export_graphviz(clf_DT,out_file="./DT.dot",class_names=['malignant','benign'],feature_names=cancer.feature_names,impurity=False,filled=True)

print("{}".format(clf_DT.feature_importances_))

print(cancer.data.shape[0])

def polt_feature_importances_cancer(model):

????feature_count = cancer.data.shape[1]

????plt.barh(range(feature_count),model.feature_importances_,align='center')

????plt.yticks(np.arange(feature_count),cancer.feature_names)

????plt.xlabel("Feature importance")

????plt.ylabel("Feature")

????plt.show()

polt_feature_importances_cancer(clf_DT)

結(jié)果如下:

可以看出來第22個特征worst perimeter的劃分能力最強,模型中第一個用到的也是x[22]。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容