分類模型:預測客戶流失

在上一章中,我們學會了預測「數值」(房價)。但現實中還有一類非常重要的問題:預測「類別」

  • 這筆交易是詐騙嗎? → 是/否
  • 這位客戶下個月會流失嗎? → 會流失/不會流失
  • 這張 MRI 影像中的腫瘤是良性還是惡性? → 良性/惡性

這些都是分類問題 (Classification)

業務場景:電商客戶流失預測

想像你經營一個月費訂閱制的電商平台,每個月都有客戶取消訂閱。如果能提前知道「哪些客戶快要流失了」,你就可以在他們取消之前,自動發送優惠券或關懷訊息給他們,大幅降低流失率。

載入客戶資料集

我們將使用一個模擬的電商客戶資料集:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 建立模擬客戶資料
np.random.seed(42)
n_customers = 1000

df = pd.DataFrame({
    'tenure_months': np.random.randint(1, 72, n_customers),        # 使用月數
    'monthly_charges': np.random.uniform(30, 120, n_customers),    # 月費金額
    'total_charges': np.random.uniform(100, 8000, n_customers),    # 總消費金額
    'num_support_tickets': np.random.randint(0, 10, n_customers),  # 客服次數
    'has_contract': np.random.choice([0, 1], n_customers),         # 是否綁約
    'avg_order_value': np.random.uniform(10, 200, n_customers),    # 平均訂單金額
    'num_complaints': np.random.randint(0, 5, n_customers),        # 投訴次數
})

# 模擬流失標籤(越高的使用月數、綁約、越不容易流失)
churn_prob = (
    0.4
    - 0.005 * df['tenure_months']
    + 0.003 * df['num_support_tickets']
    + 0.05 * df['num_complaints']
    - 0.15 * df['has_contract']
    + np.random.normal(0, 0.1, n_customers)
)
df['churn'] = (churn_prob > 0.5).astype(int)

print(f"資料集大小: {df.shape}")
print(f"流失客戶比例: {df['churn'].mean()*100:.1f}%")

邏輯迴歸 (Logistic Regression)

別被名字騙了!雖然叫做「迴歸」,但邏輯迴歸其實是用來做分類的。

它的概念是:先計算一個數值(像是迴歸),然後透過一個 Sigmoid 函數 將這個數值轉換為 0 到 1 之間的「機率」。

$$P(y=1) = \frac{1}{1 + e^{-(w_1x_1 + w_2x_2 + ... + b)}}$$

  • 如果機率 $\geq 0.5$,預測為「流失」(1)
  • 如果機率 $< 0.5$,預測為「不流失」(0)

訓練邏輯迴歸模型

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# 分割資料
X = df.drop('churn', axis=1)
y = df['churn']
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 標準化特徵(邏輯迴歸需要)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 訓練模型
log_model = LogisticRegression()
log_model.fit(X_train_scaled, y_train)

# 預測
y_pred = log_model.predict(X_test_scaled)
y_pred_proba = log_model.predict_proba(X_test_scaled)[:, 1]

# 評估
accuracy = accuracy_score(y_test, y_pred)
print(f"準確率: {accuracy:.4f}")

分類模型的評估指標

分類模型的評估比迴歸複雜一些,因為我們不能只看「準確率」。

混淆矩陣 (Confusion Matrix)

混淆矩陣是分類評估的基礎,它告訴你模型在哪裡犯了錯:

cm = confusion_matrix(y_test, y_pred)
print("混淆矩陣:")
print(cm)

# 手動解讀
TN, FP, FN, TP = cm.ravel()
print(f"\n真負例 (TN): {TN}  — 正確預測不會流失")
print(f"假正例 (FP): {FP}  — 誤判為流失(白白送了優惠券)")
print(f"假負例 (FN): {FN}  — 漏判流失(最嚴重!)")
print(f"真正例 (TP): {TP}  — 正確預測會流失")

精準率 (Precision) vs 召回率 (Recall)

精準率 (Precision):預測「會流失」的客戶中,有多少真的流失了? $$Precision = \frac{TP}{TP + FP}$$

  • 精準率低 → 太多誤判,浪費優惠券成本

召回率 (Recall):真正流失的客戶中,我們成功預測了多少? $$Recall = \frac{TP}{TP + FN}$$

  • 召回率低 → 太多漏判,沒能挽留客戶

F1 分數:精準率與召回率的調和平均數 $$F1 = 2 \times \frac{Precision \times Recall}{Precision + Recall}$$

print("\n分類報告:")
print(classification_report(y_test, y_pred, target_names=['未流失', '流失']))

重點:不要只看準確率!

假設你的資料中只有 5% 的客戶會流失。如果模型「全部預測為不流失」,準確率仍然是 95%!但這個模型完全沒有用。

當資料不平衡時(流失客戶很少),請以召回率與精準率為主要評估指標

決策樹 (Decision Tree)

決策樹是另一個非常直觀的分類演算法。它就像一個「如果...就...」的問答遊戲:

是否綁約?
├── 沒有綁約:是否經常投訴?
│   ├── 是:預測流失 ❌
│   └── 否:使用月數 > 12?
│       ├── 是:預測不流失 ✅
│       └── 否:預測流失 ❌
└── 有綁約:預測不流失 ✅
from sklearn.tree import DecisionTreeClassifier

# 決策樹不需要標準化
dt_model = DecisionTreeClassifier(max_depth=5, random_state=42)
dt_model.fit(X_train, y_train)

# 預測與評估
y_pred_dt = dt_model.predict(X_test)
print(f"決策樹準確率: {accuracy_score(y_test, y_pred_dt):.4f}")
print("\n決策樹分類報告:")
print(classification_report(y_test, y_pred_dt, target_names=['未流失', '流失']))

max_depth=5 限制樹的深度,避免過度擬合 (Overfitting)。

特徵重要性分析

決策樹有一個強大的功能:它可以告訴你「哪些特徵對預測最有幫助」:

feature_importance = pd.DataFrame({
    '特徵': X.columns,
    '重要性': dt_model.feature_importances_
}).sort_values('重要性', ascending=False)

print("特徵重要性:")
print(feature_importance)

# 畫出特徵重要性
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
plt.barh(feature_importance['特徵'], feature_importance['重要性'])
plt.xlabel('重要性')
plt.title('特徵重要性分析')
plt.gca().invert_yaxis()
plt.show()

使用 Vibe Coding 做分類

🔥 【分類模型詠唱範例】 「我有一個 customer_data.csv,包含使用月數、月費、客服次數、是否綁約、投訴次數等欄位。 請幫我: 1. 使用 LogisticRegression 與 DecisionTreeClassifier 分別訓練流失預測模型。 2. 比較兩者的準確率、精準率、召回率與 F1 分數。 3. 畫出混淆矩陣。 4. 輸出決策樹的特徵重要性排序。 5. 判斷哪個模型更適合這個任務,並說明原因。」

本日總結

在本章中,你學到了:

  1. 分類問題:預測類別而非數值
  2. 邏輯迴歸:透過 Sigmoid 函數計算分類機率
  3. 混淆矩陣:了解模型在哪裡犯錯
  4. 精準率 vs 召回率:不同場景下該關注哪個指標
  5. 決策樹:直觀的 if-else 分類規則
  6. 特徵重要性:找出哪些因素最影響預測結果

下一章,我們將學習如何避免模型過度擬合,並使用更強大的隨機森林演算法!

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!