題目是用一個人過去 14 天的行為,預測他 3 天後的情緒與壓力。序列資料、時間依賴性,直覺的答案就是 LSTM。我實際比較了五個候選方案,最後上線的是 Random Forest。這個決定值得寫下來,因為淘汰掉那個「正確答案」的理由,跟準確率完全無關。
先看限制,不要先看準確率
模型選型常被當成準確率問題,但它很少真的是。這個題目有四個特性,在準確率進入討論之前就先淘汰掉大部分選項。
每位使用者只有幾百筆資料,不是幾萬筆。 日記最勤勞也是一天一篇,一個持續寫了一年的使用者大約累積 300 筆可用資料。神經序列模型的胃口遠大於此,在這麼薄的資料上,它們會記住而不是學會 —— 你得到的是一個背下了某個人某個春天的模型。
預測必須在儲存日記的同時回來。 預測結果跟寫日記是同一個互動流程,這代表延遲預算是一般 CPU 上的數十毫秒等級。請求路徑上沒有 GPU,也不應該有。
使用者會問為什麼。 當系統告訴你「你三天後的壓力可能上升」,在心理健康產品裡,「因為模型這樣說」不是可以接受的答案。系統必須有辦法指向睡眠時數、步數,或就寢時間的波動。
維護的人只有一個。 一個需要定期重新調參才能維持水準的模型,等於一個會安靜腐爛的模型,因為沒有人的職責是做這件事。
五個候選方案
| 所需資料量 | 可解釋性 | 推論成本 | 過擬合風險 | 準確率 | |
|---|---|---|---|---|---|
| 線性迴歸 | 極少 | 高 | 可忽略 | 欠擬合 | 受限於線性假設 |
| 單一決策樹 | 極少 | 高 | 可忽略 | 高 | 不穩定 |
| Random Forest | 幾百筆 | 特徵重要度 | CPU 50ms 內 | 低 | 高且穩定 |
| XGBoost | 中等 | 特徵重要度 | 低 | 中 | 調好之後最佳 |
| LSTM | 數萬筆 | 低 | 中(需深度學習執行環境) | 小資料上偏高 | 資料夠多時高 |
線性迴歸和單一決策樹通過了限制,卻通不過題目本身:前者假設情緒與睡眠之間是線性關係,而它們並不是;後者以不穩定著稱,換一個略微不同的時間窗口重新訓練,最上層的分裂就變了。
LSTM 一次違反三項限制。它要的資料量遠超過每位使用者實際擁有的,它無法解釋自己,而且它會把一整套深度學習執行環境搬進請求路徑。最後這點值得說準確一點:這種規模的 LSTM 前向傳播在 CPU 上其實只要幾毫秒,推論本身不需要 GPU;真正的成本是訓練要動用 GPU,以及一個人要長期養著那套相依。在資料量大十倍的情況下它很可能會贏,但那個資料集在這裡並不存在。
XGBoost 是比較有意思的一個,因為如果只比較準確度,它大概會是被選中的那個。調校得當時,它在表格資料上通常會小幅勝過 Random Forest。但「調校得當」就是整句話的重點:它對超參數(訓練前要人工設定的那些旋鈕)確實敏感,而它的優勢要有人持續維護那組調校才顯現得出來。Random Forest 的招牌特性正好相反 —— 它在預設值下就大致正確,bagging(讓每棵樹只看資料的一部分再投票)免費提供了對過擬合的抵抗力,而預設參數已經夠接近最佳,那點差距不值得換來額外的維護負擔。
Random Forest 實際換到了什麼
我用 53 個特徵訓練了 100 棵樹。特徵包含 12 項行為與生理指標:平均情緒分數、平均與尖峰壓力、日記篇數、睡眠時數與品質、深睡比例、步數、活動分鐘數、HRV(心率變異性,數值越低通常代表身體越緊繃)、靜息心率、就寢時間變異,每一項各自展開成 1、3、7、14 天四個時間窗口——也就是「過去 N 天的平均」這種回看型(lag)特徵,共 48 個——再加上星期幾、連續記錄天數等 5 個日曆特徵。
迴歸目標取所有樹的平均,高壓日的分類器則平均各棵樹給出的機率,再取機率較高的那一類——這是 scikit-learn 的作法,跟 Breiman 原始論文的多數投票不同。
5-fold 交叉驗證結果(把資料切成五份,輪流拿四份訓練、一份驗證,取五次的平均):
- 情緒分數 MAE 0.22——平均絕對誤差,也就是預測值與實際值平均差多少(尺度為 −1 到 +1)
- 壓力指數 MAE 1.04(尺度為 0 到 10,22,796 列)
- 高壓日 AUC 0.948(把高壓日排在一般日前面的能力,1.0 為完美、0.5 等同亂猜)、recall 88%(真正的高壓日裡有多少被抓到)(31,720 列)
recall 是刻意拉高的。兩種錯誤的代價並不對稱:誤報的成本是一次多餘的提醒,漏報的成本是一段沒有人接住的低潮。在這個領域裡,這個不對稱大到足以單獨決定門檻要設在哪裡。
我做錯的地方
驗證用的是隨機 5-fold,但它應該是時間切分。
53 個特徵裡有 48 個是 lag 變數。隨機切分會把同一段時間的資料同時放進訓練集和驗證集 —— 第 40 天的特徵和第 42 天高度重疊,如果一個在訓練、另一個在驗證,模型等於已經看過答案了。上面那些數字很可能因此偏樂觀。
對預測問題而言,誠實的評估方式是時間切分:用較早的期間訓練,預測較晚的期間,絕不讓未來往回洩漏。如果要重做,我會先修這一項,而且我預期數字會掉下來。
我選擇保留實際量測到的數字,而不是安靜地把它們改掉,因為一個標明了已知缺陷的結果,比一個藏著缺陷的結果有用。
可以帶走的部分
讓這個決定變簡單的,是拒絕從準確率開始想。準確率是最後的決勝點,不是第一道篩選。資料量、延遲、可解釋性與維護成本,在任何模型被訓練之前,就已經把五個候選收斂到一個 —— 而排行榜會選中的那一個,是被一項排行榜根本不量測的限制淘汰的。
HeartBox 完整案例研究裡有其餘的部分,包含與這個預測並行的檢索式回饋設計。