前言
決策樹是機器學習中的一種常用算法。相關數學理論我也曾在數學模組化專欄中數學模組化學習筆記(二十五)決策樹
介紹過,本篇博文不注重相關數學原理,主要注重使用sklearn實作分類樹的效果。
參考課程見【2020機器學習全集】菜菜的sklearn完整版
決策樹簡介
決策樹(Decision Tree)是一種非參數的有監督學習方法,它能夠從一系列有特征和标簽的資料中總結出決策規則,并用樹狀圖的結構來呈現這些規則,以解決分類和回歸問題。
sklearn中的決策樹
- 子產品sklearn.tree
樹類型 | 庫表示 |
---|---|
分類樹 | tree.DecisionTreeClassifier |
回歸樹 | tree.DecisionTreeRegressor |
生成的決策樹導出為DOT格式,畫圖專用 | tree.export_graphviz |
高随機版本的分類樹 | tree.ExtraTreeClassifier |
高随機版本的回歸樹 | tree.ExtraTreeRegressor |
sklearn的基本模組化流程
對應python代碼
from sklearn import tree #導入需要的子產品
clf = tree.DecisionTreeClassifier() #執行個體化
clf = clf.fit(X_train,y_train) #用訓練集資料訓練模型
result = clf.score(X_test,y_test) #導入測試集,從接口中調用需要的資訊
分類樹 DecisionTreeClassifier
重要參數
criterion 決定不純度的計算方法
為了要将表格轉化為一棵樹,決策樹需要找出最佳節點和最佳的分枝方法,對分類樹來說,衡量這個“最佳”的名額叫做“不純度”。通常來說,不純度越低,決策樹對訓練集的拟合越好。
通俗了解:為了将一群混在一起的複雜樣本分開,用不純度來進行衡量,沒分之前,也就是根節點,不純度最高,之後越往下面不純度越低,到葉子節點,就完全分離開,不純度最低,得到的結果最“純淨”!
Criterion這個參數正是用來決定不純度的計算方法的。sklearn提供了兩種選擇:
1)輸入”entropy“,使用資訊熵(Entropy)
2)輸入”gini“,使用基尼系數(Gini Impurity)
不填寫,預設的是gini。
sklearn實際計算的是基于資訊熵的資訊增益(Information Gain),即父節點的資訊熵和子節點的資訊熵之差。
選取規則:
通常就使用基尼系數
資料次元很大,噪音很大時使用基尼系數
次元低,資料比較清晰的時候,資訊熵和基尼系數沒差別
當決策樹的拟合程度不夠的時候,使用資訊熵
兩個都試試,不好就換另外一個
建立分類樹步驟
1.導入需要的算法庫和子產品
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
import pandas as pd
import graphviz
2.檢視資料
這裡使用的是sklearn自帶的wine資料集。
wine = load_wine()
print(wine.data.shape)
print(pd.concat([pd.DataFrame(wine.data), pd.DataFrame(wine.target)], axis=1))
print(wine.feature_names)
print(wine.target_names)
總共178條資料,3分類問題。
3.劃分訓練集和測試集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
print(Xtrain.shape)
print(Xtest.shape)
test_size=0.3表示測試集占樣本數量的30%
劃分之後,訓練集為124條資料,測試集為54條資料。
4.模型建立
clf = tree.DecisionTreeClassifier(criterion="entropy")
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) # 傳回預測的準确度
print(score)
這裡選用資訊熵entropy作為計算方法。
score代表準确度
由于決策樹的建立包含随機變量,每次運作結果都不一樣。
這裡我運作幾次大緻結果準确率在90%以上。
5.決策樹可視化
feature_name = ['酒精','蘋果酸','灰','灰的堿性','鎂','總酚','類黃酮','非黃烷類酚類','花青素','顔色強度','色調','od280/od315稀釋葡萄酒','脯氨酸']
dot_data = tree.export_graphviz(clf
,feature_names= feature_name
,class_names=["類型一","類型二","類型三"]
,filled=True #控制顔色填充
,rounded=True #控制圖檔為圓角
)
graph = graphviz.Source(dot_data.replace('helvetica','"Microsoft YaHei"'), encoding='utf-8')
graph.view()
這裡直接運作會報錯,問題是雖然安裝了graphviz庫,但仍需安裝graphviz插件才能顯示圖檔。
插件下載下傳位址https://graphviz.gitlab.io/download/
windows選擇:
在安裝時,勾選将graphviz添加到環境變量
replace(‘helvetica’,’“Microsoft YaHei”’), encoding='utf-8’目的是防止中文亂碼,使用utf-8進行重新編碼。
運作之後,會直接打開一張pdf圖檔。
這就是分類決策樹,每一個分支節點上第一行代表分支的依據。
顔色代表不純度,顔色越深代表代表不純度越小,葉子節點不純度為0。
6.特征重要性顯示
上圖的決策樹分支是根據特征重要性(資訊增益)來進行分支,通過下面的程式可以列印出各個特征的重要性。
print([*zip(feature_name,clf.feature_importances_)])
得到結果:
[('酒精', 0.0), ('蘋果酸', 0.0), ('灰', 0.0), ('灰的堿性', 0.03448006546085971), ('鎂', 0.0), ('總酚', 0.0), ('類黃酮', 0.4207777417026953), ('非黃烷類酚類', 0.0), ('花青素', 0.0), ('顔色強度', 0.1444829682905809), ('色調', 0.03408453152321241), ('od280/od315稀釋葡萄酒', 0.0), ('脯氨酸', 0.3661746930226517)]
有些特征的重要性為0,說明這些名額在決策樹中沒有被利用。
随機參數 random_state & splitter
在上面的例子中,每次運作結果都會有些不同,原因在于使用sklearn自帶的決策樹時,它會預設“栽種”好幾棵不同的決策樹,從中傳回出效果最好的那一棵。
random_state用來設定分枝中的随機模式的參數,預設None,輸入任意整數,會一直長出同一棵樹,讓模型穩定下來。
splitter也是用來控制決策樹中的随機選項的,有兩種輸入值:
- 輸入”best",決策樹在分枝時雖然随機,但是還是會優先選擇更重要的特征進行分枝(重要性可以通過屬性feature_importances_檢視)
- 輸入“random",決策樹在分枝時會更加随機,樹會因為含有更多的不必要資訊而更深更大,并因這些不必要資訊而降低對訓練集的拟合。這也是防止過拟合的一種方式。
clf = tree.DecisionTreeClassifier(criterion="entropy"
,random_state=30
,splitter="random"
)
設定随機參數可以讓決策樹穩定或者更随機,效果不确定,一切以最後的score為主。
剪枝政策 max_depth
max_depth 用來限制樹的最大深度,超過設定深度的樹枝全部剪掉
策樹多生長一層,對樣本量的需求會增加一倍。
實際使用時,建議從=3開始嘗試,看看拟合的效果再決定是否增加設定深度。
剪枝政策 min_samples_leaf & min_samples_split
min_samples_leaf限定,一個節點在分枝後的每個子節點都必須包含至少min_samples_leaf個訓練樣本,否則分
枝就不會發生,一般來說,建議從=5開始使用。
min_samples_split限定,一個節點必須要包含至少min_samples_split個訓練樣本,這個節點才允許被分枝,否則
分枝就不會發生。
clf = tree.DecisionTreeClassifier(criterion="entropy"
,random_state=30
,splitter="random"
,max_depth=3
,min_samples_leaf=10
,min_samples_split=10
)
剪枝政策max_features & min_impurity_decrease
max_features限制分枝時考慮的特征個數,超過限制個數的特征都會被舍棄。
min_impurity_decrease限制資訊增益的大小,資訊增益小于設定數值的分枝不會發生。
确認最優的剪枝參數
通過程式設計循環,控制其它量不變,一個量循環改變,畫圖顯示,可以顯示出這個量的最優值。
下面以max_depth為例:
import matplotlib.pyplot as plt
test = []
for i in range(10):
clf = tree.DecisionTreeClassifier(max_depth=i+1
,criterion="entropy"
,random_state=30
,splitter="random"
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
test.append(score)
plt.plot(range(1,11),test,color="red",label="max_depth")
plt.legend()
plt.show()
繪制結果如圖所示
說明max_depth取4時,效果最好。
目标權重參數class_weight & min_weight_fraction_leaf
想象這種情況:在銀行要判斷“一個辦了信用卡的人是否會違約”,就是 是vs否(1%:99%)的比例,在這種情況下,出現了樣本不平衡,這個時候就需要調整其目标權重參數。
使用class_weight參數對樣本标簽進行一定的均衡,給少量的标簽更多的權重,讓模型更偏向少數類,向捕獲少數類的方向模組化。該參數預設None,此模式表示自動給與資料集中的所有标簽相同的權重。
有了權重之後,樣本量就不再是單純地記錄數目,而是受輸入的權重影響了,是以這時候剪枝,就需要搭配min_weight_fraction_leaf這個基于權重的剪枝參數來使用。
重要屬性和接口
1.(上面提到過)feature_importances_
能夠檢視各個特征對模型的重要性
注意後面的下劃線_不能省略
2.apply
傳回每個測試樣本所在的葉子節點的索引
clf.apply(Xtest)
3.predict傳回每個測試樣本的分類/回歸結果
clf.predict(Xtest)
其它内容補充
分類樹天生不擅長環形資料,最擅長月亮型資料的是最近鄰算法,RBF支援向量機和高斯過程;最擅長環形資料的是最近鄰算法和高斯過程;最擅長對半分的資料的是樸素貝葉斯,神經網絡和随機森林。
上面是分類樹的結果,環形資料可以看到左側出現一塊白色,說明分類效果不好。