有趣的統計學(3)

雖然平均來看,莊家的優勢勝率沒有改變,但由於莊家明牌是可視的,明牌不同時,莊家與玩家的勝率是有變化的。這也是 Bayes 所教導我們的原理:看統計數字不能只看平均值和標準差。往下鑽研看到「條件機率」的話,也許可以改變局勢。

上一回用了些章節,說明這個 python 模擬程式的大致狀況。實際做了模擬,發現玩家僅僅改變叫牌策略並不能克服「先手劣勢」。在單一的叫牌策略中,低於(不含) 15 點叫牌的話,莊家的勝率是比較低的,約為 53.7%。這一節,我們來認識一下,莊家在平均53.7% 的勝率下,有沒有我們可乘之機?

二十一點的通用規則中,莊家會顯示一張「明牌」(下表欄位為Bank_Card)。我們試著從明牌的角度來分析莊家的勝率是否跟明牌顯示的結果相關。程式並不困難,利用前節所提的 python 物件組合成一位莊家四位玩家五萬次牌局的模擬程式。結果是這樣:

Bank Card 
2 
3 
4 
5 
6 
7 
8 
9 
10 
Q 
K 
A 
Plays 
15172 
15350 
15475 
15355 
15595 
15592 
15512 
15480 
15108 
14895 
14940 
15544 
15758 
6633 
6785 
6514 
6431 
6254 
6720 
7187 
7832 
8295 
8405 
8458 
8809 
10151 
Loses 
7245 
7389 
7824 
7732 
8201 
7515 
6945 
6214 
5333 
4959 
5013 
5209 
4047 
Equals 
124? 
1185 
1138 
114? 
1141 
1457 
1379 
1434 
1480 
1521 
1459 
1525 
1570 
Win_Rate 
0.45 
0.46 
0.43 
0.47 
0.51 
0.56 
0.61 
0.63 
0.63 
0.63 
0.71

這張表告訴我們很重要的資訊,在平均53.7%的勝率下,莊家的明牌如果是 2~7,其勝率低於50%,而明牌如果是 8, 9 勝率在 50-60%,10 和 A 的勝率,都高於 60%。

修改玩家的叫牌策略,看來沒有很好的變化:低於(不含) 13 叫牌的結果如下表。我們發現一個規律,莊家明牌如果是 5,6, 降低叫牌可以增加1-2% 勝率。背後的邏輯很簡單,明牌如果 5 或 6,另一張不論是什麼牌,莊家都得再叫牌。只要叫牌,10點 (包括 10, J, Q, K)的機率約有 30%,很容易爆牌。另一個發現,莊家的明牌如果是 7,8,9,那麼莊家贏牌的機率變高約 2%。

Bank Card 
2 
3 
4 
5 
6 
7 
8 
9 
10 
Q 
K 
A 
Plays 
15728 
15924 
15280 
15248 
15472 
15656 
15588 
15412 
15320 
15204 
14932 
15156 
15080 
Wins 
7153 
7152 
6604 
6301 
6083 
7089 
7657 
8306 
8834 
8869 
8688 
8766 
10153 
Loses 
7613 
7724 
7772 
8049 
8489 
7400 
6810 
5909 
5157 
5065 
5009 
5100 
3643 
Equals 
962 
1048 
904 
898 
900 
1167 
1121 
1197 
1329 
1270 
1235 
1290 
1284 
Win Rate 
0.48 
0.48 
0.46 
0.44 
0.42 
0.49 
0.53 
0.58 
0.63 
0.64 
0.63 
0.63 
0.74

所以,我們可以調整叫牌策略,當莊家的明牌為 5,6 時,我們要確保自己不爆牌。其他的時候,採用玩家勝率較高的叫牌策略 – 低於 15 叫牌。不過,我們知道,雖然提昇了些許勝率,但莊家的明牌如果是 10,J,Q,K,A 玩家勝率輸莊家太多,這樣的改變對輸贏的結果並沒有太大的幫助。

Bank Card 
2 
3 
4 
5 
6 
7 
8 
9 
10 
Q 
K 
A 
Plays 
15796 
15332 
15292 
15648 
15540 
15352 
15452 
15252 
15216 
15508 
15360 
15204 
15048 
Wins 
7139 
6837 
6519 
6326 
6455 
6663 
7189 
7663 
8465 
8600 
8602 
8296 
9774 
Loses 
7314 
7319 
7660 
8504 
8252 
7322 
6916 
6174 
5187 
5350 
5218 
5310 
3710 
Equals 
1343 
1176 
1113 
818 
833 
1367 
1347 
1415 
1564 
1558 
1540 
1598 
1564 
Win Rate 
0.49 
0.48 
0.46 
0.43 
0.44 
0.48 
0.51 
0.55 
0.62 
0.62 
0.62 
0.61 
0.72

