資料視覺化之 Decision tree (決策樹)範例與 Machine Learning (機器學習) 概念簡單教學(入門)
本文以 python 的 Sklearn.tree.DecisionTreeClassifier 作為示範,順便示範 Pandas from dict 的應用,也說明一下簡單的 Machine Learning 概念
前言
Decision Tree (中文叫決策樹) 其實是一種方便好用的 Machine Learning 工具,可以快速方便地找出有規則資料,本文我們以 sklearn 來做範例;本文先從產生假資料,然後視覺化決策樹的狀態來示範
另外本文也簡單介紹 train/test 資料測試集的概念,說明為何會有這樣的設計,希望讓機器學習剛入門或是新手有更多的瞭解
準備資料
我們先假設一些假資料,這邊我們寫一個蘑菇產生器,然後自訂一些規則看看 Decision Tree (決策樹) 能不能找到我們隱藏的規則
import random
from collections import defaultdict
mushrooms = defaultdict(lambda: [])def checkType(size, length):
if size < 10: return '發財蘑菇'
if size < 15: return '幸運蘑菇'
if length > 15:
return '發財蘑菇'
return '神秘蘑菇'for i in range(100):
size = random.randint(1, 20)
length = random.randint(1, 20)
mushrooms['type'].append(checkType(size, length))
mushrooms['size'].append(size)
mushrooms['length'].append(length)
上面程式碼:
我們假設,尺寸(size) < 10 和 size >15 之後且長度(length) > 15 的一律為發財蘑菇,沒分類的為神秘蘑菇,然後產生 100 組測試資料
再來我們使用 pandas 來協助我們處理資料 ( 載入我們產生的 python dict )
import pandas as pd
data = pd.DataFrame.from_dict(mushrooms)
可以看到 data 內容如上 ( 因為此為亂數產生,所以各位實作基本上不會和本人相同 )
接下來我們進行資料分離,這部分是為了 traning model 和 test model 使用 ( 訓練和測試決策樹 )
y = data['type'] # 變出 y 資料
X = data.drop(['type'], axis=1) # 變出 X 資料,將 type 丟棄
各位可以 print 看看 X 和 y, 會發現 X 剩下 size / length, 而 y 剩下 type
小知識: 為什麽 Machine Learning 常常會看到 X, y ?
其實這是從數學領域來的,為了方便表示 y = f(X)
其中 f 為 function,即為我們的機器學習方法 ( model 或是任何演算法 )
普遍來說,X 代表輸入資料, y 代表輸出結果
關於 Train / Test dataset 資料概念 ( 訓練集/測試集)
再來就是分離出訓練與測試資料集,訓練集是用來訓練 Decision Tree,測試集用來測試我們的結果是否正確
這個過程其實就和我們在學校讀書考試一樣,我們透過現有的資料可以隨機分成 train / test ,用易懂的概念來說就是 小考題目 / 期中考
假設我們有 100 題沒有做過題目,我們要考學生 ( 就是 Decision tree model )可以從裡面取出一些題目 ( 例如 80 題 = 訓練集)給他練習小考,然後他會自己去修正錯誤;到期中考的時候再把我們剩下的題目 ( 20 題 = 測試集)給他,會這樣做是因為我們不希望學生提前知道考試答案( 考古題概念),不然那 20 題就測不出學生是否真的學會知識
所以一樣的概念,我們將 80 顆蘑菇給決策樹看看,最後我們用 20 顆他沒看過的蘑菇,就知道他是不是真的學會了(程度如何)
要達成上述的說法,可以自己寫 code 做分割,但是 sklearn 已經幫我們準備好了,所以只要
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
其中 test_size 為我們要保留的 test 大小,他會依據我們的 X 數量做保留
上述我們說要保留 20 筆,所以 100 * 0.2 = 20 ( 實務上就是用比例,例如我們有 80000 筆資料就是 16000 筆測試資料,不過這個比例也是看情況調整,不一定 )
開始訓練決策樹( Decision Tree)
江湖一點訣,說破不值錢
機器學習 ( Machine Learning ) 大部分時間的就是整理資料,有正確的資料才有正確的結果,這裏要訓練一個 Model 只要短短幾行程式碼
(其他 Model 如 Deep Learning 之類的就另外情況了 )
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier()
model.fit(X_train, y_train)
直接將 X_train (小考題目), y_train (小考答案) 丟給 model 他自己就會去學習了
再來看看他學了多少,我們可以用 model.score 來看看 (就是我們說的期中考 )
model.score(X_test, y_test)
這邊就可以得到分數,這個分數到標準每個 model 不一定,有的是越高越好、越低越好、滿分 1、負數 … 等等
這邊的 Decision Tree Model 滿分是 1,所以越趨近 1 的就是越好
或是透過
from sklearn.metrics import accuracy_score
y_predict = model.predict(X_test)
accuracy_score(y_test, y_predict)
其中 accuracy_score 是用於分類的演算法… 這部分有機會再另開章節說明
期末考測試
我們訓練一個 model ,最後就是要上線與投入產品應用
所以我們這邊假裝有遇到不同的蘑菇情況 (系統投入應用),假設給 100 個全新的沒看過蘑菇
from sklearn.metrics import accuracy_score
answers = [] # 存放真正答案
predicts = [] # 存放預測結果
for i in range(100):
size = random.randint(1, 20)
length = random.randint(1, 20)
answers.append(checkType(size, length))
predicts.append(model.predict([[size, length]]))accuracy_score(answers, predicts)
上述 answers 為我們的真答案, predicts 為 model 作答結果
然後透過 accuracy_score 來比較答案 ( 當然也可以自己寫 code 去比對 )
以上本人測試這次的 model 有 0.97 準確度 ( 相當於 97 分 ),各位可以自己測試看看,不過因為都是亂數所以不一定會有相同結果
視覺化表現 — Graphviz
既然叫做決策樹,那我們就可以看看他的決策過程
from sklearn.tree import export_graphviz
export_graphviz(model, out_file='mushrooms.dot',
feature_names=['size', 'length'],
class_names=model.classes_)
其中 feature_names 就是我們的 X 裡面的參數
class_names 就是我們預測的分類名稱
然後 out_file 是圖形的輸出檔案
這邊我們要透過第三方程式幫忙繪圖 ( https://graphviz.org )
Mac 可透過以下指令安裝
brew install graphviz
然後找到上面產出的 mushrooms.dot 檔案,使用以下指令產出 png 檔
dot -Tpng mushrooms.dot -o mushrooms.png
可以看到決策樹的判斷基準,第一個節點 size ≤ 9.5 ,其實滿符合我們的產生器,小於 10 的都是發財蘑菇
原來產生器中 length >15 的是發財蘑菇,這個 Decision Tree 這邊分析是 length ≤ 15.5 是神秘香菇,其他為發財蘑菇,也是大致符合判斷
註 : export_graphviz 有許多參數,加上 filled=True, rounded=True 可得到類似本文封面圖片的效果
視覺化表現 — Contour
這邊我們也來看一下資料分布情況 ( 關於 Contour 可以參考本人之前教學 )
import matplotlib.pyplot as pltresolution = 100
dx = np.linspace(np.min(1), np.max(20), resolution)
dy = np.linspace(np.min(1), np.max(20), resolution)
dx, dy = np.meshgrid(dx, dy)Xc = np.c_[dx.flatten(), dy.flatten()]
z = model.predict(Xc)# convert predict to number
kls = list(model.classes_)
z = np.array([kls.index(v) for v in z])
z = z.reshape(dx.shape)
plt.contourf(dx, dy, z, alpha=0.6)plt.xlabel('size')
plt.ylabel('length')
得出
分布上來看也是大致符合我們產生器的配置
後記
其實 Random Forest 和 Decision Tree 也有密不可分的關係,不過這部分就等哪天有空再來介紹了
祝各位 2021 新年快樂 :)