今回はイロレーティングを使って
日本がW杯で優勝する確率を
シミュレーションしてみました


解説動画はこちら



さて、今回はワールドカップ2022目前ということで
イロレーティングを用いて結果がどうなるのか
シミュレーションしてみることとしました

イロレーティングというのは
対戦ゲームやスポーツに
良く用いられているもので
相対評価で実力を表すために
使われる指標の一つです

レーティングを使うと
対戦国同志の勝率を出すことができます

レーティングから勝率を求める計算式は
次のようになっており

download


対戦国AとBでの
勝つ確率を求める事ができます

レーティングが高い方が
勝つ確率が上がります

おおよそのレーティング差での
勝率は次のようになっています

レート差勝率
1051.44%
5057.15%
10064.01%
20075.97%
30084.9%
40090.91%
50094.68%



今回は2022出場国のレーティングを
掲載しているサイトがあったので
そちらのデータを使うこととします。


レーティングの元はこちら


・データ化

このリンクを元にデータ化します
data="""
グループA	カタール	50	1439.89
グループA	エクアドル	44	1464.39
グループA	セネガル	18	1584.38
グループA	オランダ	8	1694.51
グループB	イングランド	5	1728.47
グループB	イラン	20	1564.61
グループB	アメリカ	16	1627.48
グループB	ウェールズ	19	1569.82
グループC	アルゼンチン	3	1773.88
グループC	サウジアラビア	51	1437.78
グループC	メキシコ	13	1644.89
グループC	ポーランド	26	1548.59
グループD	フランス	4	1759.78
グループD	オーストラリア	38	1488.72
グループD	デンマーク	10	1666.57
グループD	チュニジア	30	1507.54
グループE	スペイン	7	1715.22
グループE	コスタリカ	31	1503.59
グループE	ドイツ	11	1650.21
グループE	日本	24	1559.54
グループF	ベルギー	2	1816.71
グループF	カナダ	41	1475
グループF	モロッコ	22	1563.5
グループF	クロアチア	12	1645.64
グループG	ブラジル	1	1841.3
グループG	セルビア	21	1563.62
グループG	スイス	15	1635.92
グループG	カメルーン	43	1471.44
グループH	ポルトガル	9	1676.56
グループH	ガーナ	61	1393
グループH	ウルグアイ	14	1638.71
グループH	韓国	28	1530.3
""".split('\n')

# テキストからデータ化
data2 = [ d.split('\t') for d in data[1:-1]]
data2 = [d[0:3] + [float(d[3])] for d in data2]

# 国別レーティングのデータ化
data3 = {d[1]:d[3] for d in data2}

レーティングから勝率を計算する
関数はこのようになります
# レーティングから勝率計算の関数
def win_rate(a,b):
    return 1/(10**((b-a)/400) +1)


・予選の予測


さてここからは予選結果を
予測していくこととしましょう

グループリーグは総当たりで
2位までが決勝に残る事ができます

本来は勝ち点による
引き分けや得点差を加味したものなのですが
今回はシンプルにグループリーグの
勝ち残りを選ぶという仕様で
勝ち負けだけで選びます

前提条件:勝ち負けのみ、引き分けなし


さっそくグループを作って
総当たりの組み合わせを見てみましょう

グループ4チームから
総当たりの組み合わせを作るには
itertoolsのcombinationsで出来ます


import itertools
import numpy as np

# グループ分け
groups = [data2[0+i*4 : 4+i*4] for i in range(8)]

# 1グループ選ぶ
group = groups[0]
group_name = group[0][0]

# 総当たり戦の組み合わせを作る
brute_forces = list(itertools.combinations([g[1] for g in group],2))
print(brute_forces)
[('カタール', 'エクアドル'), 
('カタール', 'セネガル'), 
('カタール', 'オランダ'), 
('エクアドル', 'セネガル'), 
('エクアドル', 'オランダ'), 
('セネガル', 'オランダ')]

あとはこのチーム同士のレーティングを取ってきて
勝率にあてはめて、勝敗を決めれば
予選の勝利数が計算できます

その上位2チームが残るという訳です
# リーグ戦の結果
league_result = {g[1]:0 for g in group}
for a,b in brute_forces:
    # 国のレーティングをデータから取る
    rating_a = data3[a]
    rating_b = data3[b]
    
    # レーティングから勝率計算
    rate = win_rate(rating_a,rating_b)

    # 勝率で勝者を選ぶ
    choice = np.random.choice([a,b], p=[rate , 1-rate])
    league_result[choice] +=1
    print(a,b,rate,choice)
    
print(league_result)

wins = sorted(league_result.items(),reverse=True,key=lambda x:x[1])[0:2]
print(group_name,wins)
{'カタール': 2, 'エクアドル': 1, 'セネガル': 2, 'オランダ': 1}
グループA [('カタール', 2), ('セネガル', 2)]

こんな感じで、予選を勝つチームが
計算できました

ここまでを関数化してしまいます
def choice_wins(a,b):
    rating_a = data3[a]
    rating_b = data3[b]
    rate = win_rate(rating_a,rating_b)
    return np.random.choice([a,b], p=[rate , 1-rate])

def choice_group_wins(group):
    brute_forces = list(itertools.combinations([g[1] for g in group],2))
    league_result = {g[1]:0 for g in group}
    for a,b in brute_forces:
        rating_a = data3[a]
        rating_b = data3[b]
        choice = choice_wins(a,b)
        league_result[choice] +=1
    return sorted(league_result.items(),reverse=True,key=lambda x:x[1])[0:2]

# 予選リーグの結果
league_results = []
for group in groups:
    wins = choice_group_wins(group)
    print(wins)
    league_results.append(wins)
[('カタール', 2), ('セネガル', 2)]
[('イングランド', 2), ('アメリカ', 2)]
[('アルゼンチン', 3), ('メキシコ', 2)]
[('デンマーク', 3), ('フランス', 2)]
[('スペイン', 3), ('日本', 2)]
[('ベルギー', 2), ('モロッコ', 2)]
[('ブラジル', 2), ('スイス', 2)]
[('韓国', 3), ('ポルトガル', 1)]


勝率から計算しているので
実行毎にランダムで結果が変わります
これで予選を勝ったチームが出来ました



・予選リーグの突破確率

予選リーグの計算を10000回試行して
日本が予選を突破できる確率を
求めてみましょう

グループEのレーティングは
次の様になっています


スペイン 1715.22
ドイツ 1650.21
日本    1559.54
コスタリカ 1503.59


日本の対戦国との勝率は
次のようになります
# 日本の対戦国との勝率
rate1 = win_rate(data3['日本'],data3['スペイン'])
rate2 = win_rate(data3['日本'],data3['ドイツ'])
rate3 = win_rate(data3['日本'],data3['コスタリカ'])

print('{0}戦の勝率 : {1:.03f}%'.format('スペイン_' , rate1*100))
print('{0}戦の勝率 : {1:.03f}%'.format('_ドイツ_' , rate2*100))
print('{0}戦の勝率 : {1:.03f}%'.format('コスタリカ' , rate3*100))
スペイン_戦の勝率 : 28.984%
_ドイツ_戦の勝率 : 37.240%
コスタリカ戦の勝率 : 57.983%


日本の予選リーグ突破は
次のコードで計算しています
# 予選突破回数
japan_results = {g[1]:0 for g in groups[4]}

for i in range(10000):
    wins = choice_group_wins(groups[4])
    japan_results[wins[0][0]]+=1
    japan_results[wins[1][0]]+=1

for k,v in sorted(japan_results.items(),reverse=True,key=lambda x:x[1]):
    print('レーティング : {0:.02f} 、突破回数 : {1:04} , {2}'.format(data3[k] , v , k))
レーティング : 1715.22 、突破回数 : 8267 , スペイン
レーティング : 1650.21 、突破回数 : 5877 , ドイツ
レーティング : 1503.59 、突破回数 : 3030 , コスタリカ
レーティング : 1559.54 、突破回数 : 2826 , 日本


毎回変わりますが
おおよそ30%ほどの確率で
予選突破できるのではないかと思われます




・決勝の計算

決勝の組み合わせは次のようになっていて
各グループの1位と2位が戦う仕組みです

download-1

これをプログラムに起こしていくと
次のようになります
def final_wins(league_results):
    # 決勝リーグ1回戦の組み合わせ
    final_stage_1_result = []
    for i in range(0,7,2):
        a1 = league_results[i][0][0]
        b2 = league_results[i+1][1][0]
        choice1= choice_wins(a1,b2)
        final_stage_1_result.append(choice1)

        a2 = league_results[i][1][0]
        b1 = league_results[i+1][0][0]
        choice2 = choice_wins(a2,b1)
        final_stage_1_result.append(choice2)

    # 準々決勝の組み合わせ
    quater_finals = []
    for i in [0,4]:
        a1 = final_stage_1_result[i]
        b2 = final_stage_1_result[i+2]
        choice1= choice_wins(a1,b2)
        quater_finals.append(choice1)

        a2 = final_stage_1_result[i+1]
        b1 = final_stage_1_result[i+3]
        choice2 = choice_wins(a2,b1)
        quater_finals.append(choice2)
        
    # 準決勝の組み合わせ
    semi_finals = []
    a1 = quater_finals[0]
    b2 = quater_finals[2]
    choice1= choice_wins(a1,b2)
    semi_finals.append(choice1)

    a2 = quater_finals[1]
    b1 = quater_finals[3]
    choice2 = choice_wins(a2,b1)
    semi_finals.append(choice2)
    
    # 決勝の組み合わせ
    a1 = semi_finals[0]
    b2 = semi_finals[1]
    return choice_wins(a1,b2)

これで優勝国が導き出されます

これを使って優勝確率を
計算していきましょう


・日本が優勝できる確率は?


ここまでを10000回試行して


final_calc = {k:0 for k in data3.keys()}
for i in range(10000):
    # 予選リーグの結果
    league_results = []
    for group in groups:
        wins = choice_group_wins(group)
        league_results.append(wins)
    # 優勝国
    winner = final_wins(league_results)    
    final_calc[winner] +=1

for k,v in sorted(final_calc.items(),reverse=True,key=lambda x:x[1]):
    print('レーティング : {0:.02f} 、優勝回数 : {1:04} , {2}'.format(data3[k] , v , k))


結果はプログラムを動かすか
動画をご覧ください


まあ、普通にレーティングが高い国が
優勝する確率も高い、という
当たり前の結果になります

今回はイロレーティングを用いて
W杯で優勝する確率を
求めてみました

それでは。