跳到主要內容

DS 201 · 模組 1

建立預測問題與第一個模型

從一份服務需求資料集出發,練習定義預測問題、建立 baseline、正確切分資料,並訓練第一個可以被驗證的回歸模型。

開始第一節
已完成 0 / 5
同步我的進度加入梯次後,進度可跨裝置保存,講師也能看到

資訊

加入後,你已完成的模組編號會連同「學員代碼」傳送給講師,講師可以看到你的進度。請使用講師提供的代碼,不要輸入姓名、公司機密或其他個資。進度資料與該梯次的其他資料一起保存。

學習目標

  • 定義預測單位、target、時間範圍、決策與預測當下可取得資訊
  • ML 前先建立 naive、majority、mean 或規則型 baseline
  • 分離訓練、調參、最終評估;避免 future/target leakage
  • 建立簡單回歸模型,以 domain units 解讀 MAE/RMSE
  • 建立 baseline 與模型,用固定切分比較 held-out performance

預測問題:Target、Features、Prediction Time

35 分鐘

預測問題:Target、Features、Prediction Time

學習目標:定義預測單位、target、時間範圍、決策與預測當下可取得資訊。

你的主管說:「我們來預測下週每個服務據點的案件量吧。」這句話聽起來像一個明確的任務,但實際上還缺很多定義:一筆「預測」到底對應到哪一個單位(一個據點、一天,還是一個時段)?target 是案件數量本身,還是超過門檻的二元判斷?「下週」的起點是什麼時候?更重要的是,在做這個預測的當下,哪些資訊你真的已經知道,哪些其實是事後才會出現的?

如果跳過這一步,直接把資料丟進模型,最常見的後果是:團隊用了「案件關閉後才產生」的欄位當 feature,模型在歷史資料上表現很好,但上線後卻完全對不上,因為正式運作時那個欄位在預測當下根本還不存在。先把預測單位、target、prediction time 寫清楚,才能避免這種「事後才發現」的代價。

模糊的任務描述

「預測案件量」: 沒有說清楚預測單位、target 定義、時間範圍,也沒有檢查預測當下真的能取得哪些欄位。

明確定義的預測問題

預測單位
一列 = 一個服務據點在某個 split_time 當下,對未來一段時間的一筆預測案例(case_id)。
Target
target_numeric 是未來時段的案件量(回歸);target_binary 是是否超過容量門檻(分類)。
Prediction time
每筆 case_id 都有一個 split_time:只有在這個時間點之前就存在的 features_* 才能用來預測。
本課程的資料集(先確認 schema,再談模型)
import pandas as pd

# clean:一份服務需求預測資料集,一列代表一筆預測案例
df = pd.read_csv("DS201_Service_Demand_Clean.csv", parse_dates=["created_at", "split_time"])
df.shape
df.dtypes
df[["case_id", "split_time", "target_numeric", "target_binary"]].head()

# 先問:哪些 features_* 欄位是在 split_time 之前就已知的?
[c for c in df.columns if c.startswith("features_")]
定義預測問題時必須回答的四個問題
問題這個資料集的答案
預測單位是什麼?一個 case_id:某個服務據點在某個 split_time 的一筆需求預測
target 是什麼?target_numeric(未來案件量)或 target_binary(是否超過容量門檻)
決策是什麼?要不要提前調度人力/資源給這個據點
預測當下能取得什麼?只有 split_time 之前產生的 features_*,target 本身在預測當下永遠不可得
練習:這個欄位能不能用?(模擬案例)

假設 features_queue_length_at_split 記錄的是 split_time 當下的排隊人數,而 features_total_handling_time 記錄的是案件結案後加總的處理時數。前者在預測當下已經存在,可以當作 feature;後者要等案件結束才算得出來,屬於未來資訊,即使它和 target 的相關性很高,也不能使用。

  • 把「預測」直接等同於「分析」,沒有先定義一個明確的 prediction time
  • 只看欄位名稱判斷能不能用,而不是實際查核它的產生時間
  • 把 target 本身的歷史值直接當作 feature,卻沒有檢查它是否會在預測當下洩漏答案
  • 不同人對「一筆預測」的定義不一致,導致後續評估無法互相比較

注意

資料安全提醒:本課程所有練習都使用課程提供的合成資料。除非獲得授權,切勿將機密的機構資料、客戶個人資料或未經授權的敏感資訊貼入 AI 工具或練習環境。

資訊

Human, AI, Human:人負責定義預測單位、target 與決策,AI 可以協助列出候選 features 或畫出時間軸;人負責確認每個 feature 在預測當下真的可得,再把問題交給模型。
自我檢測

