---
# System prepended metadata

title: 使用Decision Tree預測權力遊戲角色是否存活
tags: [課堂作業, Data science]

---

使用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: 
:::











