ARK · 金融機器學習CHAPTER 02 / 12

CHAPTER 02 / 12 · PART 1 · 橫斷面資料的監督式學習

機率建模與貝葉斯思維

Probabilistic Modeling

把參數不確定性納入模型:從先驗到後驗的更新機制,與模型選擇的貝葉斯答案。

§01學習重點

§02課程內容

一、機率是什麼:一個看似哲學、其實很實務的問題

第 1 章談的是兩種建模文化;這一章往更根本的一層挖:機率這個詞本身,就有兩種讀法。

頻率學派(frequentist)的讀法:機率是長期相對頻率。說一枚硬幣正面機率二分之一,意思是擲一萬次大約五千次正面。在這個世界觀裡,模型參數(真實勝率、真實平均報酬)是一個固定但未知的常數——它沒有機率可言,有機率的是資料:換一批樣本,估計值就會抖動。所以頻率學派的不確定性語言全部繞著「重複抽樣」打轉:標準誤是「重抽很多次,估計值的標準差」;95% 信賴區間的正確讀法是「用同樣方法造一百個區間,約九十五個會罩住真值」——而不是「真值有 95% 機率落在這個區間裡」。後面那句話在頻率學派的語法裡是病句,因為真值不是隨機變數。

貝葉斯學派(Bayesian)的讀法:機率是信念的強度。參數本身可以有分布——不是說真值會變來變去,而是說你對它的認識有不確定性,而這個不確定性可以用機率分布來刻度。看資料之前你的信念叫先驗,看完資料之後叫後驗,兩者之間由貝葉斯定理接駁。在這個世界觀裡,「這檔策略真實勝率大於五成的機率是 87.9%」是一句完全合法、而且可以直接拿去做決策的話。

比喻: 品管工程師與氣象主播用的是兩種機率。品管工程師說「這條產線的不良率 0.3%」,背後是同一條產線可以日復一日重複抽驗——長期頻率真實存在,這是頻率學派的主場。氣象主播說「明天降雨機率 70%」,但明天只會發生一次,不存在「重複一萬個明天」的母體——這句話的真正意思是信念的校準:在主播說 70% 的所有日子裡,約七成真的下雨。金融裡多數要緊的問題——明年會不會衰退、這檔剛上線的策略有沒有優勢——都長得像明天的天氣,不像產線上的螺絲。

這正是分歧在金融裡刺痛的地方。頻率學派的保證多半是漸近的:樣本夠大、抽樣可以想像無限重複,性質才成立。但金融資料常常又短又不平穩——一個新策略只有幾十筆實盤交易,一段體制(低利率、某種監管環境)可能十年就換一次,「長期頻率」的長期,你可能根本等不到。貝葉斯方法在這裡有兩個實際優勢:小樣本下可以靠先驗知識補血,而且輸出的是完整分布——參數不確定性被原封不動地保留下來,後面第七節會看到,這對部位規模是有真金白銀含義的。代價則是:先驗是主觀的,選得差會把推論帶偏;而且一旦離開共軛的舒適圈,計算成本高於頻率方法。兩派不是宗教戰爭,是工具箱裡兩把用途不同的扳手。

二、估計量的品質:偏差、變異數,與一個反直覺的結論

第 1 章用偏差–方差取捨診斷預測函數;同一套語言換個對象,可以用來評估估計量(estimator)——任何「把資料變成一個數字」的公式。關鍵的視角切換:估計量吃進來的資料是隨機的,所以估計量本身也是隨機變數,有自己的期望值與變異數。

拿最貼身的例子:你想估計一檔當沖策略的真實勝率 \(\theta\)。最自然的估計量是勝場比例 \(\hat{\theta} = k/n\)(n 筆交易、k 勝)。它有兩個品質指標。偏差:\(\mathbb{E}[\hat{\theta}] - \theta\),系統性偏移的量;勝場比例的偏差是零,稱為不偏。變異數:\(\mathrm{Var}[\hat{\theta}] = \theta(1-\theta)/n\),換一批同樣大小的樣本,估計值晃動的幅度。兩者合成一個總指標——均方誤差:

$$ \mathrm{MSE}(\hat{\theta}) \;=\; \mathbb{E}\big[(\hat{\theta} - \theta)^2\big] \;=\; \mathrm{Bias}(\hat{\theta})^2 + \mathrm{Var}(\hat{\theta}) $$

逐項拆解:左邊是「估計值離真值的平均平方距離」——越小越準;右邊說這個距離恰好拆成兩塊,偏差平方(瞄準點偏了多少)加變異數(每一發子彈散得多開)。這是第 1 章偏差–方差分解的估計量版本,差別只在少了不可約誤差項——因為這裡的目標是固定的參數,不是帶雜訊的觀測。

反直覺的地方來了:不偏不等於最準。考慮一個「摻水」的估計量——把勝場數加 4、總場數加 8 再相除,\(\tilde{\theta} = (k+4)/(n+8)\)。它把估計值往 0.5 方向拉,明顯有偏;但拉近中心也讓它更穩。用蒙地卡羅實測(真實勝率 0.55、每次 40 筆交易、重複二十萬次):

PYTHON
import numpy as np