改變莊家的勝率不容易,但其實改變輸贏的結果不難。如果莊家的明牌對我們有利的時候,我們增加籌碼,例如,十倍的賭注,我們來看看結果:

當 莊 冢 5 , 6 , 12 以 下 : ; 牌 。 否 15 以 下 囗 L ; 牌 
玩 冢 : 1 ins : 21238 , 
loses = 24787 , in % = 0 · 461 , 
當 莊 冢 5 , 6 , 12 以 下 : ; 牌 。 否 15 以 下 囗 L ; 牌 
玩 冢 : 2 ins : 21459 , 
loses = 24574 , in % = 0 · 466 , 
當 莊 冢 5 , 6 , 12 以 下 : ; 牌 。 否 15 以 下 囗 L ; 牌 
玩 冢 : 3 ins : 21324 , 
loses = 24725 , in % = 0 · 463 , 
當 莊 冢 5 , 6 , 12 以 下 : ; 牌 。 否 15 以 下 囗 L ; 牌 
玩 冢 : 4 ins : 21262 , 
loses = 24666 , in % = 0 · 463 , 
基 本 邏 黽 , 17 以 下 牌 
money = 24386 
money=26029 
money = 25856 
money = 26823 
莊 冢 , w 工 ns : 98752 loses = 85283 in % = e . 537 , 
money= -13e94

哈,雖然平均來看,莊家的優勢勝率沒有改變,但由於莊家明牌是可視的,明牌不同時,莊家與玩家的勝率不同,這給了我們可乘之機。這同時也是 Bayes 所教導我們的原理:看統計數字不能只看平均值和標準差。往下鑽研看到「條件機率」的話,也許可以改變局勢。

改變二十一點的下注方式,將改變每次輸贏的期望值。如果每位玩家,在高優勢的牌局時提高下注的倍數,可以扭轉「輸牌等於輸錢」的情勢,變成「雖然輸牌的次數一樣,但能夠贏錢」…至於二十一點的規則,每一家賭場都有些許不同。一些書裏有說,某些賭場在發完牌,賭客還沒碰牌前,是可以調整賭注的。看來我們得去找到這些賭場,然後做做實驗了…

有趣的統計學(2)

從流程我們可以很明顯地看出來,玩家在叫牌的時候,有一定的可能會「爆」,爆了就輸牌輸錢。即使後手的莊家也爆牌,這一局兩人的對決還是莊家勝。這是典型的「先手劣勢」

擊敗莊家?

上一回用了些章節,說明這個 python 程式的大致狀況,接下來我們可以利用這個模型,看看統計和模擬可以教我們什麼。

首先,我們安排四位玩家和一位莊家,使用三副 156 張牌,用到剩下 40 張牌的時候,洗牌再玩。莊家的策略很清楚,依據二十一點的規則,莊家牌點小於十七的時候,必須叫牌。如果我們讓玩家的策略跟莊家一模一樣,低於十七點叫牌。下注都用最低標準的金額…假設為一塊錢(美金??)好了,我們看看結果如何? 對了,平手的局我們不算勝負,這樣子數據比較容易理解。

三十次的結果

玩家:1號, wins:14, loses=13, win%=0.519, money=10001

玩家:2號, wins:15, loses=12, win%=0.556, money=10003

玩家:3號, wins:14, loses=16, win%=0.467, money=9999

玩家:4號, wins:11, loses=16, win%=0.407, money=9996

莊家, wins:57, loses=54, win%=0.514, money=50001

在四位玩家使用同樣的策略下注叫牌、沒耍任何花招的狀況下,二號玩家勝率高達 55.6%,四號玩家只有 40.7%,這說明小數量的玩牌,的確有相當大的運氣關係。好消息是,玩了三十局,輸贏其實不大。小賭怡情,還行。

再一個三十次呢,玩家勝率的變化很大,限於篇幅,有興趣可以自行測試一番。

三千次的結果

玩家:1號, wins:1265, loses=1446, win%=0.467, money=9848

玩家:2號, wins:1235, loses=1469, win%=0.457, money=9792

玩家:3號, wins:1272, loses=1430, win%=0.471, money=9872

玩家:4號, wins:1290, loses=1439, win%=0.473, money=9883

莊家, wins:5784, loses=5062, win%=0.533, money=50605

在四位玩家使用同樣的策略下注叫牌、沒耍任何花招的狀況下,四位玩家的勝率開始接近,輸的金額也慢慢浮現,這說明較大數量的玩牌,輸贏跟運氣的關係就降低了,莊家的優勢出現。

五萬次的結果

玩家:1號, wins:20939, loses=24369, win%=0.462, money=7036

玩家:2號, wins:20934, loses=24263, win%=0.463, money=7199

玩家:3號, wins:20910, loses=24324, win%=0.462, money=7092

玩家:4號, wins:20904, loses=24452, win%=0.461, money=6915

莊家, wins:97408, loses=83687, win%=0.538, money=61758

在四位玩家使用同樣的策略下注叫牌、沒耍任何花招的狀況下,四位玩家的勝率基本上是相同的,平均 46.2%,輸的金額的差異也不很大。這說明更大數量的玩牌,勝負機率回歸本質,玩家輸牌是「天注定」的…莊家則是擁有53.8%勝率,雙方勝率的差異達到 7.6%。

超過五萬次的結果,跟重覆跑五萬次的差異不很大。我們暫時用這個次數,做為分析的基準。

同樣的策略,玩家為什麼輸?

從流程我們可以很明顯地看出來,玩家在叫牌的時候,有一定的可能會「爆」,爆了就輸牌輸錢。即使後手的莊家也爆牌,這一局兩人的對決還是莊家勝。這是典型的「先手劣勢」,玩家不可不查也。

玩家的數量多寡是否對勝率造成差異?

我們把玩家的數目 num_players 調整成三和五,經過五萬次牌局的模擬,其結果和四位玩家的勝率狀況一樣。如果玩牌的局數不多,本身就有很強的運氣因素存在,那個不可控,我們先放一邊。

三玩家

玩家:1號, wins:20833, loses=24498, win%=0.460, money=6841

玩家:2號, wins:21008, loses=24401, win%=0.463, money=7075

玩家:3號, wins:20917, loses=24451, win%=0.461, money=6945

莊家, wins:73350, loses=62758, win%=0.539, money=59139

五玩家

玩家:1號, wins:20829, loses=24532, win%=0.459, money=6778

玩家:2號, wins:20853, loses=24299, win%=0.462, money=7009

玩家:3號, wins:21053, loses=24380, win%=0.463, money=7193

玩家:4號, wins:21098, loses=24152, win%=0.466, money=7400

玩家:5號, wins:20801, loses=24557, win%=0.459, money=6708

莊家, wins:121920, loses=104634, win%=0.538, money=64912

「先手劣勢」解法

既然玩家因為先手,有「爆」的機率導致劣勢,那我們叫牌策略就不應該跟莊家一樣。降低叫牌的門檻是否可以完全克服這個劣勢? 是的,驢子也是這樣想…我們來實際模擬:

我們讓四位玩家不約而同,把低於十七-相同於莊家的叫牌邏輯,改到十六點以下(不含十六)才叫牌,同樣下一美元一注,五萬次牌局:

玩家:1號, wins:21147, loses=24531, win%=0.463, money=6941

玩家:2號, wins:20774, loses=24827, win%=0.456, money=6307

玩家:3號, wins:20997, loses=24626, win%=0.460, money=6733

玩家:4號, wins:20907, loses=24626, win%=0.459, money=6603

莊家, wins:98610, loses=83825, win%=0.541, money=63416

低於十六叫牌,模擬出來的結果跟低於十七叫牌的差別不大,玩家的勝率差不多在 45.9%,莊家是 54.1%

低於十五叫牌,模擬出來的結果跟低於十七叫牌的差別不大,玩家的勝率差不多在 46.5%,莊家是 53.5%

低於十四叫牌,模擬出來的結果跟低於十七叫牌的差別不大,玩家的勝率差不多在 46.0%,莊家是 54.0%

低於十三叫牌,模擬出來的結果跟低於十七叫牌的差別不大,玩家的勝率差不多在 45.5%,莊家是 54.5%

低於十二叫牌,模擬出來的結果跟低於十七叫牌的差別不大,玩家的勝率差不多在 44.4%,莊家是 55.6%

低於十一叫牌,哪怕是驢子都會笑出來,咱們就不丟這個臉了…看出來了嗎,在一切不變的狀況下,改變策略低於十五叫牌,玩家的勝率雖然較高,但也遠遜於莊家,雙方勝率還是有 7.0% 的差距。如果我們分析資料,會看出雖然我們「爆」的機率降低,但點數不夠被莊家吃掉的機率提高了。所以,僅只是改變叫牌點數,並不能克服這個「先手劣勢」。

別擔心,還是有新的策略可以研究,讓我們繼續看下去。

有趣的統計學(1)

在完成數個月的訓練、成功解題完成專案之後。這些同仁們在自己的工作崗位,面對新的、類似的問題,就像換了一個人,把課堂所學的統計、實驗設計執行、甚至 minitab 的分析都丟在腦後,繼續用舊方法嘗試錯誤、浪費時間…

過去一年多以來,我的工作之一,是擔任公司 6 Sigma 黑帶大師。這個團隊主要在教導公司同仁如何用科學方法解決問題。我們一面開設 6 Sigma DMAIC 的課程,結合統計學、實驗設計、分析、minitab 的使用等…一面組織同仁形成專案小組,針對工廠實際面對的重大問題,輔導同仁實戰、解決問題。

另我十分驚訝的事實是,許多工作已有五年以上的研發、技術人員,對於如何做實驗、如何科學地分析實驗,得出結論(基本的模型)…了解十分有限。我詢問一位年資已經不短的同事,如果要開發一個新產品,可能的控制因子有十七個,那麼研發團隊要用什麼方法,把十七個因子的組合,做出一個客戶至少可以接受的產品? 那位同事緬腆並帶著神密的微笑說,G哥你不知道嗎,你們家附近有一間廟,十分靈驗…我不敢繼續往下問。不過,如果大部份的工程師,對於實驗設計的方法流程不清楚,主管也不要求,那麼做實驗基本上就淪為嘗試錯誤的吃時間、吃錢機器。

更另人難過的,在完成數個月的訓練、成功解題完成專案之後。這些同仁們在自己的工作崗位,面對新的、類似的問題,就像換了一個人,把課堂所學的統計、實驗設計執行、甚至 minitab 的分析都丟在腦後,繼續用舊方法嘗試錯誤、浪費時間…

在我們一再追問下,同事們反應,因為內心俱怕統計,所以即使知道使用科學方法是更有效率的解題方式,但真正對於使用 6 Sigma 和統計,內心還是十分抗拒。

有鑑於此,我思考用何種方式,讓統計變得更有趣、更生活化、更容易理解接受,進行在工作和生活中應用。接下來,我會做一些嘗試,把一些統計的觀念,透過例子和使用 python 程式的模擬和分析產生圖形,試著讓「數據說話」…如此一來,不單可以學習統計,也順變看一下程式如何寫。

我們如何開始呢? 不如從「有趣的例子」找起。

最近逛 Kindle 網路書店,也許是統計的書買比較多,Kindle 的 AI 推了一本「擊敗莊家-21點的有利策略」給我。這是由 Edward O. Thorp 所著「Beat the Dealer: A Winning Strategy for the Game of Twenty-One」的中文翻譯,讀起來十分地有趣。很棒的地方是很簡捷,前面兩章簡單地介紹了二十一點的規則,第三章開始就展開了基本策略。我一面讀這一本西元 1962 年出版的作品,一邊思考,也許我可以用 python 和統計來重新計算,作者給出的策略是否真的有用。當然,書中顯示的策略目前幾乎已經被賭場破解了,不過,這是一個十分有意思的題目,我可以用 Bayes 方法來計算一些可能性。

話不多說,我講一下這個程式的大致結構,有興趣的可以到 github 下載並測試。網址為:https://github.com/clin8870/playCards

整個模擬程式只有 350 行,扣掉一些物件的說明,應該很容易閱讀。如果你有 python 的環境,可以 pip install numpy, pandas, matplotlib, seaborn, jupyterlab 這些超級好用的模組,那麼本機就可以執行。如果不想麻煩建置本機的 python 環境,那麼推薦使用 google colab,直接可以連 github 的檔案(https://github.com/clin8870/playCards/blob/main/PlayCards.ipynb)執行看結果,省去諸多步驟。

程式一開始是建立一些模組的連結,咱們暫時不理它…這些模組的功能,後面用到時再慢慢說明。

第一個物件是 Player,建立一個玩家的基本資料,像賭本多少,下注金額的大小等等。下注和叫牌的邏輯都是最簡單的。未來如果我們的玩家有很厲害的算法的話,可以繼承這個基本物件做修改。

莊家我沒有用 dealer 這個字,因為「據說」大部份賭場都由機器來洗牌和發牌…莊家只是套用賭場的規則叫牌、輸錢時把錢賠給 Player,贏錢反之…在我的程式裏,我用 Bank,繼承 Player 物件,用 12 行程式碼就解決了。

然後就是撲克牌 Decker,也是一個很簡單的物件,定義了牌的點數、幾付牌的參數、洗牌的動作等等…含說明大約 50 行。

賭場 House 稍後複雜,因為要把這些玩家莊家撲克牌串在一起,然後每場牌局要紀錄下來以便我們事後分析。含說明 135 行。

因為只是自己測試研究,並不是商用的軟件,所以說明的部份比較簡陋…不過程式邏輯相當直覺,應該不難理解。

下一篇,我們就可以來解析,如何做到擊敗 21 點莊家…嗯…或是根本做不到…