同事提議用「案件處理完成後才統計出的平均處理時間」當作預測「本週案件量」的一個 feature。這樣做最大的問題是什麼?

同事提議用「案件處理完成後才統計出的平均處理時間」當作預測「本週案件量」的一個 feature。這樣做最大的問題是什麼?

重點: 能完成步驟不代表結果可信;本節的能力必須能被驗證、重做並清楚說明。

Baseline

35 分鐘

Baseline:模型必須打敗什麼?

學習目標:ML 前先建立 naive、majority、mean 或規則型 baseline。

同事興奮地說:「我們的模型準確率有 82%!」但如果直接猜「每個據點的案件量都等於整體平均值」也能達到 78% 的表現,那這個模型真正帶來的增益只有 4 個百分點,而不是聽起來的 82%。沒有 baseline,任何一個分數都無法判斷模型是否值得投入使用。

選擇哪一種 baseline,取決於資料本身的特性:有明顯時間規律的資料適合用 naive baseline;類別或數值分布不均的資料,majority 或 mean baseline 往往已經很難被打敗。先花十分鐘算出 baseline,遠比事後才發現模型其實沒有增益划算。

沒有 baseline

  • 只看模型分數本身,覺得「數字夠高」就是好模型
  • 無法判斷這個分數是模型的功勞,還是資料本身就很容易預測
  • 換一批資料或換一個門檻,結論可能完全不同

先建立 baseline

  • naive/majority/mean/規則型 baseline 代表「不用機器學習也能做到的表現」
  • 模型必須明顯打敗 baseline,才值得投入訓練與維護成本
  • baseline 與模型用同一組驗證資料比較,才公平
為回歸與分類各建立一個簡單 baseline
import numpy as np

# 回歸 baseline:用訓練資料的平均案件量,當作每一筆預測
mean_baseline = df["target_numeric"].mean()
baseline_mae = (df["target_numeric"] - mean_baseline).abs().mean()

# 分類 baseline:majority class(預測「永遠不超過門檻」)
majority_class = df["target_binary"].mode()[0]
baseline_accuracy = (df["target_binary"] == majority_class).mean()

print(round(baseline_mae, 2), round(baseline_accuracy, 3))
常見的 baseline 類型
Baseline 類型適用情境範例
Naive(前一期)有時間順序的資料預測下週案件量 = 上週案件量
Majority / Mean分類 / 回歸的最簡單起點永遠預測最常見的類別,或永遠預測平均值
規則型(rule-based)已知的業務經驗法則「週一案件量通常是平日均值的 1.3 倍」
案例:baseline 看起來很弱,卻很難打敗(模擬)

某服務據點的案件量幾乎每週都落在 18 到 22 件之間,波動很小。mean baseline 的 MAE 只有 1.8,看起來「太簡單了」,但實際訓練出的回歸模型 MAE 是 1.6,只贏了 0.2 件。這代表這個情境本身就很容易預測,模型帶來的增益非常有限,是否值得投入維護成本需要另外評估。

  • 只報告模型分數,沒有同時報告對應的 baseline 分數
  • 用訓練集算出的 baseline 統計量,卻拿去跟 test set 上的模型分數比較
  • 分類問題只看 accuracy,沒有先確認多數類別占比
  • 每次資料更新後忘記重新計算 baseline,導致比較基準過時

注意

只報告模型分數、不報告 baseline,是最容易誇大模型價值的做法之一:資料本身容易預測時,任何模型都會「看起來準」,但那不是模型的功勞。
自我檢測

一個分類模型的準確率是 91%,但資料中 90% 的案例都屬於「未超過容量門檻」這個多數類別。對這個 91% 最合理的解讀是什麼?

一個分類模型的準確率是 91%,但資料中 90% 的案例都屬於「未超過容量門檻」這個多數類別。對這個 91% 最合理的解讀是什麼?

重點: 能完成步驟不代表結果可信;本節的能力必須能被驗證、重做並清楚說明。

Train/Validation/Test 與 Leakage

45 分鐘

Train / Validation / Test 與 Leakage

學習目標:分離訓練、調參、最終評估;避免 future/target leakage。

同事在同一份資料上反覆調整模型參數,每次都看 test set 上的分數,挑分數最高的那一組參數。這樣做的問題是:test set 已經被用來做決策了,它不再是「未見資料」,最終回報的分數會系統性地偏高,實際上線後的表現通常會令人失望。

