機器學習(五):通俗易懂決策樹與隨機森林及程式碼實踐

CaiYongji發表於2021-02-25

與SVM一樣,決策樹是通用的機器學習演算法。隨機森林,顧名思義,將決策樹分類器整合到一起就形成了更強大的機器學習演算法。它們都是很基礎但很強大的機器學習工具,雖然我們現在有更先進的演算法工具來訓練模型,但決策樹與隨機森林因其簡單靈活依然廣受喜愛,建議大家學習。

一、決策樹

1.1 什麼是決策樹

我們可以把決策樹想象成IF/ELSE判別式深度巢狀的二叉樹形結構。以我們在《機器學習(三):理解邏輯迴歸及二分類、多分類程式碼實踐》所舉的鳶尾花資料集為例。

我們曾用seaborn繪製花瓣長度和寬度特徵對應鳶尾花種類的散點圖,如下:

當花瓣長度小於2.45則為山鳶尾(setosa),剩下的我們判斷花瓣寬度小於1.75則為變色鳶尾(versicolor)剩下的為維吉尼亞鳶尾(virginica)。那麼我用導圖畫一下這種判別式的樹形結構如下:

因此,當我們面對任意鳶尾花的樣本,我們只需要從根節點到葉子節點遍歷決策樹,就可以得到鳶尾花的分類結論。

這就是決策樹。

1.2 決策樹程式碼實踐

我們匯入資料集(大家不用在意這個域名),並訓練模型:

import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier

#引入資料集
df = pd.read_csv('https://blog.caiyongji.com/assets/iris.csv')

#決策樹模型
X = df[['petal_length','petal_width']].to_numpy() 
y = df['species']
tree_clf = DecisionTreeClassifier(max_depth=2, random_state=42)
tree_clf.fit(X, y)

我們來視覺化決策樹:

import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(12,8))
plot_tree(tree_clf,filled=True);

如上圖,我們可以看到根節點總例項數為150時,由value = [50, 50, 50]可知,實際樣本分類為50個山鳶尾花例項、50個變色鳶尾花例項、50個維吉尼亞鳶尾花例項。我們再看最末尾右側的葉子節點(紫色),由value = [0, 1, 45]可知,實際樣本分類為0個山鳶尾花例項、1個變色鳶尾花例項、45個維吉尼亞鳶尾花例項。

那麼gini = 0.043是什麼意思呢?

1.3 基尼不純度

顯然我們進行分類時,每一個類別實際混入其他類的數量越少分類就越純粹,這種純度我們通過如下公式表示:

$$ G_i = 1 - \sum_{k=1}{n}{p2_{i,k}} $$

我們計算維吉尼亞鳶尾花節點(紫色)的gini係數1-((0/46)**2 + (1/46)**2 + (45/46)**2) = 0.04253308128544431 ≈0.043

我們使用基尼(gini)不純度來衡量決策樹的好壞。那麼我們通過最小化基尼不純度min(gini)來求解X[0],X[1](即,花瓣長度寬度特徵)邊界的過程就決策樹模型的訓練過程。

二、隨機森林

2.1 大數定理與隨機森林

其實隨機森林很簡單,我們把決策樹隨機組合在一起就是隨機森林,它比單個的決策樹更有效。

憑什麼?

假設我們有一枚不均勻的硬幣,投擲它有51%的概率為正面,49%的概率為背面,那麼當投擲1000次時,“大多數為正面"這件事的概率為75%。投擲10000次時,“大多數為正面"這件事的概率為97%。這就是大數定理,它體現的是群體智慧。質量不夠,數量來湊。由此可知,當前尋找最佳模型的方法不止是技巧的比拼,也同樣是算力的比拼。

2.2 隨機森林程式碼實踐

2.2.1. 引入新的資料集

新增引用:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

匯入資料集(大家不用在意這個域名):

df = pd.read_csv("https://blog.caiyongji.com/assets/penguins_size.csv")
df = df.dropna()
df.head()
species island culmen_length_mm culmen_depth_mm flipper_length_mm body_mass_g sex
Adelie Torgersen 39.1 18.7 181 3750 MALE
Adelie Torgersen 39.5 17.4 186 3800 FEMALE
Adelie Torgersen 40.3 18 195 3250 FEMALE
Adelie Torgersen 36.7 19.3 193 3450 FEMALE
Adelie Torgersen 39.3 20.6 190 3650 MALE

企鵝資料集包含特徵和標籤如下:

  • 特徵:所在島嶼island、鳥喙長度culmen_length_mm、鳥喙深度culmen_depth_mm、腳蹼長度flipper_length_mm、體重(g)、性別
  • 標籤:物種species:Chinstrap, Adélie, or Gentoo

2.2.2 觀察資料


sns.pairplot(df,hue='species')

我們通過pairplot方法繪製特徵兩兩之間的對應關係。

2.2.3 預處理

X = pd.get_dummies(df.drop('species',axis=1),drop_first=True)
y = df['species']
X.head()

注意,get_dummies方法將字串屬性的列轉換成了數字屬性的多個列。如,島嶼island和性別sex分別轉換成了island_Dream、island_Torgersen和sex_FEMALE、sex_MALE。這是一種獨熱編碼的關係,比如sex_FEMALE與sex_MALE屬性獨立,在空間內沒有向量關係。

culmen_length_mm culmen_depth_mm flipper_length_mm body_mass_g island_Dream island_Torgersen sex_FEMALE sex_MALE
39.1 18.7 181 3750 0 1 0 1
39.5 17.4 186 3800 0 1 1 0
40.3 18 195 3250 0 1 1 0
36.7 19.3 193 3450 0 1 1 0
39.3 20.6 190 3650 0 1 0 1

2.2.4 訓練資料

#訓練
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=101)
model = RandomForestClassifier(n_estimators=10,max_features='auto',random_state=101)
model.fit(X_train,y_train)

#預測
from sklearn.metrics import accuracy_score
preds = model.predict(X_test)
accuracy_score(y_test,preds)

使用隨機森林分類器RandomForestClassifier訓練,得到模型精度為97%。

2.2.5 網格搜尋與AdaBoost提升法(擴充)

我們使用AdaBoostClassifier分類器整合數個決策樹分類器DecisionTreeClassifier進行分類。並使用網格搜尋方法GridSearchCV來尋找最優引數。

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import AdaBoostClassifier

ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), random_state=101)
ada_clf.fit(X_train, y_train)
param_grid = {'n_estimators':[10,15,20,25,30,35,40], 'learning_rate':[0.01,0.1,0.5,1], 'algorithm':['SAMME', 'SAMME.R']}
grid = GridSearchCV(ada_clf,param_grid)
grid.fit(X_train,y_train)
print("grid.best_params_ = ",grid.best_params_,", grid.best_score_ =" ,grid.best_score_)

這是一種整合學習技術,輸出如下:

grid.best_params_ =  {'algorithm': 'SAMME', 'learning_rate': 1, 'n_estimators': 20} , grid.best_score_ = 0.9914893617021276

總結

二叉樹是決策樹的核心邏輯,隨機森林是大數定理的應用實現。這種基本思想即使不用數學公式也可以很容易的解釋清楚,這也是我做這個系列課程(文章)的主要風格特點。我認為,數學是對現實世界的解釋,但現實世界並不能被數學完全解釋。像谷歌AI主管Laurence Moroney所說:

很多人害怕數學,害怕大量的深度的微積分知識。其實我們可以實現編碼而不考慮數學,我們可以使用TensorFlow中高(層)級的API,來解決問題,如自然語言處理,影像分類,計算機視覺序列模型等而無需理解深刻的數學。就像你使用JAVA卻不一定非要掌握它是如何編譯的。未來,AI只是每個開發者技術棧(toolbox)中的一部分,就像HTML, CSS, JAVA。

希望那一天可以早點到來吧……

往期文章:

相關文章