決策樹模型透過遞迴分割資料建立預測模型,易於理解和解釋。根據變數如borrower_scorepayment_inc_ratio等建立分支,最終形成預測結果。Python 的 dmba 套件和 R 語言提供工具輸出決策樹結構。決策樹的構建過程中,使用基尼不純度或熵等指標衡量資料純度,並透過控制樹的深度和節點大小避免過擬合。然而,單一決策樹容易過擬合,因此發展出整合方法,如 Bagging 和隨機森林,以提升模型泛化能力。隨機森林在 Bagging 的基礎上,加入變數抽樣,降低單一變數的影響,進一步提升模型穩健性。實務上,R 語言的 randomForest 套件提供簡便的隨機森林模型建構方法,並可計算變數重要性,協助理解各變數對預測的貢獻度。

決策樹模型

決策樹是一種直觀且強大的機器學習模型,廣泛應用於分類別和迴歸問題。它透過遞迴分割資料,將資料集劃分為更小的子集,並在每個子集中進行預測。

R語言中的決策樹輸出

在R語言中,可以輕鬆生成決策樹的文字表示:

loan_tree
n= 3000
node), split, n, loss, yval, (yprob)
* denotes terminal node
1) root 3000 1445 paid off (0.5183333 0.4816667)
2) borrower_score>=0.575 878 261 paid off (0.7027335 0.2972665) *
3) borrower_score< 0.575 2122 938 default (0.4420358 0.5579642)
6) borrower_score>=0.375 1639 802 default (0.4893228 0.5106772)
12) payment_inc_ratio< 10.42265 1157 547 paid off (0.5272256 0.4727744)
24) payment_inc_ratio< 4.42601 334 139 paid off (0.5838323 0.4161677) *
25) payment_inc_ratio>=4.42601 823 408 paid off (0.5042527 0.4957473)
50) borrower_score>=0.475 418 190 paid off (0.5454545 0.4545455) *
51) borrower_score< 0.475 405 187 default (0.4617284 0.5382716) *
13) payment_inc_ratio>=10.42265 482 192 default (0.3983402 0.6016598) *
7) borrower_score< 0.375 483 136 default (0.2815735 0.7184265) *

內容解密:

  1. 節點結構:每個節點代表一個預測結果,包含樣本數量、錯誤分類別數量和預測類別的機率。
  2. 分割規則:根據borrower_scorepayment_inc_ratio等變數進行分割。
  3. 終端節點:用*標記,表示最終的預測結果。

Python中的決策樹輸出

在Python中,可以使用dmba套件中的textDecisionTree函式生成決策樹的文字表示:

print(textDecisionTree(loan_tree))
--
node=0 test node: go to node 1 if 0 <= 0.5750000178813934 else to node 6
node=1 test node: go to node 2 if 0 <= 0.32500000298023224 else to node 3
node=2 leaf node: [[0.785, 0.215]]
node=3 test node: go to node 4 if 1 <= 10.42264986038208 else to node 5
node=4 leaf node: [[0.488, 0.512]]
node=5 leaf node: [[0.613, 0.387]]
node=6 test node: go to node 7 if 1 <= 9.19082498550415 else to node 10
node=7 test node: go to node 8 if 0 <= 0.7249999940395355 else to node 9
node=8 leaf node: [[0.247, 0.753]]
node=9 leaf node: [[0.073, 0.927]]
node=10 leaf node: [[0.457, 0.543]]

內容解密:

  1. 節點測試:每個非葉節點根據特定條件進行測試,決定下一步的走向。
  2. 葉節點:代表最終的預測結果,包含各類別的機率。

遞迴分割演算法

決策樹的構建過程根據遞迴分割演算法,該演算法透過不斷分割資料來提高預測的準確性。

演算法步驟:

  1. 初始化:從整個資料集開始。
  2. 分割:根據某個變數的最佳分割點將資料分割成兩個子集。
  3. 遞迴:對每個子集重複步驟2,直到達到停止條件。

純度衡量指標

決策樹的構建依賴於對資料純度的衡量,常用的指標包括基尼不純度和熵。

基尼不純度:

[ I(A) = p(1-p) ]

熵:

[ I(A) = -p\log_2(p) - (1-p)\log_2(1-p) ] 這兩個指標都用於衡量資料的混雜程度,熵對中等和高精確度的評估給予更高的不純度分數。

圖表展示

下圖展示了基尼不純度和熵之間的比較: 此圖示說明瞭基尼不純度和熵在不同精確度下的變化趨勢。

決策樹的成長控制與剪枝