Leakage 不一定是程式寫錯,很多時候是資料本身的欄位定義有問題:例如某個欄位的計算方式用到了整個資料集的統計量(像是全域平均),而這個統計量本身已經包含了 test set 的資訊。在切分資料之後才計算任何統計量,是避免這種隱性 leakage 的基本原則。

三個資料切分各自的角色
切分用途規則
Train(訓練集)讓模型學習參數可以重複使用、反覆訓練
Validation(驗證集)比較不同模型或調整超參數可以多次查看,但不能是最終回報的分數
Test(測試集)近似最終、未見資料的表現只能查看一次,決定要不要調整後就不再回頭修改
依時間切分,避免用未來資料預測過去
df_sorted = df.sort_values("split_time")
n = len(df_sorted)
train = df_sorted.iloc[: int(n * 0.6)]
valid = df_sorted.iloc[int(n * 0.6): int(n * 0.8)]
test = df_sorted.iloc[int(n * 0.8):]

# 檢查:test 的最早時間,是否晚於 train 的最晚時間
train["split_time"].max() < test["split_time"].min()
  1. 依時間排序後切分
    服務需求資料具有時間順序,train 必須全部早於 valid,valid 必須全部早於 test,不能隨機打亂。
  2. 檢查 leakage 來源
    確認沒有欄位是「事後才知道」的(例如案件關閉後才產生的欄位),也沒有同一個服務據點的資料同時出現在 train 與 test。
  3. 只用 test 做一次最終評估
    test set 的分數只在所有調參都完成後查看一次;若之後又回頭調整模型,就必須視為新的一輪流程。
案例:隱性 leakage(模擬)

某同事在切分資料前,先對整個資料集的 features_queue_length 做標準化(減去整體平均、除以整體標準差)。因為這個「整體平均」裡已經混入了 test set 的數值,train 階段其實間接看到了 test 的資訊。正確做法是先切分,只用 train 的平均與標準差,再套用到 validation 與 test。

  • 任何統計量(平均、標準差、分組統計)都只能用 train 計算,再套用到 validation / test
  • 確認沒有同一個服務據點或同一個 case 在不同切分中重複出現
  • 確認欄位的產生時間在 split_time 之前,而不是只看欄位名稱像不像 feature
  • test set 的分數只查看一次,查看後若要調整模型就重新整個流程

注意

Leakage 最常見的兩種來源:(1) target leakage: 用了案件結果發生後才會出現的欄位;(2) 切分方式錯誤: 用隨機切分處理有時間順序的資料,讓未來資訊悄悄流入訓練過程。
自我檢測

一份有時間順序的服務需求資料,若改用「隨機切分」而不是「依時間切分」train/test,最可能造成什麼問題?

一份有時間順序的服務需求資料,若改用「隨機切分」而不是「依時間切分」train/test,最可能造成什麼問題?

重點: 能完成步驟不代表結果可信;本節的能力必須能被驗證、重做並清楚說明。

Regression 與評估

40 分鐘

Regression 與回歸評估:MAE、RMSE

學習目標:建立簡單回歸模型,以 domain units 解讀 MAE/RMSE。

模型訓練完成後,同事只回報一個數字:「RMSE 是 12.4」。這個數字本身沒有意義,除非你知道它的單位是什麼、和 target 的量級相比是大是小,以及它與 MAE 之間的差距透露了什麼。回歸評估的重點不是算出一個指標,而是把它翻譯回「案件量誤差」這種業務語言。

把 MAE 或 RMSE 翻譯成業務語言時,一定要連同 target 的量級一起報告。「MAE 是 3.2」在平均案件量是 20 的情境下代表誤差約 16%;但在平均案件量是 200 的情境下,同樣的 3.2 只代表 1.6% 的誤差。沒有對照量級,單獨一個誤差數字幾乎無法判斷模型好壞。

MAE 與 RMSE 的差異
指標計算方式特性
MAE(平均絕對誤差)每筆預測誤差取絕對值後平均以 target 原單位表示,容易向業務單位解釋;對每筆誤差一視同仁
RMSE(均方根誤差)每筆誤差平方後取平均,再開根號對較大的誤差更敏感;少數幾筆誤差很大的預測會被放大
訓練一個簡單回歸模型並與 baseline 比較
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error

feature_cols = [c for c in df.columns if c.startswith("features_")]
model = LinearRegression().fit(train[feature_cols], train["target_numeric"])
pred = model.predict(valid[feature_cols])

mae = mean_absolute_error(valid["target_numeric"], pred)
rmse = mean_squared_error(valid["target_numeric"], pred, squared=False)
print(round(mae, 2), round(rmse, 2))
# 與 Lesson 2 算出的 baseline_mae 比較,才能判斷模型是否值得使用
案例:同一個 MAE,不同的意義(模擬)

據點 A 的平均案件量是 15 件,模型 MAE 是 3;據點 B 的平均案件量是 150 件,模型 MAE 同樣是 3。對據點 A,這個誤差相當於平均值的 20%,可能已經大到影響人力調度;對據點 B,同樣的誤差只占平均值的 2%,影響小得多。報告誤差時應該一併說明它占 target 平均值的比例。

  • 同時報告 MAE 與 RMSE,並說明兩者的差距透露了什麼
  • 把誤差換算成占 target 平均值或中位數的百分比,而不是只給原始數字
  • 標明誤差是在哪一個切分(validation 或 test)上算出來的
  • 註明這個誤差與 baseline 相比的差距,而不是單獨呈現

注意

如果 RMSE 明顯大於 MAE,代表存在少數幾筆誤差特別大的預測;只看 RMSE 會讓你以為整體誤差都很大,只看 MAE 又可能忽略了這幾筆嚴重偏差的案例,兩者應該一起報告。
自我檢測

兩個模型在同一組資料上的 MAE 都是 10,但模型 A 的 RMSE 是 11,模型 B 的 RMSE 是 25。最合理的解讀是什麼?

兩個模型在同一組資料上的 MAE 都是 10,但模型 A 的 RMSE 是 11,模型 B 的 RMSE 是 25。最合理的解讀是什麼?

重點: 能完成步驟不代表結果可信;本節的能力必須能被驗證、重做並清楚說明。

Guided Lab

55 分鐘

Guided Lab:第一個可驗證預測模型

學習目標:在教師引導下,建立 baseline 與模型,用固定切分比較 held-out performance。

資訊

實作問題:如果你只能用一頁報告向利害關係人交代「這個模型值不值得用」,你會怎麼用固定的資料切分、baseline 與 MAE/RMSE,證明模型確實比不用機器學習更好?
  1. 確認預測問題
    寫下這份 Guided Lab 的預測單位、target_numeric、決策,以及 split_time 之前可用的 features_*。
  2. 依時間切分資料
    依 split_time 排序後切出 train/validation/test,並檢查三者的時間範圍沒有重疊。
  3. 建立 baseline
    用訓練集平均值當作 mean baseline,計算它在 validation 上的 MAE。
  4. 訓練並比較模型
    訓練一個簡單回歸模型,計算它在 validation 上的 MAE 與 RMSE,並與 baseline 比較。
  5. 最終評估
    選定模型後,只在 test set 上查看一次最終分數,不再回頭調整。
  6. 寫下仍需人工判斷的項目
    列出這個結果還無法回答、需要進一步確認或人工判斷的問題(例如季節性、極端事件)。
Guided Lab 應包含的最少內容(請填入你自己的輸出結果)
項目要回報的內容
預測問題預測單位、target、決策、prediction time 可用欄位
切分方式train/validation/test 的時間範圍與筆數
Baselinemean baseline 的 MAE
模型表現模型在 validation 上的 MAE 與 RMSE,與 baseline 的差距
最終結果test set 上只查看一次的最終分數
  • 先確認所有輸出都能重新執行一次,數字不是手動修改過的
  • 明確寫出哪些欄位被排除是因為 leakage,而不是因為模型表現比較差才移除
  • 任何「模型打敗 baseline」的結論,都附上實際的差距數字,而不是只說「有改善」

注意

「程式碼有跑出結果」不等於「這個模型可信」。每一個數字都必須能被重新執行、能被說明它的計算方式,而且 test set 只能查看一次。

完成

如果 AI 協助撰寫訓練或評估程式碼,請自己逐項檢查:切分方式是否依時間排序、features 是否都在 prediction time 之前可得、baseline 是否確實計算,以及最終分數是否只查看了一次。AI 可以加快撰寫速度;驗證與結論仍是人的責任。
自我檢測

你完成了 Guided Lab,模型在 validation 上的 MAE 比 baseline 低,但你發現其中一個 features_* 欄位其實是在案件結束後才產生的。這時最適當的做法是什麼?

你完成了 Guided Lab,模型在 validation 上的 MAE 比 baseline 低,但你發現其中一個 features_* 欄位其實是在案件結束後才產生的。這時最適當的做法是什麼?

重點: 能完成步驟不代表結果可信;本節的能力必須能被驗證、重做並清楚說明。

接下來做什麼?