第二波分析:德國是2018世界杯奪冠最大熱門? Python數據分析來揭開神秘面紗… (附源代碼)


2018年,世界杯小組賽已經在如火如荼的進行中。在上篇文章的基礎上【2018世界杯:用Python分析熱門奪冠球隊】,我們繼續分析世界杯32強的實力情況,以期能夠更進一步分析本次世界杯的奪冠熱門球隊。

三十年河東三十年河西,對於世界杯而言,這個時間可能4年就足夠。

前幾場爆冷,使得天台上已經擁擠不堪,跳水的股市更是讓天台一度混亂。

在文章開始之前,提醒大家:

賭球有風險,看球須盡興

本文的重點是通過分析32強之間的比賽,透過歷史數據來預測奪冠熱門球隊。

本次分析的數據來源於 Kaggle, 包含從 1872 年到今年的數據,包括世界杯比賽、世界杯預選賽、亞洲杯、歐洲杯、國家之間的友誼賽等比賽,一共大約 40000 場比賽的情況。

本次的環境為

  • window 7 系統
  • python 3.6
  • Jupyter Notebook
  • pandas version 0.22.0

先來看看數據的情況:

import pandas as pd
import matplotlib.pyplot as plt

%matplotlib inline
plt.style.use('ggplot')

# 解決matplotlib顯示中文問題
plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默認字體
plt.rcParams['axes.unicode_minus'] = False  # 解決保存圖像是負號'-'顯示為方塊的問題

df = pd.read_csv('results.csv')
df.head()

該數據集包含的數據列的信息如下:

  • 日期
  • 主隊名稱
  • 客隊名稱
  • 主隊進球數 (不含點球)
  • 客隊進球數 (不含點球)
  • 比賽的類型
  • 比賽所在城市
  • 比賽所在國家
  • 是否中立

結果如下:


1、 獲取所有世界杯比賽的數據(含預選賽)

創建一個新的列數據,包含獲勝隊伍的信息,以及獲取所有世界杯比賽的數據,包含預選賽。

mask = df['home_score'] - df['away_score']
df.loc[mask > 0, 'win_team'] = df.loc[mask > 0, 'home_team']
df.loc[mask < 0, 'win_team'] = df.loc[mask < 0, 'away_team']
df.loc[mask == 0, 'win_team'] = 'Draw'

df_FIFA_all = df[df['tournament'].str.contains('FIFA', regex=True)]

結果如下:


2、 世界杯戰績分析 (含預選賽)

從前文來看, 在世界杯歷史上,實力最強的5支球隊是 德國、阿根廷、巴西、法國、西班牙。

接下來,我們將比賽的范圍擴大至包含世界杯預選賽,通過5支球隊之間的比賽情況來進行分析。

team_top5 = ['Germany', 'Argentina', 'Brazil', 'France', 'Spain']
df_FIFA_top5 = df_FIFA_all[(df_FIFA_all['home_team'].isin(team_top5))&
                                        (df_FIFA_all['away_team'].isin(team_top5))]
df_FIFA_top5.shape

out:
(43, 10)

在世界杯歷史上,5支球隊在共有43場比賽相遇。

通過這43場比賽分析后,5支球隊的勝負場數排名如下:

s_FIFA_top5 = df_FIFA_top5.groupby('win_team')['win_team'].count()
s_FIFA_top5.drop('Draw', inplace=True)
s_FIFA_top5.sort_values(ascending=False, inplace=True)
s_FIFA_top5.plot(kind='bar', figsize=(10,6), title='Top Five in World Cup')

結果如下:


下面,着重來分析下這5支球隊,在世界杯上,兩兩對陣時的勝負情況。

首先自定義兩個函數,分別獲得兩支球隊獲勝場數情況以及自定義繪圖函數

# 自定義函數,返回兩支球隊獲勝場數情況
def team_vs(df,team_A,team_B):
    df_team_A_B = df[(df['home_team'].isin([team_A,team_B]))&
                                        (df['away_team'].isin([team_A,team_B]))]
    s_win_team = df_team_A_B.groupby('win_team')['win_team'].count()
    return s_win_team

# 如需獲取本文源代碼,請關注公眾號“Python數據之道”,
# 在公眾號后台回復 “code” ,謝謝大家支持。

# 自定義函數,兩支球隊在世界杯的對陣勝負情況制圖
def team_vs_plot(df,team_A,team_B,ax):
    s_win_FIFA = team_vs(df,team_A,team_B)
    title = team_A + ' vs ' +team_B
    s_win_FIFA.plot(kind='bar', ax =ax)
    ax.set_xlabel('')
    ax.set_title(title,fontdict={'fontsize':10})
    ax.set_xticklabels(s_win_FIFA.index, rotation=20)

基於上述函數,分析結果如下:

2.1 世界杯戰績:巴西 vs 其他4支球隊

f, axes = plt.subplots(figsize=(10,10), ncols=2, nrows=2)
ax1, ax2,ax3,ax4 = axes.ravel()
team_vs_plot(df_FIFA_all,'Brazil','Germany',ax=ax1)
team_vs_plot(df_FIFA_all,'Brazil','Argentina',ax=ax2)
team_vs_plot(df_FIFA_all,'Brazil','France',ax=ax3)
team_vs_plot(df_FIFA_all,'Brazil','Spain',ax=ax4)

# 如需獲取本文源代碼,請關注公眾號“Python數據之道”,
# 在公眾號后台回復 “code” ,謝謝大家支持。

# set main title of the figure
plt.suptitle('Brazil vs other Top 4 teams in World Cup', fontsize=14, fontweight='bold', x=0.5, y=0.94)
plt.show()

結果如下:


統計現象1:
在世界杯上的戰績,統計獲勝場數如下(不含平局):

巴西1:1德國,巴西6:3阿根廷,巴西1:2法國,巴西3:1西班牙

巴西隊,輸贏不好判斷……

2.2 世界杯戰績:德國 vs 其他3支球隊

代碼跟2.1部分是類似的,結果如下:


統計現象2:

在世界杯上的戰績,統計獲勝場數如下(不含平局):

德國4:1阿根廷,德國2:1法國,德國2:1西班牙

德國在這5支球隊里,獲勝的優勢相對比較明顯。

2.3 世界杯戰績:阿根廷 vs 其他2支球隊

代碼跟2.1部分是類似的,結果如下:


統計現象3:

在世界杯上的戰績,統計獲勝場數如下(不含平局):

阿根廷2:0法國,阿根廷1:0西班牙

但阿根廷不敵巴西和德國

2.4 世界杯戰績:西班牙 vs 法國


綜合小結論:

從歷屆世界杯上的表現情況來看,分析5強之間兩兩對陣后,發現德國隊的表現是最好的。其次巴西和阿根廷的表現也不錯。

考慮到,歷屆世界杯的數據,時間跨度很大,很多球隊其實已經發生了很大變化。

球隊真實的情況,可能選擇近幾年的比賽,以及包含不同級別的比賽,可能分析效果要更好些。

下面,重點來分析2014年以來包含所有比賽的情況。

3、2014年以來,所有比賽的戰績對比

首先,時間選擇2014年之后(含2014年),距離現在的時間比較近,相對來說,球隊人員的組成變化小一些。

當然,這里的時間選擇,對於結果是有影響的。 大家可以探討下這個因素帶來的影響。

3.1 2014年以來所有球隊所有比賽勝負情況概覽

df['date'] = pd.to_datetime(df['date'])
df['year'] = df['date'].dt.year
df_since_2014 = df[df['year']>=2014]
df_since_2014.shape

2014年以來,共有3600多場比賽。

針對3600多場比賽分析后,勝負場數情況如下:

s_all = df_since_2014.groupby('win_team')['win_team'].count()
s_all.drop('Draw', inplace=True)
s_all.sort_values(ascending=True, inplace=True)
s_all.tail(50).plot(kind='barh', figsize=(8,16), tick_label='',title='Top 50 in all tournament since 2014')

從上圖來看,2014年以來,墨西哥,法國,德國、葡萄牙、巴西、比利時、韓國和西班牙表現相對較好。

結果是不是跟想象中的有些差異?

6月17日的小組賽,德國不敵墨西哥,看來也不是全無理由的。

但是,本次我們主要還是要考慮32強之間的對陣,這樣更能反映現實情況。

3.2 2014年以來32強相互之間在所有比賽中的概覽情況

team_list = ['Russia', 'Germany', 'Brazil', 'Portugal', 'Argentina', 'Belgium', 'Poland', 'France',
             'Spain', 'Peru', 'Switzerland', 'England', 'Colombia', 'Mexico', 'Uruguay', 'Croatia',
            'Denmark', 'Iceland', 'Costa Rica', 'Sweden', 'Tunisia', 'Egypt', 'Senegal', 'Iran',
            'Serbia', 'Nigeria', 'Australia', 'Japan', 'Morocco', 'Panama', 'Korea Republic', 'Saudi Arabia']

df_top32 = df_since_2014[(df_since_2014['home_team'].isin(team_list))&(df_since_2014['away_team'].isin(team_list))]

s_top32 = df_top32.groupby('win_team')['win_team'].count()
s_top32.drop('Draw', inplace=True)
s_top32.sort_values(ascending=True, inplace=True)
s_top32.plot(kind='barh', figsize=(8,12), tick_label='',title='Top 32 in all tournament since 2014')
# plt.ylabel('')

從上圖來看,自2014年以來,巴西、法國、葡萄牙、阿根廷、墨西哥、比利時、德國、西班牙、英國為前9強

下面我們來分析top9之間的勝負情況。

team_top9 = [ 'Brazil', 'France', 'Portugal',
             'Argentina','Mexico','Belgium',
             'Germany','Spain','England']
df_top9 = df_since_2014[(df_since_2014['home_team'].isin(team_top9))&
                        (df_since_2014['away_team'].isin(team_top9))]
df_top9.shape

2014年以來,top 9 之間一共踢了44場比賽(包括友誼賽)。

總體來說,比賽的場數不是太多,基於這些數據來分析,可能對結果會有較大的影響。

九強排名如下:

s_top9 = df_top9.groupby('win_team')['win_team'].count()
s_top9.drop('Draw', inplace=True)
s_top9.sort_values(ascending=False, inplace=True)
s_top9.plot(kind='bar', figsize=(10,6), title='Top 9 in all tournament since 2014')

來查看下都統計了哪些類型的比賽

s_tournament = df_top9.groupby('tournament')['tournament'].count()
s_tournament_percentage = s_tournament/s_tournament.sum()
# s_tournament_percentage.sort_values(ascending=False, inplace=True)
s_tournament_percentage.tail(20).plot(kind='pie', figsize=(10,10), autopct='%.1f%%',
                           startangle=150, title='percentage of tournament', label='',
                                     labeldistance=1.25, pctdistance=1.08)

從上面來看,友誼賽占的比例較大。

考慮到友誼賽在有些情況下可能不能比較准確的反映出球隊的真實水平,且友誼賽站的場數比例較大,我們剔除友誼賽再來看看結果情況。

3.3 2014年以來32強剔除友誼賽后的勝負情況概覽

df_top9_no_friendly = df_top9[df_top9['tournament']!= 'Friendly']
df_top9_no_friendly.groupby('tournament')['tournament'].count()

out:
tournament
Confederations Cup              3
FIFA World Cup                  6
FIFA World Cup qualification    2
UEFA Euro                       2
Name: tournament, dtype: int64

剔除友誼賽后,比賽類型分布如下:


剔除友誼賽后,Top 9 的情況如下:


在概覽中可以看出,是否剔除友誼賽(Friendly),對排名還是有影響的。

另外,剔除友誼賽后,總的比賽場數更少了(只有13場),9強之間有些隊伍沒有比賽,或者沒有贏過,這個數據用來分析的作用更有限。

當然,在分析中 是否要剔除友誼賽,應該是值得商榷的。

3.4 九強兩兩對陣的勝負情況概覽

這里,我們后續分析采用包含友誼賽的數據,來分別分析9強之間兩兩對陣的情況,看看哪支球隊的勝率更高些。

首先自定義幾個函數,方便進行分析。

自定義獲取球隊某年至今獲勝比例函數

# 自定義獲取球隊某年至今獲勝比例函數
def probability(df,year,team_A,team_B):
    prob = []
    df_year = df[df['year']>= year]
    s = team_vs(df_year,team_A,team_B)
    s_team_A = 0 if s.get(team_A) is None else s.get(team_A)
    s_A_win = s_team_A/s.sum()
    s_team_B = 0 if s.get(team_B) is None else s.get(team_B)
    s_B_win = s_team_B/s.sum()
    s_draw = 1 - s_A_win - s_B_win
    prob.append(year)
    prob.append(s_A_win)
    prob.append(s_B_win)
    prob.append(s_draw)
    return prob

自定義獲取兩支球隊歷史獲勝情況對比函數

# 自定義獲取兩支球隊歷史獲勝情況對比函數
def his_team_data(df,year_start,year_end,team_A,team_B):
    row_team = []
# df_team = pd.DataFrame(columns=('year', 'team_A_win', 'team_B_win', 'draw'))
    for yr in list(range(year_start,year_end+1)):
        team_A_vs_team_B = probability(df,yr,team_A,team_B)
        row_team.append(team_A_vs_team_B)
    team_A_win = team_A + '_win_percentage'
    team_B_win = team_B + '_win_percentage'
    df_team = pd.DataFrame(row_team, columns=('year', team_A_win, team_B_win, 'draw_percentage'))
    return df_team

自定義兩支球隊歷史獲勝情況制圖函數

# 自定義兩支球隊歷史獲勝情況制圖函數
def team_plot(df,year_start,year_end,team_A,team_B,ax):
    team_A_vs_team_B = team_A + '_vs_' + team_B
    team_A_vs_team_B = his_team_data(df,year_start,year_end,team_A,team_B)
    title = team_A + ' vs ' + team_B
    columns = [team_A+'_win_percentage',team_B+'_win_percentage','draw_percentage']
    team_A_vs_team_B.set_index('year')[columns].plot(kind='line',figsize=(10,6), title=title,ax=ax)

這些函數有什么用呢,首先我們來分析下 巴西 vs 德國 的情況,如下:

team_A = 'Brazil'
team_B = 'Germany'

f, axes = plt.subplots(figsize=(6,12), ncols=1, nrows=2)
ax1, ax2 = axes.ravel()

team_plot(df,1930,2016,team_A,team_B,ax1)
ax1.set_xlabel('')
team_plot(df,2000,2016,team_A,team_B,ax2)
ax2.set_title('')

plt.show()

上述圖中,x軸代表的含義是從某年至今(數據集含有部分2018年的比賽數據),兩支球隊的勝負情況。
例如 2012對應的是 德國跟巴西從2012年至今,兩支球隊的勝負情況。

所以,時間越早,兩支球隊的比賽數量越多,數據曲線的波動可能要小些。但由於球隊的成員組成在不斷的變化,會導致越早的數據,其分析價值越弱。 因此,選擇合適的年份進行分析就顯得很重要。

有童鞋說,如果我要 同時分析德國對陣另外8支球隊呢?

這里,用上面的函數,也是很迅速的,代碼如下:

team_A = 'Germany'

for team in ['France','Portugal', 'Argentina','Mexico','Belgium','Brazil','Spain','England']:
    team_B = team

    f, axes = plt.subplots(figsize=(6,12), ncols=1, nrows=2)
    ax1, ax2 = axes.ravel()

    team_plot(df,1930,2016,team_A,team_B,ax1)
    ax1.set_xlabel('')
    team_plot(df,2000,2016,team_A,team_B,ax2)
    ax2.set_title('')

    plt.show()

運行上述代碼后,將會繪制8張圖,下面只放上其中幾張圖。

同理,如果你喜歡巴西隊或者別的球隊,也可以用上述代碼進行分析。



用上述函數可以快速的分析兩支球隊的歷史勝負情況,當然,有些球隊之間,相遇很少,或者近些年沒有遭遇過,那分析結果可能就不好用了。

當然,數據分析的只是歷史情況,足球是圓的,場上瞬息萬變。比如,阿根廷現在岌岌可危,梅西內心慌得一逼……

4 預測

本屆世界杯真的是爆冷太多:

  • 意大利,荷蘭,連小組賽都沒進;
  • 阿根廷,可以說現在已涼了半截;
  • 德國隊,若不是最后的絕殺,也差不過可以送首涼涼了,不過現在看已回血大半。

最后,來放上我的神預測。

黑馬年年有,今年特別多,預測不准,坐等 pia pia 打臉。




當然,其實我內心深處希望是下面這樣的。

怎么樣,為強大的內心點贊吧~~




特別說明: 以上數據分析,純屬個人學習用,預測結果與實際情況可能偏差很大,不能用於其他用途。

本文是一次比較綜合的項目實戰,希望可以給大家帶來一些啟發。如需獲取源代碼,請在微信公眾號【Python數據之道】后台回復“code”獲取。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM