Powered by the Tomorrow.io Weather API
[ 프리미엄 ] 코딩과 관련한 컨텐츠 및 뉴스를 공유합니다.

※ 파이썬 | Javascript | 꿀팁

[2.0.2.3 계묘년 흑토끼] 대박나세요! 자세히보기

정보박사/스포츠

파이썬 예측해보는 2022 월드컵 카타르 우승 후보

잇잇쌤 2022. 11. 25. 09:16
728x90
반응형
SMALL

안녕하세요~

잇잇쌤입니다.

 

오늘은 친구들이 가장 관심있을만한 월드컵에 대해 우승후보를 한번 점쳐볼까 합니다.

 

바로 데이터 사이언스 에서 가장 쉽게 그리고 많이 활용되고 있는 파이썬 언어를 사용해서 말이죠.

 

1. 데이터 라이브러리

 

먼저, 파이썬 언어에 API 라이브러리를 추가합니다.

제가 사용한 데이터 세트는 앞으로 보게 될 경기와 국가대표팀이 조별 리그에서 이겼거나 통과한 횟수의 데이터 세트입니다.

이제 제가 탐험을 좀 해볼게요. 당연한 것부터 시작해서 각 팀이 이전에 월드컵에서 몇 번 우승했는지 살펴봅시다.

import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt 
import seaborn as sns
plt.style.use('ggplot')
plt.rcParams['font.family'] = 'sans-serif' 
plt.rcParams['font.serif'] = 'Ubuntu' 
plt.rcParams['font.monospace'] = 'Ubuntu Mono' 
plt.rcParams['font.size'] = 14 
plt.rcParams['axes.labelsize'] = 12 
plt.rcParams['axes.labelweight'] = 'bold' 
plt.rcParams['axes.titlesize'] = 12 
plt.rcParams['xtick.labelsize'] = 12 
plt.rcParams['ytick.labelsize'] = 12 
plt.rcParams['legend.fontsize'] = 12 
plt.rcParams['figure.titlesize'] = 12 
plt.rcParams['image.cmap'] = 'jet' 
plt.rcParams['image.interpolation'] = 'none' 
plt.rcParams['figure.figsize'] = (12, 10) 
plt.rcParams['axes.grid']=True
plt.rcParams['lines.linewidth'] = 2 
plt.rcParams['lines.markersize'] = 8
colors = ['xkcd:pale orange', 'xkcd:sea blue', 'xkcd:pale red', 'xkcd:sage green', 'xkcd:terra cotta', 'xkcd:dull purple', 'xkcd:teal', 'xkcd: goldenrod', 'xkcd:cadet blue',
'xkcd:scarlet']
 
Hosted on JovianView File

다음은 예측모델링을 해야겠죠. 바로 데이터를 기반으로요..

sns.countplot(data_winner.Winner) plt.grid(True) plt.ylabel('Number of World Cup won',fontsize=14) plt.xlabel('Country',fontsize=14)

 

우리도 이미 알고 있는 거죠? 브라질이 5승, 이탈리아가 4승, 아르헨티나가 2승을 거뒀다. (최근 사우디아라비에 완패.. 정말 AI는 AI일뿐 드라마가 현실로 일어나고 있습니다!)

우리가 탐구할 수 있는 또 다른 멋진 것은 경기 데이터 세트에서 우리는 토너먼트의 무대도 가지고 있다는 사실과 관련이 있다. 한 나라가 조별리그를 통과한 횟수는 분명히 그 팀의 자질을 나타내는 것이기 때문에 그것을 탐구하는 걸 한 번 봅시다.

 

그래서 조별리그 경기로 보았을때 어떻게 될것인지 예측해보겠습니다.

 

2. 확률 분포 모델링

 

이제 지루한 부분이 끝났으니, 이번 월드컵을 어떻게 시뮬레이션할 것인지에 대해 자세히 알아보도록 하자.

우리 팀과 그들의 경기가 있습니다. 1팀(T_1)과 2팀(T_2)이 있다고 하자. 1팀이 경기에서 이길 확률은 얼마나 되나요?

t는 T_2와 추첨에서 같다.

이제 무승부에 대해서: 물론 조별리그에서는 두 팀이 비길 수 있지만, 탈락 단계에서는 비길 수 없다. 제가 나중에 어떻게 대처해야 하는지 알려드릴게요. 😉

내가 전에 말했던 것과 비슷하게, 우리는 다음과 같이 T_1이 이길 확률을 찾을 수 있죠.

 

win_draw_lose = []
for i in range(len(data_matches)):
    home_team_goal = int(data_matches['Home Team Goals'].loc[i])
    away_team_goal = int(data_matches['Away Team Goals'].loc[i])
    if home_team_goal == away_team_goal:
        win_draw_lose.append('Draw')
    if home_team_goal>away_team_goal:
        win_draw_lose.append(data_matches['Home Team Name'].loc[i])
    if home_team_goal<away_team_goal:
        win_draw_lose.append(data_matches['Away Team Name'].loc[i])
data_matches['Result']=win_draw_lose

카타르 월드컵 팀을 리스트업 해볼게요~

qatar_team_list = ["Argentina",
"Australia",
"Belgium",
"Brazil" ,
"Cameroon", 
"Canada" ,
"Costa Rica", 
"Croatia" ,
"Denmark" ,
"Ecuador" ,
"England" ,
"France" ,
"Germany" ,
"Ghana" ,
"IR Iran",
"Japan" ,
"Korea Republic",
"Mexico",
"Morocco", 
"Netherlands",
"Poland",
"Portugal",
"Qatar",
"Saudi Arabia",
"Senegal",
"Serbia",
"Spain",
"Switzerland",
"Tunisia",
"Uruguay",
"USA",
"Wales"]

 

이제 우리가 가지고 있는 데이터를 팀 리스트와 일치시켜야 합니다. 우리는 데이터 세트에 카타르에 있을 모든 팀이 있는지 확인해야 합니다

 

team_list = list(set(data_matches['Home Team Name']))
for t in qatar_team_list:
    if t not in team_list:
        print('Houston, we have a problem with team %s'%(t))
qatar_probabilities = {'Win':0.20,'Draw':0.20,'Lose':0.60}

 

아이러니하게도 카타르는 우리의 데이터 세트에 없는 유일한 팀입니다. 이 문제는 나중에 해결합시다. 카타르가 월드컵에서 실제로 얼마나 많은 경기를 이길 수 있는지에 대한 일종의 꾸며낸 현실적인 확률인 카타르_확률 사전을 일단 추가해 봅시다.

이제 확률 변환을 수행하려면 다음 함수를 사용합니다.

 

def select_team_statistics(team):
    data_team = data_matches[(data_matches['Home Team Name']==team)| (data_matches['Away Team Name']==team)]
    winning_count = len(data_team[data_team['Result']==team])
    draw_count = len(data_team[data_team['Result']=='Draw'])
    lose_count = len(data_team)-winning_count-draw_count
    return data_team,{'Winning Count':winning_count,'Draw Count':draw_count,'Lose Count':lose_count}

다음과 같이 랜덤 결과를 표시합니다.

 

 

for i in range(1,5):
    plt.subplot(2,2,i)
    random_team = np.random.choice(qatar_team_list)
    plt.title('Stats for team = %s'%(random_team),fontweight='bold')
    team_data,stats = select_team_statistics(random_team)
    labels, values = stats.keys(),stats.values()
    plt.pie(values, labels = labels,colors=['navy','darkorange','firebrick'])

 

 

우리는 단일 팀만을 위한 것이 아니라 경기를 위한 확률을 할 필요가 있다. 우리는 위의 규칙을 다음과 같은 방법으로 적용하고 있습니다.

 

def select_match_statistics(team_A, team_B):
    data_team = data_matches[(data_matches['Home Team Name']==team_A)& (data_matches['Away Team Name']==team_B)]
    data_team = data_team.append(data_matches[(data_matches['Home Team Name']==team_B)& (data_matches['Away Team Name']==team_A)])
    len_data = len(data_team)
    if len_data==0:
        print('These teams never played against each other')
    else:
        print('These teams played against each other %i times'%(len_data))
    team_A_win = len(data_team[data_team.Result==team_A])
    team_B_win = len(data_team[data_team.Result==team_B])
    draw = len(data_team[data_team.Result=='Draw'])
    return data_team,{team_A:team_A_win,team_B:team_B_win,'Draw':draw}

이제 이 확률은 두 경기가 경기 기록이 있는 경우에만 적용됩니다. 예를 들어, 이것은 프랑스와 이탈리아에서 작동한다:

 

data_match,stats = select_match_statistics('France','Italy')

하지만 이 경우에 우리는 무엇을 해야 할까요?

 

data_match,stats = select_match_statistics('France','Qatar')

 

자, 이건 진짜 질문이에요. 한 번도 경기를 치른 적이 없는 두 팀의 결과를 자동으로 예측하기 어려워 답을 모르겠죠. 우리가 할 수 있는 것은 각 시간에 대한 점수를 만들고 두 점수를 비교하여 팀 1의 승리, 팀 2의 승리 또는 두 팀이 비기는 확률로 변환하는 것입니다.

한 팀에게 좋은 점수는 팀이 조별리그를 통과한 횟수(정상화)라고 생각해요. 물론 이는 팀의 자질을 보여주는 좋은 부분이에요. 우리는 그것을 1점이라고 부를 것이면. 고려해야 할 또 다른 중요한 것은 한 팀이 월드컵에서 실제로 우승한 횟수네요. 우리는 그것을 2점이라고 부를 것이죠. score_1은 0과 1 사이에 있고 score_2는 2, 3, 4일 수 있으므로 0.5를 곱하기로해요. 그래서 T팀이 주어지면, 우리는 다음의 공식이 나오죠.

 

따라서 T_x1과 T_x2의 두 팀이 있고 T_x1의 우승 확률을 P(T_x1, T_x2)로 정의하면 다음과 같이 말할 수 있어요.

그리고..

 

하지만 이 확률의 정의는 우리가 그리는 것을 허락하지 않아요. 그래서 우리는 차라리 한 번도 경기를 치른 적이 없는 두 팀 간의 무승부 확률이 고정되어 있다고 말해요. 0.10이라고 하자구요. 그러면 우리는 다음과 같이 확률이 나와요.

 

 

 

 

그리고 그들이 그릴 확률은 다음과 같죠:

 

1. 팀의 점수를 얻는 기능

def find_score(team):
    team_data, stats = select_team_statistics(team)
    team_stage = team_data['Stage'].reset_index().drop('index',axis=1)
    sum_groups = 0
    sum_finals = 0
    for s in range(len(team_stage)):
        stage_val = team_stage.loc[s].values[0].split(' ')
        if stage_val[0]=='Group':
            sum_groups = sum_groups + 1
        if stage_val[0]!='Group':
            sum_finals = sum_finals + 1
    
    score_1 = sum_finals/(sum_groups+sum_finals)
    try:
        score_2 = 0.5*data_winner.value_counts(subset='Winner')[team]
    except:
        score_2=0
    return score_1+score_2

2. 두 팀의 점수를 확률로 변환하는 기능

def find_score_two_teams(team_A,team_B):
    if team_A == 'Qatar':
        score_1 = 0.09
        score_2 = find_score(team_B)
    if team_B == 'Qatar':
        score_2 = 0.09
        score_1 = find_score(team_A)
    if team_A!='Qatar' and team_B!='Qatar':
        score_1 = find_score(team_A)
        score_2 = find_score(team_B)
    team_A_score = score_1/(score_1+score_2)
    team_B_score = score_2/(score_1+score_2)
    if team_A_score>team_B_score:
        team_A_score = min(0.90,team_A_score)
        team_B_score = max(0.10,team_B_score)
    else:
        team_B_score = min(0.90,team_B_score)
        team_A_score = max(0.10,team_A_score)
    team_A_score = team_A_score-0.05
    team_B_score = team_B_score-0.05
    res = {team_A: team_A_score, team_B:team_B_score, 'Draw':0.10}
    return res

*우리가 볼 수 있듯이 카타르의 점수는 0.09점이다. 나는 모든 점수 1 분포의 첫 번째 0.25 사분위수에서 그것을 얻었다. 이는 월드컵에 출전한 적이 없는 팀으로서는 합리적(낮은) 가치다.

3. 경기에서 두 팀 간의 결과 확률을 추출하는 기능*

 

 

*저는 또한 패배와 무승부에서 약간의 (작은) 확률을 추가함으로써 팀이 다른 팀과 이길 확률이 100%가 되지 않도록 했습니다.

 

3. 재미있어요!
이제 우리의 모델을 작동시킬 때입니다. 우리는 카타르 월드컵을 위해 정확한 그룹을 만들어야 한다. 우리는 이 그룹을 운영할 것이고, 팀은 우리가 구축한 확률에 따라 승패를 결정할 것이다.

알고리즘 탈락 단계(A조 1팀 vs B조 2팀, B조 1팀 vs A조 2팀)도 구축한다.

우리는 이 알고리즘을 여러 번 실행할 것이고, 우리는 승자를 고를 것이다.

제가 차근차근 해볼게요. 그룹을 정의합니다.

 

group_A = ['Qatar','Ecuador','Senegal','Netherlands']
group_B = ['England','IR Iran','USA','Wales']
group_C = ['Argentina','Saudi Arabia','Mexico','Poland']
group_D = ['France','Australia','Denmark','Tunisia']
group_E = ['Spain','Costa Rica','Germany','Japan']
group_F = ['Belgium','Canada','Morocco','Croatia']
group_G = ['Brazil','Serbia','Switzerland','Cameroon']
group_H = ['Portugal','Ghana','Uruguay','Korea Republic']
groups = [group_A,group_B,group_C,group_D,group_E,group_F,group_G,group_H]

예를 들어, 다음은 그룹 B의 확률이다.

group_name = group_B
for team_1 in group_name:
    for team_2 in group_name:
        if team_1!=team_2:
            _,stats = select_match_statistics(team_1,team_2)
            if sum(stats.values())==0:
                print(stats)
                print('How do we do that? :(')
            else:
                print(stats)

{'England': 0.85, 'IR Iran': 0.05, 'Draw': 0.1} {'England': 0.0, 'USA': 0.5, 'Draw': 0.5} {'England': 0.7480456026058632, 'Wales': 0.15195439739413685, 'Draw': 0.1} {'IR Iran': 0.05, 'England': 0.85, 'Draw': 0.1} {'IR Iran': 0.05, 'USA': 0.85, 'Draw': 0.1} {'IR Iran': 0.05, 'Wales': 0.85, 'Draw': 0.1} {'USA': 0.5, 'England': 0.0, 'Draw': 0.5} {'USA': 0.85, 'IR Iran': 0.05, 'Draw': 0.1} {'USA': 0.4905405405405406, 'Wales': 0.4094594594594595, 'Draw': 0.1} {'Wales': 0.15195439739413685, 'England': 0.7480456026058632, 'Draw': 0.1} {'Wales': 0.85, 'IR Iran': 0.05, 'Draw': 0.1} {'Wales': 0.4094594594594595, 'USA': 0.4905405405405406, 'Draw': 0.1}

 

 

이러한 확률에 따라 다음과 같은 방법으로 시뮬레이션을 실행할 수 있습니다. 이것은 주어진 그룹에 대한 것이다:

def run_group(group_name):
    data_res = pd.DataFrame(np.zeros(len(group_name)).T,index= group_name,columns=['Points'])
    for team_1 in group_name:
        for team_2 in group_name:
            if team_1!=team_2:
                _,stats = select_match_statistics(team_1,team_2)
                result = np.random.choice(list(stats.keys()),p=list(stats.values()))
                try:
                    data_res['Points'].loc[result]=data_res['Points'].loc[result]+3
                except:
                    data_res['Points'].loc[team_1]=data_res['Points'].loc[team_1]+1
                    data_res['Points'].loc[team_2]=data_res['Points'].loc[team_2]+1
    return data_res.sort_values(by='Points',ascending=False)

다음은 모든 그룹에 적용됩니다.

 

group_names = ['group A','group B','group C','group D','group E','group F','group G','group H']
def run_groups():
    group_list =[]
    for g in range(len(groups)):
        g_group = run_group(groups[g])
        g_group = g_group.rename(columns={'Points':'Points '+group_names[g]})
        group_list.append(g_group)
    return group_list

그룹에 대한 시뮬레이션을 실행해 보겠습니다.

 

roup_list = run_groups()

결과는...

stats = []
for i in range(10000):
    if (i%100)==0 and i>0:
        print('Running Simulation number %i' %(i))
    winner = whole_tournament()
    stats.append(winner)

한국은어디에!!ㅎㅎ

 

 

아무튼 이걸로 마치겠습니다.

 

해당 게시글의 출처는 2022 World Cup Simulator Using Data Science, with Python | by Piero Paialunga | Nov, 2022 | Towards Data Science

 

2022 World Cup Simulator Using Data Science, with Python

Here’s how I built a world cup Simulator and predicted the next World Cup winner

towardsdatascience.com

소스는 다음과 같습니다.

piero-paialunga/worldcupsimulator (v9) - Jovian

 

728x90
반응형

'정보박사 > 스포츠' 카테고리의 다른 글

바이아웃이란?  (0) 2022.12.28
Powered by the Tomorrow.io Weather API