Monte Carlo 怎麼算條件機率 P(A|B)?
原題
考慮擲出骰子並採用 Monte Carlo 方法估算條件機率,參考附圖程式碼。 import numpy as np np.random.seed(123) n = 100000 dice_rolls = np.random.randint(1, 7, size=n) A = (dice_rolls % 2 == 0) B = (dice_rolls > 3) A_and_B = A & B 事件 A:擲出偶數 事件 B:擲出大於 3 請問下列何者為條件機率 P(A | B) 的正確值?
白話
程式模擬了 10 萬次擲骰子,定義了兩個事件:事件 A 是擲出偶數(2、4、6),事件 B 是擲出大於 3 的點數(4、5、6)。程式分別算出 A 出現幾次、B 出現幾次,以及 A 和 B 同時出現幾次,接著提供四個不同的計算式。
問你:哪一個計算式才能正確算出「已知 B 發生的前提下,A 發生的機率」P(A|B)?
先自己選一個答案,再看完整解析。
一句話總結
條件機率 P(A|B) 的公式是 P(A∩B) / P(B),換成程式碼就是 A_and_B.sum() / B.sum():分子是「A 和 B 同時發生」的次數,分母是「B 發生」的次數。
情境
先感受問題:「已知骰子大於 3,偶數機率是多少?」
假設你在桌遊社裡用程式幫大家驗證機率。你擲了 10 萬次骰子,現在有人問:「如果你知道這次骰出來的點數大於 3,那麼它同時是偶數的機率是多少?」
大於 3 的點數有 4、5、6 三種,其中偶數只有 4 和 6 兩種,所以直覺告訴你答案應該接近 2/3 ≈ 0.667。
這就是「條件機率」的核心想法:縮小範圍。不是在所有 10 萬次中找偶數,而是先把範圍縮小到「大於 3 的那些次」,再看其中有多少是偶數。
用程式碼來表達這個縮小範圍的概念,分母就是 B 的次數(大於 3 發生了幾次),分子是 A 和 B 同時滿足的次數(又大於 3 又是偶數)。
舊方法
直接算「偶數的總次數」,為什麼會算錯?
- 沒縮小範圍就算:如果用 A.sum() / n 算出的是「所有 10 萬次中偶數的機率」,也就是無條件機率 P(A) ≈ 0.5,完全沒有用到「已知大於 3」這個條件。
- 用 A.sum() 當分母:選項 C 的 A_and_B.sum() / A.sum() 算的是「在偶數中有多少大於 3」,這是 P(B|A),不是 P(A|B),把條件搞反了。
- 用兩個事件的次數相乘當分母:選項 A 的 A.sum() * B.sum() 沒有機率學上的意義,不對應任何正確公式。
- 用兩個事件的次數相加當分母:選項 B 的 A.sum() + B.sum() 也沒有意義,不是條件機率的計算方式,這樣分母會超過總樣本數。
- 混淆聯合機率與條件機率:聯合機率 P(A∩B) = A_and_B.sum() / n,是兩者同時發生的無條件機率;條件機率 P(A|B) 要再除以 P(B),也就是再縮小到 B 的範圍。
新方法
條件機率:先鎖定 B 的範圍,再數 A
骰子模擬的結果:10 萬次中,大於 3 的次數(B)大約是 50,000 次(機率 3/6 = 0.5),其中又是偶數的(A∩B,即點數 4 或 6)大約是 33,333 次(機率 2/6 ≈ 0.333)。
條件機率公式:P(A|B) = P(A∩B) / P(B)
換成樣本次數:P(A|B) ≈ A_and_B.sum() / B.sum() ≈ 33,333 / 50,000 ≈ 0.667
這與直覺計算(大於 3 的 3 個點數 4、5、6 中,偶數有 4 和 6 共 2 個,所以 2/3)完全一致。
這就是選項 D 講的:A_and_B.sum() / B.sum()。
中級考試大概率會考程式碼跟公式,所以這部分你還是要學。但如果現在學起來很痛苦,可以先跳過,等讀完其他題目回頭再來。
Step 1 純故事版(不出現公式)
想像你是籃球場的計分員,負責記錄每次投籃。你有一本記錄簿,裡面有「是否三分球」和「是否進球」兩欄。
有人問:「已知這次是三分球,進球的機率是多少?」
你不會去數所有投籃的進球率,而是先翻到「三分球」那幾頁,再數其中進球了幾次。這就是條件機率:先縮小到已知的條件範圍,再計算目標事件的比例。
Monte Carlo 做的事情一樣:先用程式模擬大量樣本,然後數出「符合條件 B 的樣本」有多少,再數其中「同時符合 A」的有多少,兩者相除就是 P(A|B) 的估計值。
Step 2 中文 ↔ 程式碼對照
| 白話說法 | 程式碼 |
|---|---|
| 模擬 10 萬次骰子 | dice_rolls = np.random.randint(1, 7, size=n) |
| 事件 A:擲出偶數 | A = (dice_rolls % 2 == 0) |
| 事件 B:擲出大於 3 | B = (dice_rolls > 3) |
| A 和 B 同時發生 | A_and_B = A & B |
| P(A|B) = P(A∩B) / P(B) | A_and_B.sum() / B.sum() |
Step 3 符號角色表
- P(A|B):條件機率:在 B 已發生的前提下,A 發生的機率
- P(A∩B):聯合機率:A 和 B 同時發生的機率
- P(B):邊際機率(marginal probability):B 發生的機率,不論 A
- A_and_B.sum():A 和 B 同時為 True 的樣本數,近似 n×P(A∩B)
- B.sum():B 為 True 的樣本數,近似 n×P(B)
- n:總模擬次數(10 萬),n 越大估計越準確
Step 4 完整公式對應
條件機率公式:P(A|B) = P(A∩B) / P(B) 骰子理論值: P(A) = 3/6 = 0.5 (偶數:2, 4, 6) P(B) = 3/6 = 0.5 (大於3:4, 5, 6) P(A∩B) = 2/6 ≈ 0.333 (偶數且大於3:4, 6) P(A|B) = (2/6) / (3/6) = 2/3 ≈ 0.667 程式碼估計(10萬次模擬): A_and_B.sum() ≈ 33,333 B.sum() ≈ 50,000 P(A|B) ≈ 33,333 / 50,000 ≈ 0.667 ✓ 與理論值吻合 選項 A:A_and_B.sum() / (A.sum() * B.sum()) 分母 ≈ 50,000 × 50,000 = 2.5 × 10⁹ → 結果接近 0,無意義 選項 B:A_and_B.sum() / (A.sum() + B.sum()) 分母 ≈ 100,000 → 實際算的是 P(A∩B),不是條件機率 選項 C:A_and_B.sum() / A.sum() ≈ 33,333 / 50,000 ≈ 0.667 → 這是 P(B|A),條件反了
Step 5 自我複述
- P(A|B) 和 P(B|A) 有什麼差異?請各舉一個生活例子。
- 如果把程式碼的 B.sum() 改成 n,算出的是什麼機率?
- 為什麼選項 C 算出來的數字和正解 D 接近(都約 0.667),但意義完全不同?
- Monte Carlo 的估計值和理論值為什麼不會完全相同?n 增大時會怎樣?
- np.random.seed(123) 的作用是什麼?去掉會怎樣?
錯選項
為什麼其他選項是錯的
AA_and_B.sum() / (A.sum() * B.sum())
字面在說什麼
用 A 發生次數乘以 B 發生次數當分母。
為什麼不對
A.sum() 和 B.sum() 各約 50,000,相乘後分母高達 25 億,讓結果趨近於零。這個算式在機率學中沒有意義,不對應任何已知的機率概念。這是把「積事件」和「積」混淆:A∩B 的個數除以 A 個數,而非除以 A 個數乘以 B 個數。
誰會選錯
看到題目裡同時有 A 和 B,不假思索地把兩者都放進分母、卻用乘法而非加法的人。直覺上覺得「兩個事件的組合」就要用兩個的乘積。
BA_and_B.sum() / (A.sum() + B.sum())
字面在說什麼
用 A 發生次數加上 B 發生次數當分母。
為什麼不對
A.sum() + B.sum() ≈ 50,000 + 50,000 = 100,000,接近總樣本數 n,所以這個式子算出來的值近似 A_and_B.sum() / n,也就是聯合機率 P(A∩B),不是條件機率 P(A|B)。條件機率需要「縮小到 B 的範圍」,分母應該只用 B 的次數。
誰會選錯
記得「條件機率要用到 A 和 B」,但不確定分母是相加還是只用 B,於是選了「兩者相加」這個看起來最保險的選項。
CA_and_B.sum() / A.sum()
字面在說什麼
用 A 的發生次數當分母,A 和 B 同時發生的次數當分子。
為什麼不對
這個式子算的是 P(B|A),也就是「已知擲出偶數,點數大於 3 的機率」,把條件搞反了。骰子的 P(B|A) = P(A∩B) / P(A) = (2/6) / (3/6) = 2/3,確實也約等於 0.667,和正解相同:這是個典型的陷阱,數字一樣但公式意義相反。
誰會選錯
沒注意到 P(A|B) 和 P(B|A) 在這個題目中恰好數值相同(因為 P(A) = P(B)),以為選了正確公式,實際上公式是顛倒的。
變形題
同個考點下次怎麼變形
答案
用條件機率 P(有病|陽性) = P(有病∩陽性) / P(陽性)。同樣的公式,分子是「真陽性」次數,分母是「所有陽性」次數,這就是醫學上的「陽性預測值(PPV)」。
答案
P(B|A) = A_and_B.sum() / A.sum(),這就是選項 C 的算法。在這題中 P(B|A) ≈ 33,333 / 50,000 ≈ 0.667,和 P(A|B) 數值相同,但意義完全不同。如果改變骰子面數或改變事件定義,P(A|B) 和 P(B|A) 就不會相等。
答案
P(A|B) = P(A)。獨立的意思就是「B 的發生不影響 A 的機率」。可以用程式驗證:如果把 B 改成「擲出奇數或偶數」(必然事件),P(A|B) 就等於 P(A) = 0.5。
答案
隨機誤差會增大,估計值在 0.667 附近波動更大。Monte Carlo 的收斂速度是 1/√n,樣本數減少 100 倍,誤差增加 10 倍。這就是為什麼 Monte Carlo 模擬通常需要大量樣本才能得到可靠估計。
答案
一樣。A[B] 是 NumPy 的布林索引,取出 B 為 True 時對應的 A 值,np.mean(A[B]) 計算這些 A 值的平均,就是「B 發生時 A 也發生」的比例,等價於條件機率 P(A|B)。這是更 Pythonic 的寫法,但背後邏輯相同。
延伸
想再往下看,這 5 個
- 蒙地卡羅方法(Monte Carlo Method)
本題核心工具,用大量隨機模擬來估計機率或積分值,樣本越多結果越準確。 - 貝氏定理(Bayes' Theorem)
條件機率的進階應用,描述在已有先驗知識的情況下如何更新機率估計。 - 機率分佈(Probability Distribution)
描述隨機變數各種結果的機率,骰子模擬的基礎,也是機器學習模型的核心假設。 - 假設檢定(Hypothesis Testing)
統計推論的基本方法,條件機率是計算 p-value 的基礎概念。 - 常態分佈(Normal Distribution)
Monte Carlo 模擬中最常用的機率分佈之一,許多統計推論都以此為假設基礎。