與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。
希望那一天可以早點到來吧……
往期文章: