Re: [討論] 對戰聯盟第一賽季積分討論
看板PokemonGO作者faradayslaw (仙人掌陰影下的寄居蟹)時間4年前 (2020/05/20 08:55)推噓67(67推 0噓 34→)留言101則, 58人參與討論串2/2 (看更多)
讀到原 PO 的計算,
讓我一鼓作氣把堆積許久遲遲未分析的 PVP 紀錄拿出來研究了 XD
以下我想先花點篇幅,用盡可能淺顯的方式解釋一下 Elo 計分系統的原理,
然後用我自己的對戰紀錄推估 pokemon go 天梯採用的參數。
看到數學會感到不適的人可以跳過前半篇。
------------------------------------------------
【Elo 計分簡介】
Elo 系統是一套在一對一競賽中,評估玩家實力的數學公式
每次實戰後,雙方的積分會因比賽結果而調整,
贏的上升,輸的扣分,但調分額度並不固定。
Elo 的思維是:
強者打敗弱者並不稀奇,因此高分玩家獲勝時,雙方都只調整少量分數。
反之,當低分玩家打贏高分玩家時,作為獎勵/懲罰,
前者的分數會大幅上升,而後者會大幅下降。
同理,雙方平手時,原先高分者降分,原低分者反之,因為前者本被期待獲勝。
那麼,這套原則要怎麼量化落實呢?
設想現在有兩名玩家 A、B,他們的賽前積分是 a 與 b。
Elo 把評分過程切成三個步驟。
第一步:用 a 與 b 的差值,估計兩人勝負的機率。
第二步:實戰。
第三步:依據實戰結果,調整兩人的積分,變為 a' 與 b'。
其中最複雜的是第一步。
下面我會詳細解釋。
------------------------------------------------
【賽前估計勝負機率】
如上所述,A、B 兩人的賽前積分是 a 與 b。
我們可以定義 10^(a-b) 為「A 打贏 B 的『不意外度』」。
什麼意思?
如果 A 比 B 強,那麼 a-b > 0,
也就是說 A 若獲勝那也不令人意外,所以「不意外度」就大於 1。
如果 A 比 B 強非常多,那麼「不意外度」就遠遠大於 1。
反之,如果 A 比 B 弱,那麼「不意外度」就在 0~1 之間
A 越弱,他要獲勝的「不意外度」就越接近零。
意思是如果他贏,那真是太令人意外了。
如果 A、B 兩人實力相仿,即 a=b,
則兩人獲勝誰都不奇怪,「不意外度」就等於 1。
為什麼要這樣定?
首先,這符合經驗。
強弱雙方的實力差距變為兩倍時,
弱者要打贏的機會並不是變成二分之一,而是更加艱難。
其次,它符合數學上的「遞移律」。
倘若有三個玩家 A、B、C,無論實力排序為何,
我們都可以發現「A 打贏 C 的不意外度」等於
「A 打贏 B 的不意外度」乘以「B 打贏 C 的不意外度」
這是基於指數函數的基本特性,
大家中學數學都學過,檢查一下即可知道這個特性確實存在。
同樣基於指數函數的基本特性,
「A 打贏 B 的不意外度」與「B 打贏 A 的不意外度」
兩者互為倒數,也就是相乘為 1。
這讓上述定義對 A、B 具有對稱性。
總之,這個定義在數學上蠻好的,該有的性質都有。
「不意外度」是一個從零到無限大之間的數字,而機率必然是個 0~1 之間的數字。
所以「不意外度」本身並不是機率,
幸好,它可以直接推算出 A、B 雙方獲勝的賽前預估機率:
A 獲勝的機率 = (A勝的不意外度) / (A勝的不意外度+B勝的不意外度)
B 獲勝的機率 = (B勝的不意外度) / (A勝的不意外度+B勝的不意外度)
我們把前面關於不意外度定義的式子放進來,就得到
A 獲勝的機率 = 10^(a-b) / ( 10^(a-b) + 10^(b-a) )
B 獲勝的機率 = 10^(b-a) / ( 10^(a-b) + 10^(b-a) )
整理一下,得到
A 獲勝的機率 = 10^(2*(a-b)) / ( 1 + 10^(2*(a-b)) )
B 獲勝的機率 = 10^(2*(b-a)) / ( 1 + 10^(2*(b-a)) )
其中數字 a 表示玩家 A 的實力(或賽前積分),數字 b 表示玩家 B 的積分。
如果我們把「A 的獲勝機率」對「實力差距 a-b」畫成圖,大概就長這樣:
https://imgur.com/w0w14dU
可以觀察到幾個現象:
一、這個圖形是旋轉對稱的,所以對玩家沒有偏袒
二、當雙方實力相同時(a=b),勝負機率各半(縱座標=0.5)
三、實力懸殊到一定程度時,強者幾乎確定獲勝
比方說 a-b=0.5 時,A 贏的機率就是 10/11 ,已經突破九成
這種形狀的函數長得像個左右拉長的字母 S,
所以俗稱 "S-shaped function"。
看到這詞大家就可以知道數學家取名字的創意大概到什麼程度。
在機率的課題中,S-shaped function 十分常見
有好幾種函數可以產生類似形狀
而 Elo 積分制度採用的這種「指數除以『指數加 1』」
正式的名稱叫做 "hyperbolic-tangent",通常寫作 tanh()
如果你有學過比高中數學再多一點的數學課,對這個函數應該不會太陌生。
好了,不管怎樣,我們現在可以掌握 A、B 兩人的賽前預估勝率了。
再寫一次:
A 獲勝的機率 = 10^(2*(a-b)) / ( 1 + 10^(2*(a-b)) )
B 獲勝的機率 = 10^(2*(b-a)) / ( 1 + 10^(2*(b-a)) )
廣義來說,其實我們未必要用 10 當指數的底。
你也可以用 2,或者用自然對數的底 e=2.7182818....,
或其他大於 1 的數字。隨你高興。
通常為了方便,我們希望競賽積分是整數,而且最好成千上萬,
這樣看起來才爽。畢竟大家都喜歡幻想自己很富有。
所以 a - b 動輒就是幾十幾百。
那為了讓指數函數不要爆炸大,
我們可以把上面的 10^(2*(a-b)) 通通修改成 10^( (a-b)/s )
其中 s 是一個幾十幾百的數字,它定義了積分的跨幅,
讓 (a-b)/s 落在零點多的範圍裡,不要動輒跳到上百。
或著可以用這句話概括:
「積分相差不大於 s 的兩名玩家,可以說他們實力差不多」
好了,不管怎樣,我們現在「真的」可以掌握 A、B 兩人的賽前預估勝率了。
再寫一次:
A 獲勝的機率 = 10^((a-b)/s) / ( 1 + 10^((a-b)/s) )
B 獲勝的機率 = 10^((b-a)/s) / ( 1 + 10^((b-a)/s) )
------------------------------------------------
【賽後調整積分】
前面說過,Elo 把評分過程切成三個步驟。
第一步:用 a 與 b 的差值,估計兩人勝負的機率。
第二步:實戰。
第三步:依據實戰結果,調整兩人的積分,變為 a' 與 b'。
我剛才用很長的篇幅完成了第一步。
第二步沒什麼好說的,就是對戰。
而對戰的結果,搭配上第一步的估算,現在要拿來第三步使用:積分調整。
以玩家 A 的視角來說吧。
比賽後,他的積分會從 a 調整為 a'。
如果 A 獲勝了,那麼
a' = a + k * ( 1 - 賽前估算A獲勝機率 )
如果 A 打輸了,那麼
a' = a + k * ( 0 - 賽前估算A獲勝機率 )
如果 A、B 雙方平手,那麼
a' = a + k * ( 0.5 - 賽前估算A獲勝機率 )
避免囉哩八唆,把三行合併成一行:
a' = a + k * ( A的輸贏結果 - 賽前估算A獲勝機率 )
可以看得出來,這套調分規則確實符合 Elo 希冀的原則:
如果你打贏比自己強的對手(a<b,即,賽前估算A獲勝機率 < 0.5)
那你應該加很多分。
如果你打贏比自己強的對手(a>b,即,賽前估算A獲勝機率 > 0.5)
那沒什麼,你本來就應該贏,所以你只會增加一點點分數。
此外,式子裡面有個參數 k,它代表調分的幅度。
如果 k 很大,玩家的積分就會隨著賽事歷程而顯著改動。
反之如果 k 很小,那麼爬分(或失分)就會很緩慢,或者說分數分布很穩定。
k 越大,這套評分系統就越刺激。
------------------------------------------------
一套 Elo 系統可以完全由三個參數描述:s, k,以及起始分數。
讀到這邊你應該可以注意到,我們剛才所有的運算都只跟 a-b 有關,
並不涉及 a 或 b 本身絕對的大小。
如果把所有玩家的積分同時提高 2000 分(或其他數字),
絲毫不影響評分的運作。
通常系統會給所有玩家一個很大的的起始分數,
目的是避免那些一直輸一直輸一直輸的玩家掉到負分,
因為掉到負分會讓玩家傷心挫折,
傷心挫折的玩家就會退坑,
太多人退坑遊戲公司就會減少營收。
畢竟就是因為現實世界令人傷心挫折我們才沈迷遊戲
如果遊戲也令人傷心那我們去玩其他比較溫馨的遊戲就好了。
總之讓人掉到負分,就營運上來講是絕對要避免的。
但就數學上來講,起始分數就只是個可有可無的平移常數而已。
那麼,pokemon go 天梯採用的 s 和 k 是多少?
這就是我後面要用實戰紀錄來回答的問題。
------------------------------------------------
【我的實戰紀錄】
我在第一賽季總共打了 277 輪,合計 1402 場。
1402 除以 277 稍微超過 5,因為技不如人,有時候連輸五場,
在 lose until you win 政策下要再打幾場才算完成一輪的關係。
下圖是我的積分歷史。
https://imgur.com/Xva9BSe
橫坐標是累計對戰場數,縱座標是積分(出水前不計)
我打了 89 輪(445 場)後登上 Rank 9,此後大部分時間都在 25XX 分浮沉掙扎
不過,我們要研究的不是積分本身,而是前後兩輪間的積分差。
把前後兩輪的積分相減,再刪去升上 R7 積分出水之前的資料後,
把「積分差」的分佈畫成直方圖:
https://imgur.com/eJklK5k
非常明顯地,這兩百多組「積分差」依照勝負場次數匯聚成六個叢集,
外加兩筆孤單的資料點——那是因為遇上了「雙方同時陣亡」的平手結果。
在每輪對戰結束、領獎勵的時候,平手跟打輸都一樣領不到。
但計算積分的時候,可以發現平手和打輸是有在區分的。
(參見上面關於 Elo 如何調分的算式)
複習一下 Elo 賽制調整積分的算式:
a' = a + k * ( A的輸贏結果 - 賽前估算A獲勝機率 )
理論上來說,叢集中軸與隔壁叢集中軸的間距,應該就等於 k,
從圖上看起來,k 大約在 18 左右。
但是用肉眼觀察實在不是很有說服力。
有沒有更可靠、更權威的驗證方式呢?
有。就是把「調分的理論值」與「調分的實際紀錄」畫成 X-Y 散布圖。
比方說吧,我在第 147 輪結束後,積分變為 2615。
在第 148 輪的第一場,我遇到積分 2578 的對手,我輸了。
在第 148 輪的第二場,我遇到積分 2609 的對手,我贏了。
在第 148 輪的第三場,我遇到積分 2625 的對手,我贏了。
在第 148 輪的第四場,我遇到積分 2626 的對手,我贏了。
在第 148 輪的第五場,我遇到積分 2630 的對手,我贏了。
在第 148 輪結束後,因為四勝一敗,我的積分上升為 2642。
實際調分 = 2642 - 2615 = 27
我可以去計算 a=2615, b=2578 等等的應調分數,
把這五個數字加起來,這就是「調分的理論值」。
當然,s 與 k 的數值是姑且先胡亂猜的。
怎麼樣才算猜得準呢?
就是要弄出一組(s,k)讓理論值接近 27,也就是實際值。
而且不只對這個數字準,對其於兩百多組都要準。
我可以把兩百多組數字畫在座標平面上,變成兩百多個點。
橫坐標(x)是「假定一組 s, k 之下的調分理論值」
縱坐標(y)是「調分實際值」
透過更改 s 與 k,我希望這些點全部乖乖躺在 y=x 的斜直線上。
我選了參數相近的九組(s = 300, 400, 500)x (k = 16, 18, 20)
作圖如下:
https://imgur.com/QjpywXL
稍微比較一下即可看出:
片面改變 s 時,這些點會以「叢集」為單位水平移動
s=300 太靠近,s=500 拉太遠,s=400 剛剛好
片面改變 k 時,這些點會在叢集內部小範圍水平移動,排成一列列短斜虛線
k=16 斜虛線太平緩,k=20 斜虛線太傾斜,k=18 剛剛好
把 s=400,k=18 那張放大:
https://imgur.com/yz4Eqsu
看起來沒有什麼系統性的誤差。
雖然有若干點稍微偏離 x=y 線,但大多只差 1,最多差到 2,平均偏離 0.6318。
我猜這些誤差是取整數的過程造成的。
因為積分會設計成整數,實質計算過程中有有很多不同的作法:
採用四捨五入?無條件捨去?無條件進位?絕對值四捨五入?
絕對值無條件捨去?絕對值無條件進位?五場結果加起來再取整數?
先個別取完五場整數再加起來?
我有點懶得一一嘗試上述做法了,反正抓到 s 跟 k 的參數就好,就沒再細細探究。
事實上 s=400,k=18 應該是最理想的整數結果了。
k=18.2 稍微比 k=18 更 fit 一點點,但 N 社應該不會用這種奇怪的參數。
所以我想,天梯用的 Elo 規則應該就這兩句話了:
面對積分比你低 x 的對手時,
你的預估獲勝機率 = 10^(x/400) / ( 1 + 10^(x/400) )
打完一輪後,你的分數調整額度等於
18 * ( 勝場數 + 0.5*平手場數 - 該輪每場「預估獲勝機率」的總和 )
------------------------------------------------
【補充】
我考慮過 N 社可能有兩種調分政策:
一、每打完一場就調整積分,但打完一整輪才顯示給玩家看
或
二、每打完一場先把調整額度賒起來,打完一整輪才實施
實際算出來的結果是(二)的可能性高得多。
檢驗過程蠻無聊的,這邊就不放細節了。
此外,我也做了 season 0 的分析。
當時要走很多路才能打 PVP,所以樣本不是很多
不過以分析來說足夠了。
當時的 s=600,而 k=9 只有 season 1 的一半
所以當時要靠致勝努力爬分是很沒效率的
而且配對系統在 2/16~2/17 時做了一次大調整。
在那之前你很容易配到跟你積分差距 150 分以上的對手
總之,從 season 0 到 season 1,
Niantic 對 PVP 的規則終究是有點改善啦。
不過,我私心很希望 N 社取消 lose until you win 政策
這讓我整理資料的時候多了很多麻煩。
還有在那之前,拜託,先把連線 bug 和三盾 bug 修好,可以嗎。
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 101.12.63.114 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/PokemonGO/M.1589936144.A.E5A.html
推
05/20 09:00,
4年前
, 1F
05/20 09:00, 1F
→
05/20 09:00,
4年前
, 2F
05/20 09:00, 2F
推
05/20 09:10,
4年前
, 3F
05/20 09:10, 3F
→
05/20 09:11,
4年前
, 4F
05/20 09:11, 4F
是的,正確名稱是叫 battle until you win。
我稱作 lose until you win 有點戲謔的意思,
因為一直打輸還不能乾脆了斷,感覺很恥辱......
推
05/20 09:26,
4年前
, 5F
05/20 09:26, 5F
推
05/20 09:31,
4年前
, 6F
05/20 09:31, 6F
→
05/20 09:37,
4年前
, 7F
05/20 09:37, 7F
→
05/20 09:38,
4年前
, 8F
05/20 09:38, 8F
啊對,你說的沒錯,正式名稱是 sigmoidal curve......
推
05/20 09:47,
4年前
, 9F
05/20 09:47, 9F
→
05/20 09:47,
4年前
, 10F
05/20 09:47, 10F
推
05/20 09:51,
4年前
, 11F
05/20 09:51, 11F
→
05/20 09:51,
4年前
, 12F
05/20 09:51, 12F
推
05/20 10:02,
4年前
, 13F
05/20 10:02, 13F
推
05/20 10:15,
4年前
, 14F
05/20 10:15, 14F
推
05/20 10:30,
4年前
, 15F
05/20 10:30, 15F
推
05/20 10:39,
4年前
, 16F
05/20 10:39, 16F
推
05/20 10:40,
4年前
, 17F
05/20 10:40, 17F
推
05/20 10:41,
4年前
, 18F
05/20 10:41, 18F
推
05/20 10:43,
4年前
, 19F
05/20 10:43, 19F
→
05/20 10:43,
4年前
, 20F
05/20 10:43, 20F
推
05/20 10:45,
4年前
, 21F
05/20 10:45, 21F
→
05/20 10:45,
4年前
, 22F
05/20 10:45, 22F
推
05/20 10:52,
4年前
, 23F
05/20 10:52, 23F
推
05/20 10:52,
4年前
, 24F
05/20 10:52, 24F
推
05/20 11:15,
4年前
, 25F
05/20 11:15, 25F
推
05/20 11:27,
4年前
, 26F
05/20 11:27, 26F
推
05/20 11:30,
4年前
, 27F
05/20 11:30, 27F
推
05/20 11:48,
4年前
, 28F
05/20 11:48, 28F
真的不是啦
推
05/20 11:54,
4年前
, 29F
05/20 11:54, 29F
→
05/20 11:55,
4年前
, 30F
05/20 11:55, 30F
呃,對,我跳了一步通分,結果指數的部分漏寫了。
獲勝機率應該是 10^(a-b) / ( 10^(a-b) + 10^(b-a) )
整理之後變成 10^(2*(a-b)) / ( 1 + 10^(2*(a-b)) )
之後再用任意參數 s 把那個 2 吸收掉
感謝提醒,趕快來修改內文 XD
推
05/20 11:58,
4年前
, 31F
05/20 11:58, 31F
→
05/20 11:58,
4年前
, 32F
05/20 11:58, 32F
推
05/20 12:01,
4年前
, 33F
05/20 12:01, 33F
→
05/20 12:01,
4年前
, 34F
05/20 12:01, 34F
→
05/20 12:01,
4年前
, 35F
05/20 12:01, 35F
還有 26 則推文
還有 3 段內文
推
05/20 15:39,
4年前
, 62F
05/20 15:39, 62F
推
05/20 16:11,
4年前
, 63F
05/20 16:11, 63F
推
05/20 16:38,
4年前
, 64F
05/20 16:38, 64F
推
05/20 16:40,
4年前
, 65F
05/20 16:40, 65F
推
05/20 16:45,
4年前
, 66F
05/20 16:45, 66F
推
05/20 17:10,
4年前
, 67F
05/20 17:10, 67F
推
05/20 17:19,
4年前
, 68F
05/20 17:19, 68F
推
05/20 17:42,
4年前
, 69F
05/20 17:42, 69F
→
05/20 18:53,
4年前
, 70F
05/20 18:53, 70F
→
05/20 18:54,
4年前
, 71F
05/20 18:54, 71F
推
05/20 19:06,
4年前
, 72F
05/20 19:06, 72F
→
05/20 19:06,
4年前
, 73F
05/20 19:06, 73F
→
05/20 19:06,
4年前
, 74F
05/20 19:06, 74F
推
05/20 19:30,
4年前
, 75F
05/20 19:30, 75F
推
05/20 20:23,
4年前
, 76F
05/20 20:23, 76F
推
05/20 20:30,
4年前
, 77F
05/20 20:30, 77F
→
05/20 20:30,
4年前
, 78F
05/20 20:30, 78F
推
05/20 22:23,
4年前
, 79F
05/20 22:23, 79F
→
05/20 22:23,
4年前
, 80F
05/20 22:23, 80F
推
05/20 23:03,
4年前
, 81F
05/20 23:03, 81F
→
05/20 23:03,
4年前
, 82F
05/20 23:03, 82F
推
05/20 23:09,
4年前
, 83F
05/20 23:09, 83F
推
05/20 23:42,
4年前
, 84F
05/20 23:42, 84F
推
05/21 00:41,
4年前
, 85F
05/21 00:41, 85F
推
05/21 00:49,
4年前
, 86F
05/21 00:49, 86F
推
05/21 00:59,
4年前
, 87F
05/21 00:59, 87F
推
05/21 01:20,
4年前
, 88F
05/21 01:20, 88F
→
05/21 03:30,
4年前
, 89F
05/21 03:30, 89F
→
05/21 03:30,
4年前
, 90F
05/21 03:30, 90F
→
05/21 03:30,
4年前
, 91F
05/21 03:30, 91F
推
05/21 09:16,
4年前
, 92F
05/21 09:16, 92F
推
05/21 09:22,
4年前
, 93F
05/21 09:22, 93F
→
05/21 11:00,
4年前
, 94F
05/21 11:00, 94F
推
05/21 20:06,
4年前
, 95F
05/21 20:06, 95F
→
05/21 20:06,
4年前
, 96F
05/21 20:06, 96F
→
05/21 20:07,
4年前
, 97F
05/21 20:07, 97F
推
05/22 11:28,
4年前
, 98F
05/22 11:28, 98F
→
05/22 11:28,
4年前
, 99F
05/22 11:28, 99F
→
05/22 11:39,
4年前
, 100F
05/22 11:39, 100F
推
05/23 02:10,
4年前
, 101F
05/23 02:10, 101F
討論串 (同標題文章)