rng = np.random.default_rng(21)
theta_true, n, trials = 0.55, 40, 200_000
wins = rng.binomial(n, theta_true, size=trials)   # 二十萬個平行世界的勝場數

est_ml = wins / n                 # 勝場比例(最大概似估計量,不偏)
est_sh = (wins + 4) / (n + 8)     # 收縮估計量(往 0.5 拉,有偏)

for name, est in (("勝場比例", est_ml), ("收縮估計", est_sh)):
    bias = est.mean() - theta_true
    var  = est.var()
    mse  = np.mean((est - theta_true) ** 2)
    print(f"{name}|偏差 {bias:+.5f}|變異數 {var:.5f}|MSE {mse:.5f}")
# 輸出:
# 勝場比例|偏差 -0.00014|變異數 0.00620|MSE 0.00620
# 收縮估計|偏差 -0.00845|變異數 0.00431|MSE 0.00438

收縮估計量付出了 0.008 的偏差,換到變異數從 0.00620 降到 0.00431,總帳(MSE)從 0.00620 降到 0.00438——有偏的估計量整體更準。這不是巧合,是偏差–方差取捨在估計量世界的重演:40 筆交易撐不起一個完全不受約束的估計,往一個合理的中心收縮,用一點系統性偏移買下大量穩定性,小樣本下是划算的交易。

還有一件事先按下不表:\((k+4)/(n+8)\) 這個看起來像工程小抄的公式,其實一個字都不多不少,正是某個貝葉斯後驗分布的平均值。收縮的幅度、收縮的中心,都可以從先驗推出來——下一節揭曉。

三、貝葉斯推論流程:先驗、似然、後驗

貝葉斯推論的全部機器,就是一條定理:

$$ p(\theta \mid \mathbf{y}) \;=\; \frac{p(\mathbf{y} \mid \theta)\, p(\theta)}{p(\mathbf{y})} \;\propto\; p(\mathbf{y} \mid \theta)\, p(\theta) $$

逐項拆解:\(p(\theta)\) 是先驗——看資料前你對參數的信念分布;\(p(\mathbf{y} \mid \theta)\) 是似然——假如參數是 \(\theta\),觀測到手上這批資料 \(\mathbf{y}\) 的機率,資料對參數的全部發言權都封裝在這裡;\(p(\mathbf{y})\) 是邊際似然(也叫證據),對 \(\theta\) 積分後的常數,推論單一模型的參數時可以無視、第五節比較模型時它會變成主角;左邊 \(p(\theta \mid \mathbf{y})\) 是後驗——看完資料後更新過的信念。整條式子唸成白話:後驗正比於似然乘先驗——新信念是舊信念被資料修正後的樣子。

拿策略勝率當完整例子。每筆交易勝負是一次伯努利試驗,n 筆交易、k 勝的似然是 \(\theta^{k}(1-\theta)^{n-k}\)(乘上一個與 \(\theta\) 無關的組合數)。先驗選 Beta 分布:

$$ p(\theta) \;=\; \frac{1}{B(\alpha,\beta)}\,\theta^{\alpha-1}(1-\theta)^{\beta-1} \quad\Longrightarrow\quad \theta \mid \text{資料} \;\sim\; \mathrm{Beta}(\alpha + k,\; \beta + n - k) $$

逐項拆解:\(B(\alpha,\beta)\) 是讓密度積分為一的正規化常數;\(\alpha, \beta\) 是先驗的兩個形狀參數,最好的讀法是虛擬戰績——開賽前先記上 \(\alpha\) 場虛擬勝場、\(\beta\) 場虛擬敗場(於是後驗平均恰好是「虛擬加真實戰績」的合計勝率);右邊的箭頭是整個共軛機制:Beta 先驗乘上伯努利似然,指數直接相加,後驗還是 Beta,參數更新規則簡單到像記帳——勝場加進 \(\alpha\),敗場加進 \(\beta\)。先驗與後驗同屬一個分布家族,稱為共軛;共軛讓貝葉斯更新從一個積分問題退化成一次加法。

現在可以兌現上一節的伏筆了。Beta 後驗的平均值是 \((\alpha+k)/(\alpha+\beta+n)\);取 \(\alpha=\beta=4\),就是 \((k+4)/(n+8)\)——那個「摻水」估計量。所謂收縮,就是先驗的八場虛擬戰績(四勝四敗,戰意堅定地相信勝率五成上下)跟真實戰績混在一起算平均。先驗越強(\(\alpha+\beta\) 越大),拉力越大;資料越多(n 越大),真實戰績淹沒虛擬戰績,估計值向勝場比例靠攏——貝葉斯與頻率學派在大樣本下和解

具體跑一遍。一檔台股當沖策略上線,40 筆訊號、24 勝 16 敗。先驗用 Beta(4,4)。批次更新:後驗 \(\mathrm{Beta}(4+24,\,4+16)=\mathrm{Beta}(28,20)\)。但貝葉斯還送一個免費功能——逐筆更新:每收一筆交易就把當下的後驗當成下一筆的先驗,跑完 40 筆,結果跟一次算完完全一樣:

PYTHON
import numpy as np
from math import lgamma

rng = np.random.default_rng(2)
record = rng.permutation(np.array([1]*24 + [0]*16))   # 40 筆交易的勝負序列

# 逐筆更新:勝場記入 alpha,敗場記入 beta
a, b = 4.0, 4.0
for i, x in enumerate(record, 1):
    a += x; b += 1 - x
    if i in (10, 25, 40):
        m  = a / (a + b)
        sd = (a * b / ((a + b) ** 2 * (a + b + 1))) ** 0.5
        print(f"{i:>2d} 筆後:Beta({a:.0f},{b:.0f})|後驗平均 {m:.4f}|後驗標準差 {sd:.4f}")
print("批次一次算:Beta(28,20),兩者相同 ->", (a, b) == (28.0, 20.0))
# 輸出:
# 10 筆後:Beta(10,8)|後驗平均 0.5556|後驗標準差 0.1140
# 25 筆後:Beta(18,15)|後驗平均 0.5455|後驗標準差 0.0854
# 40 筆後:Beta(28,20)|後驗平均 0.5833|後驗標準差 0.0704
# 批次一次算:Beta(28,20),兩者相同 -> True

# 決策級輸出:策略真實勝率大於五成的機率
th = np.linspace(1e-6, 1 - 1e-6, 200_001)
logB = lgamma(28) + lgamma(20) - lgamma(48)
pdf = np.exp(27 * np.log(th) + 19 * np.log(1 - th) - logB)
print("P(theta > 0.5 | 資料) =", round(np.trapz(pdf[th > 0.5], th[th > 0.5]), 4))
# 輸出:P(theta > 0.5 | 資料) = 0.8785

三個觀察。第一,後驗平均 0.5833 落在先驗中心 0.5 與勝場比例 0.6 之間——收縮如期發生。第二,後驗標準差從先驗的 0.1667 一路縮到 0.0704:資料進來,信念收窄,這就是「學習」在分布語言裡的樣子。第三,逐筆更新與批次更新給出同一個後驗——這個性質叫序列貝葉斯更新,機器學習語境裡就是線上學習:模型隨資料流持續更新,不必回頭重算整批歷史。高頻風控、即時信用審核,吃的都是這口飯。

比喻: 主管心裡對新進交易員的評價,就是一部貝葉斯更新機。報到第一天,評價全靠履歷——這是先驗;之後每天的實際表現是新資料,下班時主管心裡的評價已經被當天表現修正過——這是後驗;隔天早上,昨晚的後驗自動變成今天的先驗。三個月後的總評價,跟把九十天表現攤開一次評完,結論一樣——這就是逐筆等於批次。而履歷越唬人(先驗越強),實際表現要扭轉它就得花越多天。

最後補一句頻率學派給不出的話:後驗算出 \(\mathbb{P}(\theta > 0.5 \mid \text{資料}) = 0.879\)——「這檔策略真的有優勢的機率約 88%」。p 值講的是「假設策略沒優勢,看到這種戰績多罕見」,繞著假設打轉;貝葉斯直接回答你真正想問的那個問題。

四、頻率還是貝葉斯:一張實務決策清單

哲學講完,回到工程。什麼時候該用哪一套?判準大致四條。

樣本大小。樣本大、似然函數又乖(單峰、低維),兩派答案幾乎重合——先驗被資料淹沒,這時頻率方法便宜又夠用。樣本小的時候差異才浮現:先驗知識值錢,但也危險——一個把機率質量放錯地方的先驗,會把後驗帶進溝裡。小樣本下選貝葉斯,等於選擇「信我的先驗」勝過「信漸近理論」,這筆交換要自覺地做。

似然的形狀。維度高、多峰、有平坦區的似然,最大概似估計的數值最佳化常常翻車(卡在局部極值、對起始點敏感);貝葉斯用抽樣方法從後驗抽點,反而繞開找唯一極值這件事——計算上有時是貝葉斯更穩,這點常出乎直覺。

更新的節奏。資料是一次到位還是持續流入?第三節看到,貝葉斯的逐筆更新天生就是線上學習;頻率方法要模仿這件事,通常得用滑動視窗反覆重估,既費算力又引入視窗長度這個新的任意參數。

計算預算。共軛組合(Beta-Bernoulli、常態-常態這類)的更新是解析的、近乎免費;一旦先驗與似然不共軛,就得動用數值積分或馬可夫鏈蒙地卡羅,成本跳一個量級。實務上大量貝葉斯應用刻意留在共軛世界裡,不是因為共軛先驗最能表達信念,而是因為它讓即時更新可行——這是誠實的工程妥協。

五、模型選擇:證據、Occam 剃刀與模型平均

到目前為止都在「一個模型內」估參數。更難的問題是模型之間怎麼選。這問題在金融裡格外尖銳:同一批報酬資料,三個不同的因子組合常常配適度幾乎相同,但對「哪些變數重要」給出完全不同的故事——選錯敘事,下一季的部位就跟著錯。頻率學派的工具(顯著性檢定、資訊準則)在模型彼此不巢套、係數顯著性又相近時,經常給不出乾脆的裁決。

貝葉斯的答案是把「哪個模型對」也當成一個推論問題。關鍵量是第三節被我們無視的分母——邊際似然,模型選擇語境裡改叫證據

$$ p(\mathbf{y} \mid \mathcal{M}) \;=\; \int p(\mathbf{y} \mid \theta, \mathcal{M})\, p(\theta \mid \mathcal{M})\, d\theta $$

逐項拆解:\(\mathcal{M}\) 是候選模型;積分把「模型在每一個參數值下解釋資料的能力」用先驗加權平均起來。注意動詞——是平均,不是挑最大。最大概似看的是模型調到最佳狀態時的表現;證據看的是模型在先驗覆蓋的整個參數範圍上的平均表現。兩個模型的證據相除叫貝氏因子,配上模型的先驗機率就能算出各模型的後驗機率。

比喻: 評估兩家投信,一家只發一檔基金,另一家旗下三百檔。只看冠軍基金(最大概似),三百檔那家幾乎必贏——檔數多,總有幾檔押中行情。改看全公司平均績效(證據),大量押錯方向的基金會把平均拉下來,小而準的那家反而勝出。複雜模型就是旗下基金超多的投信:參數空間大,總有某組參數把資料配得漂亮,但把先驗下所有參數版本平均起來,攤薄效應現形。「挑最大」獎勵彈性,「取平均」懲罰彈性——證據自動內建 Occam 剃刀,這就是機制。

用一個交易例子跑數字。過去 60 個交易日,大盤 36 天收漲。兩個候選模型:\(\mathcal{M}_1\)——隨機漫步,上漲機率鎖死 0.5,零參數;\(\mathcal{M}_2\)——上漲機率是未知的 \(\theta\),先驗均勻。60% 的上漲日看起來像趨勢,證據怎麼判?

PYTHON
import math

n, x = 60, 36                                # 60 個交易日,36 天收漲
ev1 = math.comb(n, x) * 0.5 ** n             # M1:p=0.5,無參數可積分
ev2 = 1 / (n + 1)                            # M2:均勻先驗下的證據(解析結果)
w1, w2 = ev1 / (ev1 + ev2), ev2 / (ev1 + ev2)
print(f"證據 M1={ev1:.6f}  M2={ev2:.6f}")
print(f"貝氏因子 M2/M1 = {ev2/ev1:.3f}(ln BF = {math.log(ev2/ev1):+.3f})")
print(f"模型後驗機率:隨機漫步 {w1:.3f}|未知偏差 {w2:.3f}")
# 輸出:
# 證據 M1=0.031270  M2=0.016393
# 貝氏因子 M2/M1 = 0.524(ln BF = -0.646)
# 模型後驗機率:隨機漫步 0.656|未知偏差 0.344

# 模型平均預測明天上漲的機率
p1, p2 = 0.5, (x + 1) / (n + 2)              # M2 的後驗預測機率
print(f"BMA 預測 = {w1*p1 + w2*p2:.4f}(M1 給 {p1}、M2 給 {p2:.4f})")
# 輸出:BMA 預測 = 0.5333(M1 給 0.5、M2 給 0.5968)

# 對照組:若是 42 天收漲呢?
ev1b = math.comb(60, 42) * 0.5 ** 60
print(f"42/60 時:ln BF = {math.log((1/61)/ev1b):+.3f}")
# 輸出:42/60 時:ln BF = +3.017

結果值得盯三秒:36/60 的上漲日,證據卻以 0.656 對 0.344 偏向隨機漫步。直覺會喊「六成上漲、有趨勢」,證據說:這種程度的偏離,簡單模型自己就解釋得掉,犯不著為它添一個自由參數。\(\mathcal{M}_2\) 的問題不是配不上資料——它配得更好——而是它的先驗把預算攤在所有 \(\theta\) 上,大量根本不像資料的 \(\theta\) 拖垮了平均。要到 42/60(七成上漲日),對數貝氏因子才翻到 +3.0,證據強烈轉向「真有偏差」。證據不獎勵配適,獎勵「以合理的預算配適」

最後一步是想通了就很自然的延伸:既然模型有後驗機率,何必單壓一個?貝葉斯模型平均(BMA)把各模型的預測用模型後驗機率加權——上例中 BMA 給出明天上漲機率 0.5333,介於兩個模型之間、偏向證據較強的那個。當沒有任何模型一枝獨秀時,模型不確定性本身就是風險,BMA 把這層風險誠實地攤進預測裡,而不是假裝你已經知道哪個模型是對的。作業二會讓你在樣本外驗證:這個「不押注」的策略常常比任何單一模型都穩。

六、機率圖模型與混合模型:幫市場狀態做軟分群

單參數推論走完了,往多變數世界跨一步。機率圖模型用一張圖表達一組隨機變數的依賴結構:節點是變數,邊是條件依賴,箭頭有方向時稱貝葉斯網路。它的價值是把「聯合分布」這個高維怪物拆成一串局部條件分布的乘積——圖的結構本身就是一組條件獨立假設。你其實已經見過一個最小的例子而不自知:假設特徵在給定類別下彼此條件獨立,就得到樸素貝葉斯分類器——它與 logistic 迴歸是同一枚硬幣的生成面與判別面(推導收在原書對照)。

這一節聚焦圖模型家族裡對金融最實用的成員:混合模型。動機很直白:市場日報酬用一顆常態分布罩不住——平靜期的報酬窄而密,動盪期寬而狂,硬用單一常態去配,兩邊都配不像。混合模型的辦法是疊加:

$$ p(x) \;=\; \sum_{k=1}^{K} \pi_k \,\mathcal{N}\!\left(x;\, \mu_k, \sigma_k^2\right) $$

逐項拆解:\(K\) 是成分(狀態)數,這裡取 2——平靜與動盪;\(\mathcal{N}(x;\mu_k,\sigma_k^2)\) 是第 k 個狀態自己的常態分布,各有各的平均 \(\mu_k\) 與波動 \(\sigma_k\);\(\pi_k\) 是混合權重——隨便抽一天,它屬於狀態 k 的機率,加總為一。這就是高斯混合模型(GMM)。

麻煩在於:每一天屬於哪個狀態,資料裡沒寫——它是隱變數。給定參數,我們能做的是回頭問每一天:「你比較像哪個狀態生的?」答案又是一次貝葉斯定理:

$$ \gamma_k(x_i) \;=\; \frac{\pi_k\, \mathcal{N}(x_i;\, \mu_k, \sigma_k^2)}{\sum_{\ell} \pi_\ell\, \mathcal{N}(x_i;\, \mu_\ell, \sigma_\ell^2)} $$

逐項拆解:分子是「先驗(狀態占比)乘似然(該狀態生出這筆報酬的密度)」,分母是全部狀態加總的正規化——結構跟第三節的貝葉斯定理一模一樣,只是參數換成了隱狀態。\(\gamma_k(x_i)\) 稱為責任值:狀態 k 對觀測 \(x_i\) 負多少責任。注意它是 0 到 1 的連續值,不是硬邦邦的分派——每一天拿到的是各狀態的成員機率,這就是軟分群,K-means 那種一刀切的硬分群是它把責任值推到極端後的特例。

比喻: 責任值像 DNA 祖源報告。報告不會把你硬塞進單一族群,而是說「你的基因 80% 來自甲族群、20% 來自乙族群」——每個族群對你的血統各負一部分責任。混合模型給每個交易日出的就是這種報告:這一天的報酬,八成像平靜市場生的、兩成像動盪市場生的。硬要二選一反而丟資訊——曖昧本身就是資料告訴你的事實。

參數與隱狀態互相依賴——知道參數才能算責任值,知道責任值才好估參數——EM 演算法用交替迭代解開這個雞生蛋問題:E 步固定參數、算每筆資料的責任值;M 步固定責任值、用它加權重估參數(加權平均、加權變異數、權重占比);來回迭代到收斂,每一輪都保證似然不降。實跑一次——模擬 500 個交易日,八成日子從平靜分布(平均 +0.05%、波動 0.8%)抽出,兩成從動盪分布(平均 −0.1%、波動 2.5%)抽出,然後讓 EM 在不知道哪天是哪種狀態的前提下把結構挖回來:

PYTHON
import numpy as np

rng = np.random.default_rng(88)
n = 500
turb = rng.random(n) < 0.2                       # 真實狀態(EM 看不到)
r = np.where(turb, rng.normal(-0.001, 0.025, n),  # 動盪:平均-0.1%、波動2.5%
                   rng.normal(0.0005, 0.008, n))  # 平靜:平均+0.05%、波動0.8%

def npdf(x, mu, sd):
    return np.exp(-0.5 * ((x - mu) / sd) ** 2) / (sd * np.sqrt(2 * np.pi))

pi1, mu1, sd1 = 0.5, 0.0, 0.005                  # 初始猜測:成分1(窄)
pi2, mu2, sd2 = 0.5, 0.0, 0.030                  # 初始猜測:成分2(寬)
for _ in range(200):
    w1, w2 = pi1 * npdf(r, mu1, sd1), pi2 * npdf(r, mu2, sd2)
    g1 = w1 / (w1 + w2); g2 = 1 - g1             # E 步:責任值
    pi1, pi2 = g1.mean(), g2.mean()              # M 步:加權重估
    mu1, mu2 = (g1*r).sum()/g1.sum(), (g2*r).sum()/g2.sum()
    sd1 = np.sqrt((g1*(r-mu1)**2).sum()/g1.sum())
    sd2 = np.sqrt((g2*(r-mu2)**2).sum()/g2.sum())

print(f"平靜:占比 {pi1:.3f}|波動 {sd1*100:.3f}%   (真實佔比 {1-turb.mean():.2f})")
print(f"動盪:占比 {pi2:.3f}|波動 {sd2*100:.3f}%   (真實佔比 {turb.mean():.2f})")
for x0 in (-0.05, -0.012, 0.003):
    a = pi1 * npdf(x0, mu1, sd1); b = pi2 * npdf(x0, mu2, sd2)
    print(f"日報酬 {x0*100:+.1f}% -> 平靜責任 {a/(a+b):.3f}|動盪責任 {b/(a+b):.3f}")
# 輸出:
# 平靜:占比 0.795|波動 0.803%   (真實佔比 0.78)
# 動盪:占比 0.205|波動 2.398%   (真實佔比 0.22)
# 日報酬 -5.0% -> 平靜責任 0.000|動盪責任 1.000
# 日報酬 -1.2% -> 平靜責任 0.808|動盪責任 0.192
# 日報酬 +0.3% -> 平靜責任 0.917|動盪責任 0.083

EM 從完全不知情出發,把動盪日占比估到 0.205(真實 0.22)、兩個狀態的波動率也都貼近真值。責任值的行為更值得玩味:單日 −5% 幾乎確定是動盪狀態(責任 1.000);但 −1.2% 的下跌日,模型反而說八成像平靜狀態——因為平靜分布雖窄,0.8% 波動下跌 1.2% 並不稀奇,而動盪狀態的先驗占比只有兩成。軟分群不是按報酬絕對值切線,是先驗與似然的完整權衡。這套「隱狀態+軟歸屬」的思維有個著名的實務化身:風險管理裡把市場拆成常態與壓力兩種情境的壓力測試建模。它目前少了一樣東西——狀態的時間記憶(今天動盪,明天多半還動盪);給隱狀態裝上轉移機率,就是第 7 章的隱馬可夫模型。

七、金融連結:厚尾與部位規模

收尾前,把本章兩個工具直接接上金融的兩條神經。

厚尾是混合的影子。金融日報酬的分布比常態「尖峰厚尾」——極端日出現的頻率遠超常態分布的預言,這是金融計量最老牌的典型事實之一。混合模型給了它一個結構性解釋:上一節那批模擬報酬,逐日來看每天都從某個常態分布抽出,但兩種波動率混在一起,整體樣本的超額峰度實測達 3.72(常態為 0)——常態的混合天生就是厚尾。反過來說:用單一常態去估風險值,等於假裝動盪狀態不存在,極端損失的機率會被系統性低估。這也呼應第 1 章的警語——模型的失效模式比模型的平均表現更值得研究。

參數不確定性應該縮小你的部位。第三節的策略:後驗 Beta(28,20)。假設每筆交易賠率一比一,凱利公式說最適下注比例是 \(f^* = 2p - 1\)。插入式做法拿點估計 0.6 直接代入,得 \(f = 0.2\)。但 0.6 只是分布的一個點——後驗還告訴我們 \(\theta\) 有 12.1% 的機率根本小於 0.5。把整個後驗攤開,對每個候選部位計算後驗期望對數成長率再取最大:

PYTHON
import numpy as np
from math import lgamma

th = np.linspace(1e-6, 1 - 1e-6, 200_001)
logB = lgamma(28) + lgamma(20) - lgamma(48)
pdf = np.exp(27 * np.log(th) + 19 * np.log(1 - th) - logB)   # 後驗 Beta(28,20)

f_grid = np.linspace(0.0, 0.4, 41)
growth = [np.trapz((th * np.log1p(f) + (1 - th) * np.log1p(-f)) * pdf, th)
          for f in f_grid]
best = int(np.argmax(growth))
print(f"插入式凱利(p=0.6):f = {2*0.6-1:.2f}")
print(f"後驗期望成長最大化:f = {f_grid[best]:.2f}(期望對數成長 {growth[best]:.5f})")
print(f"插入式 f=0.20 的期望對數成長:{growth[20]:.5f}")
# 輸出:
# 插入式凱利(p=0.6):f = 0.20
# 後驗期望成長最大化:f = 0.17(期望對數成長 0.01395)
# 插入式 f=0.20 的期望對數成長:0.01338

答案從 0.20 降到 0.17——不是因為策略變差,而是因為我們對它的認識還不夠好。插入式決策把點估計當真值用,等於對參數不確定性視而不見;貝葉斯決策把「勝率可能其實不到五成」的那 12.1% 機率誠實計價,最適部位自動變保守。40 筆交易的資訊量,就只配 0.17 的部位——資料多了、後驗收窄了,最適部位才會慢慢向 0.20 靠攏。把不確定性留在模型裡直到做決策的最後一刻,這是貝葉斯思維對資金管理最實際的一句忠告,也是第 3 章把同一套思維推向迴歸與高斯過程時,我們要一路帶著的紀律。

§03原書對照

本課以自創例子重走了原書第二章的骨架,下列內容原書有、本課未展開,按頁碼供深入。其一,似然概念的思想史定位:原書引述 Fisher 本人說明為何需要在「機率」之外另造「概似」一詞,並以此標記頻率學派的方法論起點(p.52)。其二,估計量品質的完整損失函數家族:絕對誤差與平方誤差、平均絕對誤差、均方誤差與其平方根、最小均方誤差估計量,以及多維參數的誤差共變異矩陣(pp.54–55);本課只用了其中的 MSE 分解。其三,Duembgen 與 Rogers「什麼都不要估」的立場:對衍生品定價中「先校準、再把估計值當真值用」的主流做法之批判,主張以濾波與 MCMC 維持全程機率一致性(p.50)。其四,無差別原則的警示框:把「五五開」當成無知的預設其實注入了多餘資訊,並以「某股票明天會不會漲」為例說明對投資問題濫用此原則的危險(p.59)。其五,擲幣例的後驗變異數完整數值推演(式 2.4–2.5,p.58)與含 Gamma 函數的 Beta 正規化常數(式 2.6,p.61)。其六,貝葉斯預測分布的一般式:把似然對後驗積分得到新觀測的分布(式 2.8,p.62)。其七,模型選擇的量化尺度:Jeffreys 尺度表把對數貝氏因子分成弱、中、強證據帶(表 2.1,p.67);例 2.4 以 200 次擲幣 115 次正面對比兩模型,算出貝氏因子後結論是證據不足,並附一個發人深省的旁註——同一批資料的頻率學派雙尾檢定 p 值約 4%、會拒絕公正硬幣假設,兩套方法論在同一資料上分道揚鑣(pp.67–68)。其八,超參數與階層貝葉斯建模:先驗自身的參數、先驗的先驗(p.68)。其九,logistic 迴歸與樸素貝葉斯的精確對應:權重為對數似然比、截距為對數勝算比的完整推導,與條件獨立假設的角色(pp.70–72,習題 2.7)。其十,受限玻爾茲曼機作為無向圖模型的能量函數表述(p.72,習題 2.8)。其十一,成分數 K 的決定:Kolmogorov–Smirnoff 檢定與熵準則,以及厚尾資料至少需要兩個輕尾成分補償的實務準則(p.75)。其十二,章末習題群:查帳詐欺偵測的貝葉斯定理應用、日圓匯率與 S&P 500 的條件機率耦合模型、以及序列資料下的模型比較與預測更新(pp.76–79)。原書第二章對應印刷頁 pp.47–80。