決策樹在成長過程中會不斷分裂資料,直到葉節點變得非常純淨(即所有資料屬於同一類別)。然而,這種過度成長的樹往往會過度擬合訓練資料,學習到的是資料中的雜訊而非真實的模式。因此,我們需要控制樹的複雜度,以確保模型能夠在新資料上表現良好。

為何需要停止樹的成長

當決策樹不斷成長時,分裂規則變得越來越細緻。最終,樹會從識別出真正可靠的資料關係轉變為識別出只存在於雜訊中的微小規則。一個完全成長的樹會導致葉節點完全純淨,因此在訓練資料上達到 100% 的準確率。然而,這種準確率是虛假的,因為模型已經過度擬合了訓練資料中的雜訊。

控制樹的成長方法

在 R 和 Python 中,有多種方法可以控制決策樹的成長:

  • 避免分裂一個分割槽,如果結果子分割槽太小或終端葉太小。在 R 的 rpart 中,這些限制由引數 minsplitminbucket 分別控制,預設值為 20 和 7。在 Python 的 DecisionTreeClassifier 中,可以使用引數 min_samples_split(預設 2)和 min_samples_leaf(預設 1)來控制。
  • 如果新的分割槽不能顯著降低不純度,則不分裂該分割槽。在 R 的 rpart 中,這由複雜度引數 cp 控制,它衡量樹的複雜程度。在 Python 的 DecisionTreeClassifier 中,引數 min_impurity_decrease 用於根據加權不純度減少值來限制分裂。

這些方法涉及任意規則,可以用於探索性工作,但我們很難確定最佳值(即能夠最大化新資料上預測準確率的值)。因此,我們需要將交叉驗證與系統地改變模型引數或透過剪枝修改樹結合起來。

在 R 中控制樹的複雜度

使用複雜度引數 cp,我們可以估計出在新資料上表現最佳的樹的大小。如果 cp 太小,則樹會過度擬合資料,學習到的是雜訊而非訊號。另一方面,如果 cp 太大,則樹會太小,預測能力不足。R 的 rpart 中預設的 cp 值為 0.01,但對於較大的資料集,這個值可能太大。

使用交叉驗證確定最佳 cp

  1. 將資料分成訓練集和驗證集。
  2. 使用訓練資料成長樹。
  3. 逐步剪枝,並在每個步驟中記錄 cp 值。
  4. 記錄對應於驗證資料上最小誤差的 cp 值。
  5. 重複步驟 1-4 多次,並平均對應於最小誤差的 cp 值。
  6. 使用最佳 cp 值來成長最終的樹。

在 R 的 rpart 中,可以使用引數 cptable 生成 cp 值及其相關的交叉驗證誤差表,從而確定具有最低交叉驗證誤差的 cp 值。

在 Python 中控制樹的複雜度

Python 的 scikit-learn 中的決策樹實作不支援複雜度引數或剪枝。解決方案是使用網格搜尋來遍歷不同引數值的組合。例如,可以在 5 到 30 的範圍內變化 max_depth,並在 20 到 100 之間變化 min_samples_split。scikit-learn 中的 GridSearchCV 方法是一種方便的方法,可以將透過所有組合的詳盡搜尋與交叉驗證結合起來。然後,使用交叉驗證的模型效能選擇最佳引數集。

預測連續值

使用決策樹預測連續值(也稱為迴歸)遵循相同的邏輯和程式,除了不純度是由每個子分割槽中與平均值的平方偏差(平方誤差)來衡量,並且預測效能是由每個分割槽中的均方根誤差(RMSE)來判斷。

scikit-learn 中的 sklearn.tree.DecisionTreeRegressor 方法可用於訓練決策樹迴歸模型。

決策樹的應用

決策樹模型具有兩個吸引人的特點:

  • 提供視覺化工具來探索資料,以瞭解哪些變數是重要的以及它們如何相互關聯。決策樹可以捕捉預測變數之間的非線性關係。
  • 提供一套規則,可以有效地傳達給非專業人士,無論是用於實施還是為了「銷售」資料探勘專案。

然而,在預測方面,通常使用多棵樹的結果比單棵樹更強大。隨機森林和提升樹演算法幾乎總是提供更好的預測準確性和效能。

主要概念

  • 決策樹產生一組規則來分類別或預測結果。
  • 這些規則對應於資料的連續分割。
  • 每個分割參考一個特定的預測變數的值,並將資料分成該預測變數的值高於或低於該分割值的記錄。
  • 在每個階段,樹演算法選擇使每個子分割槽中的結果不純度最小化的分割。
  • 當無法進行進一步的分割時,樹就完全成長,每個終端節點或葉節點都有單一類別的記錄;遵循該規則(分割)路徑的新案例將被分配到該類別。
  • 完全成長的樹會過度擬合資料,必須進行剪枝,以捕捉訊號而非雜訊。
  • 多棵樹演算法(如隨機森林和提升樹)提供更好的預測效能,但會失去單棵樹根據規則的溝通能力。
# 使用網格搜尋來找到最佳引數
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier

# 定義引數網格
param_grid = {
    'max_depth': range(5, 31),
    'min_samples_split': range(20, 101)
}

# 初始化決策樹分類別器
clf = DecisionTreeClassifier(random_state=42)

# 初始化網格搜尋
grid_search = GridSearchCV(estimator=clf, param_grid=param_grid, cv=5)

# 進行網格搜尋
grid_search.fit(X_train, y_train)

# 輸出最佳引數
print("最佳引數:", grid_search.best_params_)

#### 最佳引數解密:
# 網格搜尋透過遍歷指定的引數網格來找到最佳引陣列合。
# 在這個例子中,我們遍歷了 max_depth 從 5 到 30 和 min_samples_split 從 20 到 100 的所有組合。
# cv=5 表示使用 5 折交叉驗證來評估每個引陣列合的效能。
# 最終,輸出最佳引陣列合。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title 決策樹與隨機森林架構

package "決策樹建構" {
    component [遞迴分割] as split
    component [基尼/熵指標] as metric
    component [節點預測] as node
}

package "過擬合控制" {
    component [最大深度] as depth
    component [最小節點數] as min_node
    component [剪枝] as prune
}

package "隨機森林" {
    component [Bagging 抽樣] as bag
    component [變數子集] as subset
    component [多樹投票] as vote
}

package "實作工具" {
    component [R: randomForest] as r_rf
    component [Python: dmba] as py_dmba
    component [變數重要性] as importance
}

split --> metric : 選擇最佳
metric --> node : 分類結果

depth --> prune : 限制
min_node --> prune : 停止條件

bag --> subset : 每棵樹
subset --> vote : 整合預測
vote --> importance : 計算貢獻

r_rf --> importance : R 實作
py_dmba --> importance : Python 實作

note right of metric
  基尼不純度: p(1-p)
  熵: -Σp*log(p)
end note

note bottom of vote
  多數投票決定
  降低過擬合風險
end note

skinparam dummy {
}
    package "資料處理" {
        component [資料收集] as collect
        component [資料清洗] as clean
        component [特徵工程] as feature
    }

    package "模型訓練" {
        component [模型選擇] as select
        component [超參數調優] as tune
        component [交叉驗證] as cv
    }

    package "評估部署" {
        component [模型評估] as eval
        component [模型部署] as deploy
        component [監控維護] as monitor
    }
}

collect --> clean : 原始資料
clean --> feature : 乾淨資料
feature --> select : 特徵向量
select --> tune : 基礎模型
tune --> cv : 最佳參數
cv --> eval : 訓練模型
eval --> deploy : 驗證模型
deploy --> monitor : 生產模型

note right of feature
  特徵工程包含:
  - 特徵選擇
  - 特徵轉換
  - 降維處理
end note

note right of eval
  評估指標:
  - 準確率/召回率
  - F1 Score
  - AUC-ROC
end note

@enduml

Bagging 與隨機森林概述

在1906年,統計學家弗朗西斯·高爾頓(Sir Francis Galton)參加了英格蘭的一個縣集市,當時正在舉行一場競猜一頭展覽牛的宰後重量的比賽。雖然個人的猜測差異很大,但平均值和中位數都與牛的真實重量相差不到1%。詹姆斯·蘇洛維基(James Surowiecki)在他的書《群眾的智慧》(The Wisdom of Crowds)中探討了這種現象。這一原理同樣適用於預測模型:對多個模型的預測結果進行平均(或採取多數投票)——即模型整合——結果證明比僅選擇一個模型更準確。

Bagging 與隨機森林的關鍵術語

  • 整合(Ensemble):透過使用多個模型的集合來進行預測。
    • 同義詞:模型平均(Model Averaging)
  • Bagging:透過自助法(Bootstrapping)資料來形成多個模型的集合的一般技術。
    • 同義詞:自助匯總(Bootstrap Aggregation)
  • 隨機森林(Random Forest):根據決策樹模型的Bagging估計型別。
    • 同義詞:Bagged 決策樹(Bagged Decision Trees)
  • 變數重要性(Variable Importance):衡量預測變數在模型效能中的重要程度。

整合方法的基本原理

整合方法已被廣泛應用於各種不同的建模方法中,尤其是在Netflix獎中,Netflix向任何能夠提出一個模型,使預測Netflix客戶對電影評分的準確性提高10%的參賽者提供100萬美元的獎金。簡單的整合方法如下:

  1. 對給定的資料集開發一個預測模型並記錄預測結果。
  2. 對相同的資料重複使用多個模型。
  3. 對於每個需要預測的記錄,取所有模型預測結果的平均值(或加權平均值,或多數投票)。

Bagging 演算法

Bagging由Leo Breiman在1994年提出。其基本步驟如下:

  1. 初始化模型數量$M$和要選擇的記錄數量$n$($n < N$),設定迭代次數$m = 1$。
  2. 從訓練資料中進行自助重抽樣(有放回),形成子樣本$Y_m$和$\mathbf{A}_m$(稱為bag)。
  3. 使用$Y_m$和$\mathbf{A}_m$訓練一個模型,建立一套決策規則$f_m(\mathbf{A})$。
  4. 增加模型計數器$m = m + 1$,如果$m \leq M$,則傳回步驟2。

隨機森林

隨機森林是在決策樹上應用Bagging的基礎上發展而來的,並有一個重要的擴充套件:在抽樣記錄的同時,演算法還會對變數進行抽樣。在傳統的決策樹中,為了確定如何建立一個分割槽的子分割槽,演算法透過最小化某個標準(如Gini不純度)來選擇變數和分割點。在隨機森林中,在演算法的每個階段,變數的選擇被限制在一個隨機的子集變數中。

隨機森林演算法步驟:

  1. 從記錄中進行自助重抽樣。
  2. 對於第一次分割,隨機抽樣$p < P$個變數,無放回。
  3. 對每個被抽樣的變數$X_{j1}, X_{j2}, …, X_{jp}$,應用分割演算法:
    • 對$X_{jk}$的每個值$s_{jk}$:
      • 將分割槽$A$中的記錄分割為兩部分:一部分是$X_{j(k)} < s_{j(k)}$的記錄,另一部分是$X_{jk} \geq s_{jk}$的記錄。
      • 衡量每個子分割槽內類別的同質性。
    • 選擇使分割槽內同質性最大化的$s_{jk}$值。
  4. 選擇使分割槽內同質性最大化的變數$X_{jk}$和分割值$s_{jk}$。
  5. 繼續下一次分割,重複上述步驟,從步驟2開始。
  6. 直到樹生長完成。
  7. 傳回步驟1,再次進行自助重抽樣,並重新開始整個過程。

如何選擇每次分割時要抽樣的變數數量?

一個經驗法則是選擇$\sqrt{P}$,其中$P$是預測變數的數量。R語言中的randomForest包實作了隨機森林演算法。以下是將該包應用於貸款資料的例子。

R語言範例程式碼:

# 載入必要的函式庫
library(randomForest)

# 假設 loan_data 是我們的資料框
# 將目標變數轉換為因子(如果還不是的話)
loan_data$target <- as.factor(loan_data$target)

# 使用 randomForest 函式建立模型
model <- randomForest(target ~ ., data = loan_data, 
                       ntree = 100,  # 設定樹的數量
                       mtry = floor(sqrt(ncol(loan_data) - 1)),  # 設定每次分割時的變數數量
                       importance = TRUE,  # 是否計算變數重要性
                       proximity = TRUE)  # 是否計算接近度矩陣

# 輸出模型的匯總資訊
print(model)

# 檢視變數重要性
importance(model)

內容解密:

  1. 載入必要的函式庫:首先,我們需要載入randomForest函式庫來使用隨機森林演算法。
  2. 資料準備:將目標變數轉換為因子,以適應分類別任務的需求。
  3. 建立隨機森林模型:使用randomForest函式建立模型,其中ntree引數設定了要生長的樹的數量,mtry引數根據經驗法則設定為$\sqrt{P}$,其中$P$是預測變數的數量。
  4. importance = TRUE:計算每個變數的重要性,這對於瞭解哪些變數對模型的預測最有幫助非常有用。
  5. proximity = TRUE:計算接近度矩陣,可以用於進一步的分析,如異常值檢測等。
  6. 輸出模型的匯總資訊:透過print(model)可以獲得模型的概覽,包括錯誤率、混淆矩陣等資訊。
  7. 檢視變數重要性:透過importance(model)可以瞭解每個變數對模型的貢獻程度。

這段程式碼展示瞭如何使用R語言中的randomForest包來建立和分析隨機森林模型。透過這種方法,我們可以構建強大的預測模型,並深入瞭解哪些變數對於預測結果最為重要。