決策樹
基礎理論
是什麼
決策樹多用於分類任務,本質上就是一棵樹形結構,通過樹形結構中的節點屬性來劃分新的數據屬於哪個分支。形式其實和流程圖一樣
決策樹通常有三個步驟:特徵選擇、決策樹的生成、決策樹的修剪。
作用
根據給定的訓練數據集構建一個決策樹模型,使它能夠對實例進行正確的分類。本質上是從訓練集中歸納出一組分類規則,或者說是由訓練數據集估計條件概率模型。
優缺點
計算直觀簡單,輸出結果易於理解。缺點容易過擬合。
決策樹生成步驟
特徵選擇
對於數據的衆多屬性,如何找出當前按照哪個屬性進行劃分分類效果最好呢? 這就需要藉助信息學論的知識。信息論中熵度量了事物的不確定性,越不確定的事物,它的熵就越大。特徵選擇都是基於此概念進行
- ID3算法就是用信息增益大小來判斷當前節點應該用什麼特徵來構建決策樹。
- C4.5在ID3基礎上改進,使用信息增益率來判斷,容易偏向於取值較多的特徵的問題。
- CART分類樹算法使用基尼係數,基尼係數代表了模型的不純度,基尼係數越小,則不純度越低,特徵越好。容易偏向於取值較少的特徵的問題。
不作細講,參考blog或西瓜書。
決策樹的生成
有了特徵選擇的標準,生成樹其實就是在樣本屬性總選出最好的特徵,已此特徵作爲節點進行劃分;然後在對節點下的子集數據進行重複步驟,不斷找出最好的劃分特徵,進行劃分。
# 創建分支的僞代碼, 檢測數據集中每個子項是否屬於同一類:
If so return 類標籤:
Else
尋找劃分數據集的最好特徵
劃分數據集
創建分支節點
for 每個劃分的子集
調用函數createBranch()並增加返回結果到分支節點中
return 分支節點
決策樹的修剪
決策樹修建的目的就是爲了防止過擬合,如果不剪枝,樹形結構過於龐大複雜,對於訓練樣本來說準確度很高,但是泛化性差。
剪枝有兩種:
- 預剪枝
預剪枝是指在決策樹生成過程中,對每個結點在劃分前先進行估計,若當前結點的劃分不能帶來決策樹泛化性能提升,則停止劃分並將當前結點標記爲葉結點 - 後剪枝
後剪枝則是先從訓練集生成一棵完整的決策樹,然後自底向上地對非葉結點進行考察,若將該結點對應的子樹替換爲葉結點能帶來決策樹泛化性能提升,則將該子樹替換爲葉結點.
代碼實現
有了上面理論基礎,就可以自己實現決策樹算法了,機器學習實戰 Ch03 中有ID3的實現,可以參考
實踐
結合實際的一個例子講講具體如何應用決策樹進行分類,使用sklean庫,不用重複造輪子。
代碼參考
例子使用西瓜書中數據集。
編號 | 色澤 | 根蒂 | 敲聲 | 紋理 | 臍部 | 觸感 | 密度 | 含糖率 | 好瓜 |
---|---|---|---|---|---|---|---|---|---|
1 | 青綠 | 蜷縮 | 濁響 | 清晰 | 凹陷 | 硬滑 | 0.697 | 0.46 | 是 |
2 | 烏黑 | 蜷縮 | 沉悶 | 清晰 | 凹陷 | 硬滑 | 0.774 | 0.376 | 是 |
3 | 烏黑 | 蜷縮 | 濁響 | 清晰 | 凹陷 | 硬滑 | 0.634 | 0.264 | 是 |
4 | 青綠 | 蜷縮 | 沉悶 | 清晰 | 凹陷 | 硬滑 | 0.608 | 0.318 | 是 |
覺得機器學習流程基本都是 數據預處理 、 模型選擇 、 根據測試結果來進行模型調參。
1、數據預處理
因爲西瓜書中數據爲離散的文本值,一般使用one-hot 編碼來進行映射,這裏因爲是決策樹算法,直接將數據轉換爲數值數據就可以。使用sklearn的LabelEncoder
即可
數據較少,直接劃分訓練集,測試集。
2、使用sklearn訓練
DecisionTreeClassifier 方法
參數很多,列舉下程序中使用到的幾個參數。
- criterion=’gini’: 特徵選擇算法Gini impurity,和基尼係數還不一樣
- splitter:表示在構造樹時,選擇結點的原則,默認是splitter=‘best’,即選擇最好的特徵點分類,比如基於信息增益分類時,則選擇信息增益最大的特徵點,還可以是’random’
- max_depth:樹的最大深度
- min_samples_leaf:表示每個葉結點最小的樣本數目
- min_samples_split: 分裂所需的最小數量的節點數.當葉節點的樣本數量小於該參數後,則不再生成分支.該分支的標籤分類以該分支下標籤最多的類別爲準
def train(x, y):
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state = 123)
print(len(y_train), len(y_test))
clf = tree.DecisionTreeClassifier(min_samples_split=2, min_samples_leaf=2)
clf.fit(X_train, y_train)
print('train score:', clf.score(X_train, y_train), ' test score:', clf.score(X_test, y_test))
dot_data = tree.export_graphviz(clf, out_file='1.dot',feature_names=X_train.columns.values, class_names=['good', 'bad'])
可以看到min_samples_split=2,表示當節點中樣本數量少於2 時不再分裂;
min_samples_leaf=2 表明葉子節點最小樣本數量爲2。 需要同時滿足兩個條件
參考
結果可視化
先導出’.dot’文件
dot_data = tree.export_graphviz(clf, out_file='tree.dot')
然後使用 graphviz
工具來進行圖片導出:
dot -Tpng tree.dot -o 1.png
可以看出,爲了保證葉子節點最小樣本數量爲2,最下面兩個葉子節點樣本數量都爲3,而且不進行再次分裂,如果再次分裂,就會有葉子幾點爲1 的情況(比如最下層左葉子節點,value=[1,2],表示正負樣本數爲1,2,如果再次分裂將會有葉子幾點爲1的情況)
3、根據測試結果調整模型參數
傳統的機器學習算法尋找最優參數,可以使用grid search,像決策樹這種可調參數並不多,時間消耗也可以接受。對於多個可變參數,不能先找出其中一個參數最優值,然後再此基礎上去找另一個參數最優值,因爲多參數直接也會有影響。
代碼參考