§04作業和解答

作業一:Beta-Bernoulli 手算+numpy 驗證

另一檔新策略只累積了 15 筆交易、9 勝 6 敗。先驗取 Beta(2,2)。(1) 手算後驗分布、後驗平均與後驗標準差;(2) 用 numpy 驗證手算,並計算策略真實勝率大於 0.5 的機率;(3) 說明同樣是六成勝場比例,為什麼這裡的後驗比第三節(40 筆、24 勝)更寬。

解答 SOLUTION

(1) 手算:後驗 \(\mathrm{Beta}(2+9,\,2+6)=\mathrm{Beta}(11,8)\)。後驗平均 \(11/19 \approx 0.5789\)(介於先驗中心 0.5 與勝場比例 0.6 之間)。後驗變異數 \(11\times 8/(19^2\times 20) = 88/7220 \approx 0.01219\),標準差 \(\approx 0.1104\)。

(2) numpy 驗證:

PYTHON
import numpy as np
from math import lgamma

a, b = 2 + 9, 2 + 6                       # Beta(11, 8)
mean = a / (a + b)
sd = (a * b / ((a + b) ** 2 * (a + b + 1))) ** 0.5
print(f"後驗平均 {mean:.4f}|後驗標準差 {sd:.4f}")   # 0.5789|0.1104

th = np.linspace(1e-6, 1 - 1e-6, 200_001)
logB = lgamma(a) + lgamma(b) - lgamma(a + b)
pdf = np.exp((a - 1) * np.log(th) + (b - 1) * np.log(1 - th) - logB)
print("P(theta > 0.5) =", round(np.trapz(pdf[th > 0.5], th[th > 0.5]), 4))
# 輸出:P(theta > 0.5) = 0.7596

(3) 兩個原因疊加。第一,資訊量:後驗的「等效樣本數」是 \(\alpha+\beta+n\),這裡是 19,第三節是 48——資料少,信念自然寬。第二,量化對比:勝率大於五成的機率這裡只有 76.0%,第三節是 87.9%。同樣的勝場比例,樣本量不同,該有的信心就不同——這正是點估計丟掉、而後驗保留下來的資訊。用 15 筆交易的戰績決定加碼幅度,和用 40 筆決定,本來就不該是同一個數字。

作業二:模型平均 vs 單一模型的樣本外比較

延續第五節:訓練期 60 個交易日、36 天收漲,三個預測器——\(\mathcal{M}_1\) 永遠報 0.5、\(\mathcal{M}_2\) 報後驗預測機率 \(37/62 \approx 0.5968\)、BMA 報 0.5333。現在拿到樣本外 40 個交易日,其中 21 天收漲。用平均對數損失(log loss,越小越好)比較三者的樣本外表現,並解釋結果。

解答 SOLUTION
PYTHON
import math

preds = {"M1 隨機漫步": 0.5, "M2 未知偏差": 37/62, "BMA": 0.5333}
n_te, x_te = 40, 21                       # 樣本外:40 天、21 天收漲
for name, p in preds.items():
    ll = -(x_te * math.log(p) + (n_te - x_te) * math.log(1 - p)) / n_te
    print(f"{name:>8s}|預測 {p:.4f}|樣本外 log loss {ll:.5f}")
# 輸出:
# M1 隨機漫步|預測 0.5000|樣本外 log loss 0.69315
# M2 未知偏差|預測 0.5968|樣本外 log loss 0.70244
# BMA|預測 0.5333|樣本外 log loss 0.69203

樣本外上漲比例 21/40 = 0.525。\(\mathcal{M}_2\) 被訓練期的 0.6 帶得太滿,樣本外反而墊底;\(\mathcal{M}_1\) 太保守;BMA 的 0.5333 離事後真相 0.525 最近,log loss 最低。機制:BMA 的預測是兩個模型按證據加權的折衷,訓練期資料不足以裁決誰對時,它拒絕押注單一敘事,於是在樣本外吃到「不押注」的紅利。要強調的是:BMA 不是永遠贏——若樣本外真的走出強趨勢,\(\mathcal{M}_2\) 會反超——它贏的是期望:在模型不確定性真實存在時,加權平均的預測比賭對單一模型的預測更穩。這與第 1 章「新舊模型並肩跑」的實務智慧一脈相承,只是這裡連權重都由證據自動決定。

作業三:混合模型責任值計算

某市場的兩狀態高斯混合參數為:平靜狀態占比 0.75、平均 +0.04%、波動 0.7%;動盪狀態占比 0.25、平均 −0.2%、波動 2.2%。(1) 寫出責任值公式,手算日報酬 −3.0% 那天動盪狀態的責任值;(2) 用 numpy 驗證,並同時計算日報酬 +0.1% 那天;(3) 解釋為何 +0.1% 那天動盪責任不是零。

解答 SOLUTION

(1) 責任值 \(\gamma_{\text{動盪}}(x) = \pi_t\,\mathcal{N}(x;\mu_t,\sigma_t^2)\,/\,[\pi_c\,\mathcal{N}(x;\mu_c,\sigma_c^2) + \pi_t\,\mathcal{N}(x;\mu_t,\sigma_t^2)]\)。對 \(x=-0.03\):平靜密度需要算 \((x-\mu_c)/\sigma_c = (-0.03-0.0004)/0.007 \approx -4.34\),超過四個標準差,密度趨近零;動盪密度 \((x-\mu_t)/\sigma_t = (-0.03+0.002)/0.022 \approx -1.27\),密度可觀。分子遠大於分母中的平靜項,責任值應非常接近 1。

(2) numpy 驗證:

PYTHON
import numpy as np

def npdf(x, mu, sd):
    return np.exp(-0.5 * ((x - mu) / sd) ** 2) / (sd * np.sqrt(2 * np.pi))

pi_c, mu_c, sd_c = 0.75, 0.0004, 0.007    # 平靜
pi_t, mu_t, sd_t = 0.25, -0.002, 0.022    # 動盪
for x0 in (-0.03, 0.001):
    wc, wt = pi_c * npdf(x0, mu_c, sd_c), pi_t * npdf(x0, mu_t, sd_t)
    print(f"日報酬 {x0*100:+.1f}%|平靜責任 {wc/(wc+wt):.4f}|動盪責任 {wt/(wc+wt):.4f}")
# 輸出:
# 日報酬 -3.0%|平靜責任 0.0017|動盪責任 0.9983
# 日報酬 +0.1%|平靜責任 0.9046|動盪責任 0.0954

手算方向正確:−3.0% 那天動盪責任 0.9983。

(3) +0.1% 是一個再平凡不過的日子,但動盪狀態並非只生產極端報酬——它是一顆以 −0.2% 為中心、2.2% 波動的常態分布,生出 +0.1% 的密度並不小,只是比平靜狀態小一個量級;再乘上 0.25 的先驗占比,就得到 9.5% 的責任。這正是軟分群的要義:平凡的日子也可能出自動盪狀態,只是機率較低。硬分群會把這一天百分之百記給平靜狀態,動盪狀態的參數估計就永遠學不到自己也會生產平凡日子這件事——EM 之所以用責任值加權而不是硬分派,原因就在這裡。

作業四:框架選擇的實戰判斷

三個場景,各自回答「頻率、貝葉斯、還是都可以」,並給出兩條以上理由:(1) 一檔剛上線兩週、僅 18 筆交易的新策略,要決定是否加碼;(2) 高頻做市系統,每天數十萬筆成交紀錄,要估計某特徵與短期價格變動的關係;(3) 銀行的線上信用審核模型,客群的違約行為隨景氣緩慢漂移,需要持續吸收新案件。

解答 SOLUTION

(1) 貝葉斯。第一,18 筆交易處於小樣本深水區,頻率學派的漸近性質完全靠不住,信賴區間寬得沒有行動含義;貝葉斯可以把回測績效或同類策略的歷史表現編成先驗補血。第二,加碼是決策問題,需要的是「勝率大於某門檻的機率」這種後驗語句與第七節那種期望效用計算,頻率輸出接不上這個決策介面。但要自覺:此時結論對先驗敏感,先驗要攤開給投資委員會看,而不是藏在代碼裡。

(2) 頻率(或兩者皆可)。第一,數十萬筆樣本早已進入「先驗被資料淹沒」的區間,兩派答案幾乎相同,貝葉斯的額外計算成本買不到東西。第二,高頻場景對延遲敏感,最大概似或最小平方的解析解與增量演算法成熟便宜。值得補一句:若似然多峰或參數高維到 MLE 最佳化不穩,貝葉斯抽樣反而是計算上的避風港——「大樣本就用頻率」是經驗法則,不是定理。

(3) 貝葉斯。第一,「持續吸收新案件」正是序列更新的主場:後驗變先驗、逐筆進化,不必定期拿全部歷史重訓;頻率方案得靠滑動視窗重估,多出視窗長度這個任意選擇。第二,客群漂移意味著舊資料的代表性衰減,貝葉斯框架可以對舊資訊做打折(例如把後驗適度加寬再當先驗),把「遺忘」做成機制。但注意:漂移若是斷崖式的制度變遷而非緩慢漂移,任何自動更新都會慢半拍——第 1 章房貸案例的教訓在此依然有效,監控與人工接管的護欄不可省。

§05參考資料