使用Decision Tree預測權力遊戲角色是否存活 === ###### tags: `Data science` `課堂作業` data 來源 : [Game of Thrones](https://www.kaggle.com/mylesoneill/game-of-thrones?select=battles.csv) :::warning 這篇用到的資料"character-deaths.csv",檔案中有917個角色,他們每一個人都已經被標註了最後是存活或死亡,因此後面會切割成訓練集與測試集,最後對**測試集資料做預測**。 這篇重點不在於特徵工程或是把準確度提高,主要是熟悉**決策樹的建立、模型評估與決策樹可視化的練習**。 ::: ## 資料讀取 ``` import pandas as pd df = pd.read_csv('./archive/character-deaths.csv') df.head(5) ``` ![](https://i.imgur.com/vefAHLj.png) :::info Name : 角色名字 Allegiances : 家族 Death Year : 死亡年份 Book of Death : 死亡集數 Death Chapter : 死亡章節 Book intro Chapter : 角色登場介紹章節 Gender : 1 -> 男性 0 -> 女性 Nobility : 1 -> 貴族 0 -> 平民 GoT/CoK/SoS/FfC/DwD: 出現在第一、二、三...本書中 ::: ## 資料前處理 1. 觀察資料有無空值 ``` df.info() ``` ![](https://i.imgur.com/S6nZJoN.png) :::info 觀察出Death Year,Book of Death, Death Chapter,Book Intro Chapter 有空值,待會處理。 ::: 2. 處理空值 - 2-1 首先,Death Year,Book of Death, Death Chapter,對於最後預測的結果來說都是代表一樣的意思,即為死亡,因此我們挑一個欄位,經由多次實驗,最後挑選"Death Year"處理與訓練,**將空值填入0,代表存活**,**有值的地方填入1,代表死亡**。這樣一來資料集變得更簡潔了,減少noise. ``` df['Death Year'] = df['Death Year'].fillna(0) df['Death Year'][df['Death Year'] > 0] = 1 df ``` ![](https://i.imgur.com/GnlsvWH.png) - 2-2 Book Intro Chapter 這部分先將空值填入0 ``` df['Book Intro Chapter'] = df['Book Intro Chapter'].fillna(0) df ``` ![](https://i.imgur.com/Rer1eCn.png) 3. Allegiances Allegiances這個欄位是非數字的,但是模型只善於處理數字,因此我們需要對此欄位做處理。 :::info categorical variables 又分為兩種,一種是 nominal,另一種是 ordinal - nominal: 分類的值沒有任何先後順序或等級關係。 e.g. green/red/blue - ordinal:分類的值是有等級關係的 e.g. high/medium/low ::: Allegianves 是屬於nominal的,我們可以用一種名為 **One Hot Encoding 的技術**來解決這個問題。我們為列中的每一種分類都分別單獨建一個列(即會有新的欄位產生),用 0 或 1 填充,這些新建的列被稱作 **dummy vaiables**。 ``` Allegiances_dummy = pd.get_dummies(df.Allegiances) df = pd.concat([df, Allegiances_dummy], axis = 1) df ``` ![](https://i.imgur.com/ilWRJKh.png) :::info 我們會發現欄位數從本來的 13 增加至 34 個欄位 ::: ## 切割訓練集與測試集 訓練集 75 %,測試集 25 % ``` from sklearn.model_selection import train_test_split X = df.iloc[:,5:] y = df.loc[:,'Death Year'] X_train,X_test,y_train,y_test = train_test_split(X, y, test_size = 0.25) ``` ## 訓練模型 ``` from sklearn.tree import DecisionTreeClassifier clf = DecisionTreeClassifier(criterion = 'entropy',max_depth= 9, random_state = 10).fit(X_train, y_train) ``` :::info 利用matplotlib畫出學習曲線來確認最優的max-depth ::: ``` import matplotlib.pyplot as plt from sklearn import tree y_eff = [] for i in range(10): # 測試的條件數 tree_clf = tree.DecisionTreeClassifier(criterion="entropy" ,random_state = 10 ,splitter = "best" ,max_depth = i+1 #測試條件 ) tree_clf = tree_clf.fit(X_train,y_train) score = tree_clf.score(X_test,y_test) y_eff.append(score) plt.plot(range(1,11),y_eff,color="red",label="max_depth") plt.legend() plt.show() ``` ![](https://i.imgur.com/G4bEsDH.png) :::info 因此我們將 max-depth 設為 9 ::: ## 評估模型 - 混淆矩陣 ``` from sklearn.metrics import confusion_matrix y_pred = clf.predict(X_test) confusion_matrix(y_test, y_pred) ``` ![](https://i.imgur.com/3ZxAHra.png) ``` from sklearn.metrics import plot_confusion_matrix import matplotlib.pyplot as plt plot_confusion_matrix(clf, X_test,y_test) ``` ![](https://i.imgur.com/Xb2P7KE.png) - accuracy ``` # accuracy from sklearn.metrics import accuracy_score accuracy = accuracy_score(y_test, y_pred) accuracy ``` :::info (TP + TN) / (TP + TN + FP + FN) (52 + 123) / (52 + 123 + 32 + 23) 約等於 0.7609 ::: ![](https://i.imgur.com/cnn7xP3.png) - precision 在所有預測為正樣本中,有多少為正樣本 ``` from sklearn.metrics import precision_score precision_score(y_test, y_pred) ``` :::info TP / (TP + FP) 52 / (52 + 32) 約等於 0.62 ::: ![](https://i.imgur.com/ww5RVdT.png) - recall 在所有正樣本當中,能夠預測多少正樣本的比例 ``` #recall from sklearn import metrics metrics.recall_score(y_test, y_pred) ``` :::info TP / (TP + FN) 52 / (52 + 23) 約等於 0.69 ::: ![](https://i.imgur.com/VdZxzMJ.png) ## 決策樹可視化 以下分別使用 Graphviz 與 使用scikit-learn的 tree.plot_tree 方法將決策數視覺化,Graphviz 好處是可以匯出pdf,若沒有這需求的話就可以使用scikit-learn就好。 1.使用Graphviz將決策樹視覺化 ``` from sklearn.tree import export_graphviz import os os.environ["PATH"] += os.pathsep + 'C:\Program Files\Graphviz\bin' ``` - 匯出PDF ``` import pydotplus dot_data=tree.export_graphviz(clf,out_file=None) graph=pydotplus.graph_from_dot_data(dot_data) graph.write_pdf('game of thrones.pdf') ``` - 直接將圖畫出來看 ``` from IPython.display import Image #將 Decisson Tree Classifier 放入 dot_data = tree.export_graphviz(clf, out_file=None, filled=True, rounded=True, special_characters=True) graph = pydotplus.graph_from_dot_data(dot_data) Image(graph.create_png()) ``` ![](https://i.imgur.com/YWd2CTq.png) 2. 從scikit-learn 版本21.0開始,可以使用scikit-learn的 tree.plot_tree 方法來利用matplotlib將決策樹視覺化,而不再需要依賴於難以安裝的dot庫。 ``` fig, ax = plt.subplots(figsize=(25, 25)) tree.plot_tree(clf, ax=ax, fontsize=12) plt.show() ``` ## 結論 這次的重點在於熟悉決策樹的建立與使用,學習到的觀念與工具大概有以下: - 資料前處理 -> one hot encoding - 資料建模 -> scikit-learn DecisionTreeClassifier - 評估模型 -> confusion matrix、precsion、recall、accuracy - 決策數可視化 -> Graphviz 、sckit-learn tree.plot_tree(簡單易用) :::info 這篇主要藉由課堂作業,寫下來的筆記,主要是針對新手觀看, 若有任何疑問或是更好的建議,歡迎大家留言指教討論 :smile: :::