KSLab_M1
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 8_決策樹 ## Source <!-- - 大數據分析與資料探勘 W11 --> - 應⽤機器學習於Python C2-4 ## 課堂投影片與練習 - [ ] **今日學習目標** * 理解決策樹的基本概念與工作原理。 * 認識決策樹的優點與限制。 * 掌握決策樹在實際問題中的應用。 * 透過Python實作,建立並評估決策樹模型。 --- - [ ] **決策樹概念:為什麼需要它?** * **情境:** 假設你是一位披薩公司(如:必勝客、達美樂)的資料科學家,成功建立了一個分類模型,能預測披薩是美味還是難吃的披薩。 * 你的模型決策邊界是數學公式:`-100 + 6*溫度 + 3*濕度 = 0`。 * 當你向主管和製作披薩的人員講解此模型時,他們可能會覺得「你到底在說什麼啊?」甚至覺得「你根本不懂怎麼烤披薩的基本知識」。因為只給數學公式,大家常常無法理解模型是如何做出判斷的。 * **問題:** 如何才能讓你的模型更容易被理解,並贏得業務團隊的信任呢? * **答案:** 模型的**「可解釋性 (Interpretability)」**在真實環境中非常重要。而**決策樹就是一個解釋性能力很強的模型**。 --- - [ ] **決策樹概念:什麼是決策樹?** * **定義:** 決策樹它是一個**樹型結構的分類演算法**。它也具有**監督式的特徵萃取與描述**功能,能將輸入變數根據目標設定選擇分枝方式,並以樹枝狀的層級架構呈現,萃取分類規則。 * **核心思想:** 決策樹的分類主要是從最上方的**樹根**開始,將特徵變數切分到不同的子樹或節點,透過不斷的切割,最終成為具有決策節點的**葉節點**。 * **範例解釋:** 與其說「-100 + 6\*溫度 + 3\*濕度 > 0 預測是一個美味的披薩」,不如說「在烘烤披薩過程中,只要**溫度維持在120~125度,濕度維持在5%~7%**,就會是一個很美味的披薩」。這樣的話,老闆跟製作Pizza人員就能立即理解。 --- - [ ] **決策樹概念:決策樹的組成** * **樹根 (Root Node):** * 位於決策樹的最上方,是資料切分的起點。 * 例如:在鐵達尼號生存率的分析中,根節點可能是「性別 (Sex)」。 * **決策節點 / 內部節點 (Internal Node / Decision Node):** * 位於樹的中間,用於根據特徵變數進行切分,引導資料流向不同的子節點。 * **葉節點 (Leaf Node):** * 位於樹的最底層,沒有子節點,通常代表最終的決策結果或分類結果。 * 例如:鐵達尼號範例中,葉節點會顯示出「存活率最高的是誰」或「存活率較低的人來自哪裡」等決策結果。 --- - [ ] **決策樹概念:如何進行切分?** * **目標:** 在決策樹中,我們希望**每一個節點的「資訊增益 (Information Gain)」都是最大的**。資訊增益就是**原始資料的總訊息減去分枝後的總訊息**。 * **常用衡量方法:** * **熵 (Entropy):** * 來自熱力學的量,用來計算一個系統中失序的現象。 * 套用到資訊理論上,它代表了**接收每條信息中包含的資訊平均量**。熵值越高,表示資料的離散程度或亂度越高,**不確定性越大**。 * **Gini 係數 (Gini Index):** * 衡量資料集合對於所有類別的**不純度 (impurity)**。 * 我們希望透過分枝,能最大幅度地**減少不純度**。 * **Scikit-Learn 的預設演算法:** Python 中常用的機器學習套件 Scikit-Learn 所使用的決策樹演算法是 **CART (Classification and Regression Tree)**,它主要以 **Gini 係數**作為決定分枝變數的準則,建立**二分式**的決策樹。 --- - [ ] **課堂練習:決策樹概念理解** 1. **任務:** 請用自己的話解釋「決策樹」是什麼,以及它與我們之前學過的「羅吉斯迴歸」模型相比,最大的優勢是什麼? 2. **任務:** 決策樹的「葉節點」代表什麼?請舉一個除了鐵達尼號生存率之外的例子來解釋。 3. **思考:** 為什麼決策樹在進行節點切分時,會希望「資訊增益」最大化?這和我們想要「好好分類」有什麼關係? --- - [ ] **決策樹的優點** * **高可解釋性 (Interpretability):** * 模型結果直觀,易於理解和解釋。 * 可以直接提出「如果...則...」的規則,便於與非技術人員溝通和分享模型洞察。 * **容易提取規則:** * 從決策樹的結構中,可以輕鬆地歸納出分類或預測的規則。 * **適用於多類別變數的大型資料集:** * 能處理包含許多類別型特徵的大型資料集。 * **無需特徵縮放:** * 決策樹對數值型特徵的尺度不敏感,通常不需要像其他模型一樣進行標準化或正規化。 (非來源資訊,可提醒學生) --- - [ ] **決策樹的缺點** * **抗噪性較低:** * 容易受到資料中**雜訊 (Noise)** 的影響。 * **容易過度學習 (Overfitting) 或低度學習 (Underfitting):** * **樹越大,過度學習的機率會較高**。這表示模型在訓練資料上表現很好,但在新的、未見過的資料上表現很差。 * **樹越小,低度學習的機率也會較高**。這表示模型無法充分捕捉資料中的模式,導致在訓練資料和新資料上表現都不好。 * **結果穩定性較差:** * 決策樹的結果常常會因為特徵數量的微小不同而產生不一樣的變化。這使得模型在面對略微變化的資料時,其決策邊界可能會劇烈變化。 * **對不平衡資料敏感:** (非來源資訊,可提醒學生) * 如果某些類別的樣本數量遠多於其他類別,決策樹可能會偏向多數類別,導致對少數類別的預測效果不佳。 --- - [ ] **決策樹的優化:修剪 (Pruning)** * 為了解決過度學習和低度學習的問題,在決策樹中有一種叫做**「修剪 (Pruning)」**的技術。 * **預先修剪 (Pre-pruning):** * 這是我們**比較常使用**的一種方法。 * 它在決策樹**生長過程中**就設定停止門檻值。當分割的評估值未達到此門檻時,就會停止生長。例如:設定資訊增益比必須大於0.1,或資料比數要超過5才繼續分枝。 * **優點:** 執行效率較高,且能提早停止學習,常常就可以幫助我們**解決過度學習的問題**。 * **缺點:** 可能導致**過度修剪 (over-pruning)**,且門檻值設定不易。 * **事後修剪 (Post-pruning):** * 讓決策樹可以隨意發展,**等樹都長完了**,我們才用專業的知識去判斷是否將多餘的分支剪掉。 * **優點:** 可避免過度修剪,以及加強對雜訊的忍受程度。 * **缺點:** 效率較低。 * **常見方法:** 最小成本複雜度修剪 (Minimal Cost-Complexity Pruning)。 --- - [ ] **課堂練習:優缺點與修剪** 1. **情境題:** 你的公司想要用機器學習模型來預測客戶流失,並且希望業務團隊能夠理解這個模型,以便他們採取精準的挽留措施。請問你會推薦使用決策樹嗎?為什麼? 2. **思考題:** 什麼是「過度學習 (Overfitting)」?如果你的決策樹模型發生了過度學習,你會考慮採取哪種「修剪」策略來改善?為什麼? 3. **討論:** 決策樹的結果穩定性較差,這可能帶來什麼潛在問題? --- - [ ] **決策樹的應用場景** * **分類問題 (Classification):** * **鐵達尼號生存率分析:** 根據乘客的性別、艙等、年齡等特徵預測其是否存活。 * **鳶尾花分類:** 根據花萼和花瓣的長度、寬度將鳶尾花分為不同品種。 * **員工績效評估:** 根據年資、教育程度、經驗等預測員工績效等級。 * **迴歸問題 (Regression):** * **波士頓房價預測:** 根據房屋特徵預測房價。 * **薪資預測:** 根據員工特徵預測月收入。 * **其他常見應用:** * 客戶行為分析 (例如:判斷客戶是否會購買某產品) * 醫療診斷輔助 (例如:根據症狀判斷疾病) * 風險評估 (例如:判斷貸款申請人的信用風險) --- - [ ] **實作範例:鐵達尼號生存預測 (分類問題)** * **資料集介紹:** 鐵達尼號生存範例是一個**很經典的分類教學問題**,非常適合用決策樹的數學模型來解釋分類如何操作。 * **變數包含:** 存活與否 (Survived)、船票等級 (Pclass)、性別 (Sex)、年齡 (Age)、配偶/手足人數 (SibSp)、父母/小孩人數 (Parch)、票價 (Fare)、船艙號 (Cabin) 以及登船港口 (Embarked) 等。 * **流程概覽:** 我們將依循資料分析的標準流程:**資料探索 -> 資料前處理 -> 模型建立 -> 模型評估 -> 結果匯出**。 * **程式碼環境:** 我們將使用 **Python 語言搭配 Scikit-learn 函式庫**來進行實作。 --- - [ ] **實作範例:資料探索 - 載入與概覽** * 通常在資料分析比賽中,主辦單位會提供資料下載連結或直接存取URL,這樣就不需要把非常大的資料集下載到本機端。 * 我們將利用 `pandas` 函式庫來載入資料,並使用 `info()` 和 `head()` 兩個常用函數來快速查看資料的結構和前幾筆內容,以初步了解資料的狀況。 ```python= # 匯入必要的函式庫 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns df_train = pd.read_csv('train.csv') print("--- 資料概覽 (df_train.info()) ---") df_train.info() print("\n--- 資料前五筆 (df_train.head()) ---") df_train.head() ``` --- **實作範例:資料探索 - 視覺化分析** * 透過視覺化圖表,我們可以更直觀地理解資料分佈和變數間的關係。這是資料分析中非常重要的一步! * **範例:** * **不同登船口的分佈:** 我們發現大多數人都是從 'S' 這個登船口登船的。 * **不同性別的存活人數分析:** 可以觀察到女性的存活率通常比男性高,這與當時「老弱婦孺優先上救生船」的常識相符。 * **不同艙等的存活率:** 頭等艙 (Pclass=1) 的存活率通常是最高的,因為他們有最高的優先順序,且更接近救生船。 * **家庭人數與存活率:** 資料探索顯示,隨着家庭人數的增加,存活率會降低,尤其有5到8個成員的大家庭,存活率甚至可能是0。 ```python= #不同登船口的分佈 sns.countplot(x='Embarked', data=df_train) plt.title('不同登船口的分佈') plt.show() #不同性別的存活人數分析 sns.countplot(x='Sex', hue='Survived', data=df_train) plt.title('不同性別的存活人數分析') plt.show() #不同艙等的存活率 sns.countplot(x='Pclass', hue='Survived', data=df_train) plt.title('不同艙等的存活率') plt.show() #家庭人數與存活率 sns.countplot(x='SibSp', hue='Survived', data=df_train) plt.title('家庭人數與存活率') plt.show() ``` --- - [ ] **實作範例:資料前處理 - 處理缺失值** * 在現實世界的資料中,經常會遇到**缺失值 (NA/NaN)** 的情況,需要進行處理,否則模型可能無法正確運行。 * **年齡 (Age):** * 這個欄位有較多缺失值。 * 由於年齡分佈很廣 (從兒童到80歲的長者),如果使用平均數來填充,容易引入偏差。 * 因此,我們決定使用**中位數 (Median)** 來取代缺失值,因為中位數對極端值不那麼敏感。 * **登船港口 (Embarked):** * 這個欄位也有一些缺失值。 * 在資料探索時我們發現,從 'S' 這個登船口登船的人數最多。 * 因此,我們假設缺失的登船口最可能是 'S',並使用**眾數 (Mode)** 'S' 來填充。 * **船艙號 (Cabin):** * 這個欄位的缺失值非常多,甚至超過了資料的一半。 * 根據常識,船艙號可能與艙等 (`Pclass`) 和票價 (`Fare`) 有關聯,但在我們的分析中,其重要性可能較低。 * 因此,為了簡化模型,我們決定直接**刪除 (Drop)** 此欄位。 ```python= # 處理缺失值 # 1. 年齡 (Age):用中位數取代 df_train['Age'].fillna(df_train['Age'].median(), inplace=True) # 2. 登船港口 (Embarked):用眾數 'S' 取代 # 先找到眾數 most_frequent_embarked = df_train['Embarked'].mode() df_train['Embarked'].fillna(most_frequent_embarked, inplace=True) # 3. 船艙號 (Cabin):直接刪除 df_train.drop('Cabin', axis=1, inplace=True) # 檢查是否還有缺失值 print("處理缺失值後,各欄位的缺失值數量:") print(df_train.isnull().sum()) ``` --- - [ ] **實作範例:資料前處理 - 特徵工程與編碼** * **建立新特徵 (Feature Engineering):** * 有時候原始資料的特徵不足以表達其潛在關係,我們需要**創造新的特徵**。 * **`TravelAlong` (是否有家人同行):** 我們觀察到 `SibSp` (手足/配偶人數) 和 `Parch` (父母/小孩人數) 這兩個欄位都代表了家庭成員的資訊。在逃生時,家人是兄弟姐妹或父母都一樣重要。因此,我們將這兩個變數合併為一個新的變數 `TravelAlong`。如果 `SibSp` 或 `Parch` 任何一個不為0,則 `TravelAlong` 為1 (表示有家人同行),否則為0 (表示獨自一人)。 * 建立新特徵後,原始的 `SibSp` 和 `Parch` 欄位就可以刪除,因為它們的資訊已被 `TravelAlong` 取代。 * **刪除不必要的特徵:** * 像 `PassengerId` (乘客ID)、`Name` (姓名)、`Ticket` (船票號碼) 這些欄位屬於**個人資料**,在做資料分析時通常**不重要**,因為它們與生存與否的模式關係不大,因此我們會將它們刪除。 * **類別變數編碼 (Encoding):** * 機器學習模型通常只能處理**數值型資料**。因此,我們需要將像「性別 (Sex)」和「登船港口 (Embarked)」這樣的**類別變數 (Categorical Variables)** 轉換為數值。 * 我們可以使用 Scikit-learn 中的 **`LabelEncoder`** 來完成這件事。它會將不同的類別映射為不同的整數數字。例如,性別可能轉換為0和1 (男/女),登船港口可能轉換為0, 1, 2。 ```python= from sklearn.preprocessing import LabelEncoder # 1. 建立新特徵 'TravelAlong' # 如果 SibSp 或 Parch 任何一個大於 0,則 TravelAlong 為 1,否則為 0 df_train['TravelAlong'] = ((df_train['SibSp'] > 0) | (df_train['Parch'] > 0)).astype(int) # 2. 刪除不必要的特徵 (包括已被 TravelAlong 取代的 SibSp 和 Parch) df_train.drop(['PassengerId', 'Name', 'Ticket', 'SibSp', 'Parch'], axis=1, inplace=True) # 3. 類別變數編碼 # 性別 (Sex) le_sex = LabelEncoder() df_train['Sex'] = le_sex.fit_transform(df_train['Sex']) # male/female -> 0/1 # 登船港口 (Embarked) le_embarked = LabelEncoder() df_train['Embarked'] = le_embarked.fit_transform(df_train['Embarked']) # C/Q/S -> 0/1/2 print("\n--- 前處理後資料前五筆 (df_train.head()) ---") print(df_train.head()) print("\n--- 前處理後資料型態 (df_train.info()) ---") df_train.info() ``` --- - [ ] **實作範例:模型建立與訓練** * **區分特徵 (X) 和目標變數 (Y):** * `X` 代表我們用來預測的**輸入特徵** (例如:艙等、性別、年齡、票價等)。 * `Y` 代表我們想要預測的**目標變數** (在本例中是「存活」與否)。 * **劃分訓練集與測試集:** * 在建立模型之前,我們會將資料劃分為**訓練集 (Training Set)** 和**測試集 (Testing Set)**。 * 訓練集用於**模型學習**資料中的模式,而測試集則用於**評估模型在未知資料上的表現**,模擬真實世界的預測情況。 * 通常,訓練集佔總資料的70%,測試集佔30%。 * **載入決策樹分類器:** * 我們從 `sklearn.tree` 中匯入 `DecisionTreeClassifier`。 * **設定模型參數:** * `max_depth` (樹的最大深度) 是決策樹非常重要的參數,它**可以限制樹的生長,防止過度學習**。 * 我們不知道樹的最佳深度應該是多深,所以會透過迴圈來設定從2到10的不同深度,看看哪一個深度能讓模型有最好的分類表現。 ```python= from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score # 定義特徵 (X) 和目標變數 (Y) # 移除 'Survived' 欄位作為特徵,保留其他欄位 X = df_train.drop('Survived', axis=1) # 將 'Survived' 欄位作為目標變數 Y = df_train['Survived'] # 劃分訓練集和測試集 # test_size=0.3 表示測試集佔總資料的30% # random_state=42 用於確保每次運行結果一致 (可重現性) X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3, random_state=42) print(f"訓練集特徵 (X_train) 樣本數: {len(X_train)}") print(f"訓練集目標 (Y_train) 樣本數: {len(Y_train)}") print(f"測試集特徵 (X_test) 樣本數: {len(X_test)}") print(f"測試集目標 (Y_test) 樣本數: {len(Y_test)}") ``` --- - [ ] **實作範例:尋找最佳樹深度** * 為了找到最適合模型的樹深度,我們可以建立一個迴圈,**嘗試不同的 `max_depth` 設定 (從2到10)**,並評估每個模型的表現。 * **評估指標:** * **Accuracy (準確率):** 最直觀的指標,表示模型正確預測的比例。 * **Precision (精確率)、Recall (召回率)、F1-Score (F1分數):** 這些是更全面的分類模型評估指標。例如,**精確率**關注在所有被模型預測為正類別的樣本中,有多少是真正屬於正類別的;**召回率**則關注所有真正屬於正類別的樣本中,有多少被模型成功找出。 ```python= # 嘗試不同深度來尋找最佳模型 best_accuracy = 0 best_depth = 0 model_performance = [] # 用來儲存不同深度模型的表現 # 迴圈從深度 2 到 10 (range(2, 11) 表示從 2 開始,到 10 結束) for depth in range(2, 11): # 建立決策樹分類器模型,設定當前迴圈的 max_depth dt_classifier = DecisionTreeClassifier(max_depth=depth, random_state=42) # 使用訓練資料來擬合 (Fit) 模型 dt_classifier.fit(X_train, Y_train) # 使用測試資料來進行預測 (Predict) Y_pred = dt_classifier.predict(X_test) # 計算模型的評估指標 accuracy = accuracy_score(Y_test, Y_pred) # precision_score 和 recall_score 在某些情況下如果只有一類被預測到,可能會產生警告 # zero_division=0 參數可以避免這個警告,並將該指標值設為 0 precision = precision_score(Y_test, Y_pred, zero_division=0) recall = recall_score(Y_test, Y_pred, zero_division=0) f1 = f1_score(Y_test, Y_pred, zero_division=0) # 將結果儲存到列表中 model_performance.append({ 'Depth': depth, 'Accuracy': accuracy, 'Precision': precision, 'Recall': recall, 'F1-Score': f1 }) # 如果當前模型的準確率比之前的最佳準確率更高,則更新最佳深度和準確率 if accuracy > best_accuracy: best_accuracy = accuracy best_depth = depth print("\n--- 不同樹深度下的模型表現 ---") for perf in model_performance: # 格式化輸出,保留四位小數 print(f"深度: {perf['Depth']}, 準確率: {perf['Accuracy']:.4f}, " f"精確率: {perf['Precision']:.4f}, 召回率: {perf['Recall']:.4f}, " f"F1分數: {perf['F1-Score']:.4f}") print(f"\n根據準確率,最佳樹深度為: {best_depth} (準確率: {best_accuracy:.4f})") # 根據來源的範例,最佳深度為6,準確率為0.813433 ``` --- - [ ] **課堂練習:模型訓練與評估** 1. **任務:** 在Python程式碼中,`test_size=0.3` 代表什麼意思?為什麼我們需要將資料劃分為訓練集和測試集? 2. **任務:** 試著將 `random_state` 的值改為不同的數字 (例如:1、10、100),重新執行程式碼,觀察最佳深度和準確率是否有變化。這說明了什麼? 3. **討論:** 如果我們在預測疾病時,希望盡量找出所有真正患病的病人 (即使會有一些誤報),那麼在評估模型時,你會更關注「精確率 (Precision)」、「召回率 (Recall)」還是「準確率 (Accuracy)」?為什麼? --- - [ ] **實作範例:模型視覺化** * 訓練好的決策樹模型可以被視覺化,這對於理解模型的決策邏輯非常有幫助。 * **`export_graphviz`:** Scikit-learn 提供這個函數,可以將決策樹輸出為 **`.dot` 格式的檔案**。這個 `.dot` 檔案可以被 **Graphviz 軟體**讀取並轉換成圖片檔 (例如:`.png` 或 `.jpg`)。 * **如何解讀決策樹圖:** * 圖中的每個方框代表一個**節點**。 * 每個節點內會顯示用於切分的**特徵條件** (例如:`Sex <= 0.5`)。 * 根據條件判斷結果,資料會流向左邊 (通常是 `True`) 或右邊 (通常是 `False`) 的子節點。 * 最終到達的**葉節點**會顯示該路徑下的**最終分類結果** (例如:`class = Survived`)。 **安裝必要套件 (Graphviz + pydotplus)** ```cmd= # 安裝套件(Graphviz + pydotplus) !apt-get install -y graphviz !pip install graphviz pydotplus ``` **模型視覺化** ```python= # 匯入套件 from sklearn.tree import export_graphviz import pydotplus from IPython.display import Image import graphviz # 重新訓練最佳模型(保險起見) final_dt_classifier = DecisionTreeClassifier(max_depth=best_depth, random_state=42) final_dt_classifier.fit(X_train, Y_train) # 特徵與類別名稱 feature_names = X.columns.tolist() class_names = ['Not Survived', 'Survived'] # ➤ 1. 儲存為 .dot 檔案(可供下載或外部轉檔用) export_graphviz( final_dt_classifier, out_file='titanic_decision_tree.dot', feature_names=feature_names, class_names=class_names, filled=True, rounded=True, special_characters=True ) print(".dot 檔案已儲存為 'titanic_decision_tree.dot'") # ➤ 2. 轉成圖形,inline 顯示在 Colab/Jupyter 中 dot_data = export_graphviz( final_dt_classifier, out_file=None, feature_names=feature_names, class_names=class_names, filled=True, rounded=True, special_characters=True ) graph = pydotplus.graph_from_dot_data(dot_data) Image(graph.create_png()) ``` --- **實作範例 : 模型預測** * 假設我們要預測一個新的乘客是否存活,這裡我們需要輸入所有特徵的值,並且確保順序和前處理方式一致 * 假設新乘客資料: Pclass=3, Sex=male(1), Age=30, Fare=15, Embarked=S(2), TravelAlong=0(No) * **注意:這裡的數值必須是經過 LabelEncoder 編碼後的結果** ```python= new_passenger_features = pd.DataFrame([ [3, 1, 30, 15.0, 2, 0]], columns=['Pclass', 'Sex', 'Age', 'Fare', 'Embarked', 'TravelAlong']) # 使用訓練好的模型進行預測 predicted_survival = final_dt_classifier.predict(new_passenger_features) # 使用 predict_proba 估計屬於各類別的機率 predicted_proba = final_dt_classifier.predict_proba(new_passenger_features) print(f"\n預測新乘客的存活結果: {predicted_survival} (0: 死亡, 1: 存活)") print(f"預測為死亡的機率: {predicted_proba[0][0]:.4f}") print(f"預測為存活的機率: {predicted_proba[0][1]:.4f}") ``` --- - [ ] **課堂練習:決策樹視覺化與解讀** 1. **任務:** 如果你成功將決策樹視覺化成圖片,請試著追蹤一條從根節點到任意一個葉節點的路徑。這條路徑代表了什麼樣的決策規則? 2. **任務:** 解釋 `predict_proba()` 函式在決策樹中的作用是什麼?它提供了什麼額外的信息? 3. **思考:** 除了 `max_depth` 之外,`DecisionTreeClassifier` 還有哪些參數可以控制樹的形狀?(例如:`min_samples_leaf`、`max_leaf_nodes`)。這些參數對決策樹的生長和過度學習問題有何影響? --- - [ ] **實作範例:迴歸問題 - 波士頓房價預測** * 決策樹不僅可以用於**分類問題**,也可以用於**迴歸問題**,這時我們使用**決策樹迴歸器 (DecisionTreeRegressor)**。 * **模型:** 從 `sklearn.tree` 匯入 `DecisionTreeRegressor`。 * **評估指標:** * 迴歸模型的績效通常以**最小極值**為主。 * 常見的迴歸評估指標包括: * **R² (決定係數):** 衡量模型解釋變異的比例,值越接近1越好。 * **MAE (平均絕對誤差):** 預測值與真實值之間絕對差值的平均值,越小越好。 * **MSE (均方誤差):** 預測值與真實值之間平方差值的平均值,對大誤差懲罰較重,越小越好。 * **RMSE (均方根誤差):** MSE 的平方根,與原始數據單位相同,越小越好。 * **表現:** 決策樹做迴歸分析**未必會比線性模型差,有時候還會有比較好的表現**。 ```python= from sklearn.tree import DecisionTreeRegressor from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error from sklearn.model_selection import train_test_split import pandas as pd import numpy as np # 載入波士頓房價資料集 (在較新版本的 sklearn 中已被移除,這裡使用 try-except 或模擬數據) try: from sklearn.datasets import load_boston boston = load_boston() X_boston = pd.DataFrame(boston.data, columns=boston.feature_names) Y_boston = pd.Series(boston.target, name='MEDV') print("已成功載入波士頓房價資料集。") except ImportError: print("警告: load_boston 在當前 sklearn 版本中可能已棄用。將使用模擬數據集進行演示。") # 建立一個簡易的模擬數據集用於演示 np.random.seed(42) # 設置隨機種子以確保結果可重現 X_boston = pd.DataFrame(np.random.rand(200, 5), columns=[f'Feature_{i}' for i in range(5)]) Y_boston = pd.Series(20 + 5 * X_boston['Feature_0'] + 3 * X_boston['Feature_1'] - 2 * X_boston['Feature_2'] + np.random.randn(200) * 5) print("已使用模擬數據集。") # 劃分訓練集和測試集 X_train_boston, X_test_boston, Y_train_boston, Y_test_boston = \ train_test_split(X_boston, Y_boston, test_size=0.3, random_state=42) # 建立決策樹迴歸模型 # max_depth 參數同樣重要,可以防止過度學習 dt_regressor = DecisionTreeRegressor(max_depth=5, random_state=42) dt_regressor.fit(X_train_boston, Y_train_boston) # 進行預測 Y_pred_boston = dt_regressor.predict(X_test_boston) # 評估模型表現 r2 = r2_score(Y_test_boston, Y_pred_boston) mae = mean_absolute_error(Y_test_boston, Y_pred_boston) mse = mean_squared_error(Y_test_boston, Y_pred_boston) rmse = np.sqrt(mse) # RMSE 是 MSE 的平方根 print("\n--- 決策樹迴歸模型表現 ---") print(f"R² (決定係數): {r2:.4f}") print(f"MAE (平均絕對誤差): {mae:.4f}") print(f"MSE (均方誤差): {mse:.4f}") print(f"RMSE (均方根誤差): {rmse:.4f}") ``` --- - [ ] **總結與展望** * **決策樹:** 是一種**直觀、可解釋性強**的機器學習模型,適用於**分類和迴歸**問題。 * **優點:** 易於理解其決策邏輯、結果可轉換為規則、無需複雜的資料預處理 (如特徵縮放)。 * **缺點:** 對資料中的雜訊較敏感、容易發生過度學習或低度學習。 * **優化:** 可以透過**「修剪 (Pruning)」**技術來控制樹的複雜度,改善模型的泛化能力。 * **進階概念 (簡要提及,非本課程重點):** * **整合學習 (Ensemble Learning):** 透過結合**多個決策樹 (或多個模型)**,可以顯著提高模型的預測準確率和穩定性。這就像「三個臭皮匠,勝過一個諸葛亮」。 * **Bagging (拔靴整合):** 一種整合學習方法,透過**重複取樣**訓練多個模型,然後將它們的預測結果**聚合** (例如:分類問題用「投票」,迴歸問題用「平均」)。 * **隨機森林 (Random Forest):** 是一種非常流行的整合學習方法,它是 **Bagging 概念的一種應用**。它訓練多個決策樹,並在每個節點隨機選擇特徵進行分枝,進一步提高了模型的穩定性和準確率。這是一種非常強大且廣泛使用的模型!

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully