「客戶流失預測模型」詳解

本案例將帶領我們進入「分類 (Classification)」的世界,這是機器學習中另一大核心任務。我們將學習如何建立一個模型,來預測一個類別型結果——顧客「是」或「否」會流失。課程的重點在於分類模型獨有的資料前處理技巧,以及如何評估模型的預測成效。

1. 環境設定:中文字型

核心概念: matplotlibseaborn 套件預設並未包含中文字型,若直接繪圖,圖表中的中文(如標題、座標軸標籤)將會顯示為無法辨識的方塊亂碼(暱稱為豆腐)。因此,繪製中文圖表前的第一步,就是手動安裝並設定字型。

本案例應用重點:

  • !wget ...: 我們在 Colab 中使用 wget 這個指令,從網路上下載一個開源的思源黑體字型檔 (.otf 檔),並將其存放在系統的字型路徑中。
  • import matplotlib.font_manager as fm: 引入字型管理器,用來讀取我們剛下載的字型檔。
  • plt.rcParams['font.family'] = ...: 這是最關鍵的一步,透過 rcParams (runtime configuration parameters) 這個設定,我們明確地告知 matplotlib:「接下來所有的圖表,請一律使用我們剛剛指定的那個中文字型來繪製。」

2. 載入數據

  • files.upload(): 執行這行程式碼時,Colab 會在您的瀏覽器中跳出一個檔案上傳的對話視窗,讓您可以從本機電腦選擇要上傳的檔案
  • uploaded = ...: 當您選擇檔案並完成上傳後,files.upload() 會回傳一個 Python 字典 (dictionary),裡面包含了您上傳的檔案資訊(檔名作為 key,檔案內容作為 value)。這個字典會被存放在 uploaded 這個變數中。
  • try: ... except Exception as e: ...:這是一個錯誤處理的結構。
    • try:: 程式會嘗試執行 try 區塊內的所有程式碼。
    • except Exception as e:: 如果在 try 的過程中,發生任何錯誤(例如,上傳的檔案不是 CSV 格式、檔案已損毀等),程式不會因此崩潰,而是會跳到 except 區塊,執行裡面的程式碼來處理這個例外狀況。
  • file_name = next(iter(uploaded)):因為 uploaded 是一個字典,我們需要從中取出檔名。
    • iter(uploaded) 會建立一個字典鍵(也就是檔名)的迭代器。
    • next(...) 則會從這個迭代器中取出第一個項目。由於我們一次只上傳一個檔案,所以這樣就能成功取得該檔案的檔名。
如果使用本地端的編輯器執行Python腳本(例如Spyder,VSCode),只要設定好工作目錄,就可以直接使用pandas read_csv() 方法載入數據集。upload()是用在當你使用colab環境時。

3. Pandas – 分類模型的預處理 (Preprocessing)

核心概念: 機器學習模型只能理解數字,無法直接處理文字類型的類別資料(例如 Gender 欄位的 ‘Male’/’Female’)。因此,在訓練模型前,我們必須將這些文字轉換為數值格式。

本案例應用重點:

  • le.fit_transform(df_processed['Churn']) :將文字類型的目標變數轉換為數值
    • LabelEncoder: 這是 scikit-learn 函式庫中的一個工具,中文稱為「標籤編碼器」。它的唯一功能,就是將文字標籤(例如 ‘Yes’, ‘No’ 或 ‘蘋果’, ‘香蕉’)轉換成數字編碼(例如 0, 1, 2)。
    • le = ...: 這行程式碼的作用是建立一個 LabelEncoder 的實例,您可以想像成我們準備好了一台「標籤編碼機」,並將它命名為 le
    • 整個轉換的核心做了兩件事情:fit (學習) 和 transform (轉換)。
    • fit (學習):
      • fit_transform 會先掃描 df_processed['Churn'] 這個欄位,找出裡面所有不重複的文字標籤。在這個案例中,它會找到 'No''Yes' 這兩種。
      • 接著,它會在內部建立一個對應的規則,通常是按照字母順序來編碼,例如:‘No’ -> 0, ‘Yes’ -> 1。這個過程就是 fit,代表編碼機已經「學會」了轉換的規則。
    • transform (轉換):
      • 學會規則後,編碼機會再次遍歷 Churn 欄位中的每一個值,並根據剛剛學會的規則,將所有的 'No' 都換成 0,所有的 'Yes' 都換成 1
  • pd.get_dummies(): 這是本案例最關鍵的資料前處理步驟,稱為 One-Hot Encoding。它會自動將所有文字類型的欄位(如 Gender, Contract, HasSupportTicket)轉換成多個 0 和 1 的新欄位,讓機器學習模型能夠理解這些類別資訊。
    • drop_first=Truepd.get_dummies() 函式中一個非常重要的參數,它的主要目的是為了避免「多重共線性」(Multicollinearity),也常被稱為虛擬變數陷阱 (Dummy Variable Trap)。用一個簡單的例子來解釋:假設我們有一個 Gender 欄位,裡面只有 ‘Male’ 和 ‘Female’ 兩種值。
    • 如果「不使用」drop_first=True
      • pd.get_dummies() 會產生兩個新的欄位:Gender_MaleGender_Female
      • 如果某位客戶是男性,那 Gender_Male 會是 1,Gender_Female 會是 0。
      • 如果某位客戶是女性,那 Gender_Male 會是 0,Gender_Female 會是 1。
      • 問題:這兩個新欄位是完全相關的。只要我們知道 Gender_Male 的值,就能 100% 推斷出 Gender_Female 的值(例如 Gender_Male 是 0,Gender_Female 必定是 1)。這種完美的線性關係會對某些機器學習模型(特別是線性迴歸)造成干擾,讓模型難以穩定地估計出各個特徵的影響力。
    • 如果「使用」了 drop_first=True
      • pd.get_dummies() 會先產生 Gender_FemaleGender_Male 兩個欄位,然後丟棄第一個(在此例中是 Gender_Female),只留下 Gender_Male 這一個欄位。
      • 現在,模型的解讀方式變成:
        • 如果 Gender_Male 是 1,代表該客戶是男性。
        • 如果 Gender_Male 是 0,代表該客戶不是男性,也就是女性(這就是被丟棄的那個基準類別)。
      • 好處:我們只用一個欄位,就完整地保留了原始的性別資訊,同時完全避免了欄位間的完美相關性,讓模型能更穩定地運作。
    • 總結來說,drop_first=True 的目的就是在進行 One-Hot Encoding 時,自動捨棄掉一個多餘的參考欄位,以避免多重共線性的問題,讓後續的機器學習模型更穩健。
  • pd.to_numeric(errors='coerce'): 在資料清理階段,確保費用相關的欄位都是數值型態。errors='coerce' 是一個重要的參數,它會自動將任何無法轉換為數字的值變為 NaN (缺失值),方便我們後續統一處理。
  • 用中位數填補空值:
    • df_processed['TotalCharges']:
    • 首先,程式碼選定了我們正在處理的 DataFrame df_processed 中,名為 TotalCharges (總消費金額) 的這個欄位。
    • .median():
    • 接著,它計算了 TotalCharges 這個欄位中所有現存數值的中位數。中位數是指將所有數值由小到大排序後,位於最中間的那個數。使用中位數來填補空值,是一種比平均數更穩健的方法,因為它不容易受到極端值(非常高或非常低的消費金額)的影響。
    • .fillna(...):
    • 這個函式的名字是 “fill na” 的縮寫,也就是「填補空值 (NA/NaN)」。它的作用是找到 TotalCharges 欄位中所有空白或無效的儲存格。
    • inplace=True:
    • 這是一個非常重要的參數。inplace=True 的意思是:「請直接在原始的 df_processed 資料表上進行修改」。如果沒有這個參數(或設為 False),fillna 會回傳一個修改過後的新資料表,但原始的 df_processed 不會改變。
機器學習模型(如決策樹、迴歸模型等)的運算基礎是數學,它們只能理解數字,無法直接處理 'Yes','No','Male' 或 'Female' 這樣的文字。因此,在訓練模型之前,我們必須將這些文字標籤轉換成模型可以理解的數值格式。這個過程就是「標籤編碼」(Labe Encodidng)。

4. Scikit-learn – 建立決策樹分類模型

核心概念: 我們將使用 scikit-learn 來建立一個決策樹 (Decision Tree) 分類器,這是一種直觀且易於理解的分類演算法。

本案例應用重點:

  • 定義特徵 (X) 與目標 (y): 我們需要明確地將資料集分為兩部分:X 是用來預測的特徵(例如客戶合約類型、月費等),而 y 則是我們要預測的目標——Churn 欄位。
  • train_test_split(): 與迴歸模型相同,我們將資料切分為訓練集與測試集,以客觀地評估模型成效。
  • DecisionTreeClassifier(): 從 scikit-learn 中選擇並初始化一個決策樹分類模型。
  • .fit().predict(): 同樣使用 .fit() 進行訓練,並用 .predict() 來對測試集進行流失預測。

5. Scikit-learn – 分類模型的成效評估

核心概念: 分類模型的評估指標比迴歸模型更豐富,我們不只關心「答對率」,更關心「模型錯在哪裡」。

本案例應用重點:

  • confusion_matrix (混淆矩陣): 這是評估分類模型最重要的工具。它能清楚地顯示出模型在「預測流失,且實際也流失 (True Positive)」和「預測未流失,但實際已流失 (False Negative)」等四種情況下的表現,幫助我們了解模型的具體錯誤類型。
  • classification_report: 這個函式會一次性回報多個關鍵指標,包含準確率 (Precision)召回率 (Recall)F1-score,讓我們能更全面地評估模型的好壞。
  • accuracy_score: 整體預測的正確率,也就是「答對的題數 / 總題數」。

6. Matplotlib & Seaborn – 分類結果的視覺化

核心概念: 我們將評估指標與模型洞察,透過視覺化圖表呈現出來。

本案例應用重點:

  • seaborn.heatmap(): 我們使用熱力圖來視覺化「混淆矩陣」,透過顏色的深淺,讓模型的預測結果一目了然。
  • model.feature_importances_: 這是決策樹模型的一個重要屬性,它儲存了每一個特徵對於預測結果的「重要性分數」。
  • sns.barplot(x='重要性', y='特徵', data=feature_importance_df, palette='viridis') 這行程式碼是使用 seaborn 函式庫來繪製一個水平長條圖,目的是將「特徵重要性」這個分析結果視覺化。。

總結來說,這個案例的學習路徑是:

資料清理 -> One-Hot Encoding -> 切分資料集 -> 訓練分類模型 -> 評估分類模型 -> 視覺化”特徵重要性”