如何用數據科學推演並組建2018世界盃球隊的最佳陣型?

如何用數據科學推演並組建2018世界盃球隊的最佳陣型?

來自專欄景略集智

隨著 2018 俄羅斯世界盃的腳步聲越來越近,想必很多球迷都按耐不住內心的激動了吧,預測帝也紛紛上線,憑著各種數據猜測:哪些球隊會挺到總決賽爭奪獎盃

而對球迷們來說,自己喜歡的球隊會怎麼組隊同樣是個津津樂道的話題:應當採用什麼陣型?該選擇哪些球員?誰該坐冷板凳誰該上場踢球?

作為一個狂熱的足球迷,我(作者 James Le——譯者注)就開始想了:能不能給世界盃參賽球隊中我喜歡的球隊推演出理想的陣型?恰好我本人是搞數據科學的,又從小到大喜歡玩《FIFA》,於是我意識到,其實我可以藉助 EA 出品的非常流行的足球模擬遊戲《FIFA18》,利用裡面的數據完成這項分析。

排兵布陣絕對能給玩家帶來極大的快感

在本文,我會帶你一步步了解我是如何為本屆世界盃 8 支最強參賽球隊組建理想陣型的,並在結尾給出會是哪兩支球隊爭奪冠軍的個人預測。這八支球隊分別是法國隊,德國隊,西班牙隊,英國隊,巴西隊,阿根廷隊,比利時隊葡萄牙隊

《FIFA18》數據集

我在 Kaggle 上獲取了《FIFA18》的數據集,包含了《FIFA18》中 17000+ 個球員,每個球員有 70 余個屬性。該數據集是從足球專業網站 soFIFA(sofifa.com/)上抓取得,提取的均是當前世界各足球俱樂部球員的真實個人數據。而且還有很多有意思的數據特徵,比如球員價值、薪水、年齡、排名等等,這些都是值得深挖的信息。

在載入數據後,我只選取了最有意思列進行分析:「名字」「年齡」「國籍」「整體得分」「潛力」「俱樂部」「價值」「薪水」「偏愛位置」

interesting_columns = [ Name, Age, Nationality, Overall, Potential, Club, Value, Wage, Preferred Positions]FIFA18 = pd.DataFrame(FIFA18, columns=interesting_columns)

這裡我們快速瀏覽一下數據集中整體得分最高的 5 名球員:

數據可視化

為了能讓你更好的理解數據集,我對球員的「年齡」「整體得分」「偏愛位置」「國籍」「價值」「薪水」做了一些可視化。我們分別看一下:

可以看到,大部分球員的年齡在 20 到 26 歲之間,25 歲的最多。

上圖顯示數據呈正態分布,平均整體得分為 66。

從上圖可以看到,球員們最偏愛的 4 個位置分別為:中後衛,前鋒,守門員中前衛

我用了程序包 plot.ly 繪製了球員國籍的地理可視化圖,可以看到球員大部分集中在歐洲國家,具體來說,英國、德國、西班牙法國最多。

而在球員價值這裡,我根據球員的年齡和整體得分製作了他們的價值的散點圖。從圖表上看,球員的價值似乎在 28-33 歲到達巔峰狀態,然後開始下降。球員的整體得分都在 90+。

在薪水方面,我同樣製作了一個散點圖。和球員的價值分布大致相同,在 30-33 歲期間,球員的價值會達到最高,然後下降

最佳陣容分析

好了,我們切入正題,探討為各個球隊組建最佳陣容。為了讓分析更簡單些,我只選取感興趣的數據:「球員」「年齡」「國籍」「整體得分」「潛力得分」「俱樂部」「位置」「價值」「薪水」

FIFA18 = FIFA18[[Name, Age, Nationality, Overall, Potential, Club, Position, Value, Wage]]FIFA18.head(10)

我寫了兩個很重要的函數:get_best_squad_n(根據球隊陣型和球員的國籍,函數會根據球員的整體得分返回配備了最佳球員的陣容以及球員的位置)和 get_summary_n(根據一列陣型選項和球員,函數會根據每個陣容中球員的平均整體得分對不同陣型進行比較)。

代碼1

def get_best_squad_n(formation, nationality, measurement = Overall): FIFA18_copy = FIFA18.copy() FIFA18_copy = FIFA18_copy[FIFA18_copy[Nationality] == nationality] store = [] for i in formation: store.append([ FIFA18_copy.loc[[FIFA18_copy[FIFA18_copy[Position].str.contains(i)][measurement].idxmax()]][Position].to_string(index = False), FIFA18_copy.loc[[FIFA18_copy[FIFA18_copy[Position].str.contains(i)][measurement].idxmax()]][Name].to_string(index = False), FIFA18_copy[FIFA18_copy[Position].str.contains(i)][measurement].max(), FIFA18_copy.loc[[FIFA18_copy[FIFA18_copy[Position].str.contains(i)][measurement].idxmax()]][Age].to_string(index = False), FIFA18_copy.loc[[FIFA18_copy[FIFA18_copy[Position].str.contains(i)][measurement].idxmax()]][Club].to_string(index = False), FIFA18_copy.loc[[FIFA18_copy[FIFA18_copy[Position].str.contains(i)][measurement].idxmax()]][Value].to_string(index = False), FIFA18_copy.loc[[FIFA18_copy[FIFA18_copy[Position].str.contains(i)][measurement].idxmax()]][Wage].to_string(index = False) ]) FIFA18_copy.drop(FIFA18_copy[FIFA18_copy[Position].str.contains(i)][measurement].idxmax(), inplace = True) return np.mean([x[2] for x in store]).round(2), pd.DataFrame(np.array(store).reshape(11,7), columns = [Position, Player, measurement, Age, Club, Value, Wage]).to_string(index = False)

代碼2

def get_summary_n(squad_list, squad_name, nationality_list): summary = [] for i in nationality_list: count = 0 for j in squad_list: # for overall rating O_temp_rating, _ = get_best_squad_n(formation = j, nationality = i, measurement = Overall) summary.append([i, squad_name[count], O_temp_rating.round(2)]) count += 1 return summary

我同時還讓陣容選擇更為嚴格些:

squad_343_strict = [GK, CB, CB, CB, RB|RWB, CM|CDM, CM|CDM, LB|LWB, RM|RW, ST|CF, LM|LW]squad_442_strict = [GK, RB|RWB, CB, CB, LB|LWB, RM, CM|CDM, CM|CAM, LM, ST|CF, ST|CF]squad_4312_strict = [GK, RB|RWB, CB, CB, LB|LWB, CM|CDM, CM|CAM|CDM, CM|CAM|CDM, CAM|CF, ST|CF, ST|CF]squad_433_strict = [GK, RB|RWB, CB, CB, LB|LWB, CM|CDM, CM|CAM|CDM, CM|CAM|CDM, RM|RW, ST|CF, LM|LW]squad_4231_strict = [GK, RB|RWB, CB, CB, LB|LWB, CM|CDM, CM|CDM, RM|RW, CAM, LM|LW, ST|CF]squad_list = [squad_343_strict, squad_442_strict, squad_4312_strict, squad_433_strict, squad_4231_strict]squad_name = [3-4-3, 4-4-2, 4-3-1-2, 4-3-3, 4-2-3-1]

1——法國隊

我們來探究一下法國隊的幾種不同的可能陣容,以及每種陣容對排名得分的影響。

France = pd.DataFrame(np.array(get_summary_n(squad_list, squad_name, [France])).reshape(-1,4), columns = [Nationality, Squad, Overall]) France.set_index(Nationality, inplace = True) France[Overall] = France[Overall].astype(float) print (France)

我們看看將最好的 11 名法國球員按 4-3-3 陣型組隊時的情況:

rating_433_FR_Overall, best_list_433_FR_Overall = get_best_squad_n(squad_433_strict, France, Overall)print(-Overall-)print(Average rating: {:.1f}.format(rating_433_FR_Overall))print(best_list_433_FR_Overall)

從數據上看,法國隊的整體排名得分為 84.6.

2——德國隊

作為上屆世界盃冠軍得主,德國隊肯定是今年世界盃的奪冠熱門。

Germany = pd.DataFrame(np.array(get_summary_n(squad_list, squad_name, [Germany])).reshape(-1,4), columns = [Nationality, Squad, Overall])Germany.set_index(Nationality, inplace = True)Germany[Overall] = Germany[Overall].astype(float)print (Germany)

可以看到,不管是 3-4-3 陣型還是 4-3-3 陣型,德國隊的當前排名得分都非常高。如果是我,我會選擇 4-3-3 陣型。

rating_433_GER_Overall, best_list_433_GER_Overall = get_best_squad_n(squad_433_strict, Germany, Overall)print(-Overall-)print(Average rating: {:.1f}.format(rating_433_GER_Overall))print(best_list_433_GER_Overall)

從數據上看,德國隊的整體排名得分為 86.3.

3——西班牙

那麼 2010 年世界盃冠軍西班牙隊呢?

Spain = pd.DataFrame(np.array(get_summary_n(squad_list, squad_name, [Spain])).reshape(-1,4), columns = [Nationality, Squad, Overall])Spain.set_index(Nationality, inplace = True)Spain[Overall] = Spain[Overall].astype(float)print (Spain)

和德國隊一樣,不管是 4-3-4 陣型還是 4-2-3-1 陣型,西班牙隊排名得分都很高。我會選擇 4--2-3-1 陣型。

rating_4231_ESP_Overall, best_list_4231_ESP_Overall = get_best_squad_n(squad_4231_strict, Spain, Overall)print(-Overall-)print(Average rating: {:.1f}.format(rating_4231_ESP_Overall))print(best_list_4231_ESP_Overall)

從數據上看,西班牙隊的整體排名得分為 86.6.

4——英國隊

雖然坐擁歐洲最好的足球協會,英國足球隊在國家隊層面上似乎做得並不好。我們看看在世界盃的陣型有哪些選擇:

England = pd.DataFrame(np.array(get_summary_n(squad_list, squad_name, [England])).reshape(-1,4), columns = [Nationality, Squad, Overall])England.set_index(Nationality, inplace = True)England[Overall] = England[Overall].astype(float)print (England)

看來英國隊還是應採取 4-3-3 陣型。

rating_433_ENG_Overall, best_list_433_ENG_Overall = get_best_squad_n(squad_433_strict, England, Overall) print(-Overall-) print(Average rating: {:.1f}.format(rating_433_ENG_Overall)) print(best_list_433_ENG_Overall)

從數據上看,英國隊的整體排名得分為 82.7.

5——巴西隊

歷史上巴西隊贏得世界盃冠軍的次數最多,「桑巴軍團」的實力不是蓋的,毫無疑問也是本屆世界盃奪冠的熱門球隊。

Brazil = pd.DataFrame(np.array(get_summary_n(squad_list, squad_name, [Brazil])).reshape(-1,4), columns = [Nationality, Squad, Overall])Brazil.set_index(Nationality, inplace = True)Brazil[Overall] = Brazil[Overall].astype(float)print (Brazil)

我們可以看到,巴西隊和英國隊的陣型選擇相同,還是 4-3-3 陣型。

rating_433_BRA_Overall, best_list_433_BRA_Overall = get_best_squad_n(squad_433_strict, Brazil, Overall)print(-Overall-)print(Average rating: {:.1f}.format(rating_433_BRA_Overall))print(best_list_433_BRA_Overall)

從數據上看,巴西隊的整體排名得分為 85.5.

6——阿根廷隊

作為阿根廷最著名的球員,梅西仍在等候阿根廷隊吹響衝擊冠軍的號角,完成他為阿根廷奪冠的未競夢想。4年前的最終決戰中敗北的他,今年能否帶領阿根廷隊再次來到奪冠的總決賽?

Argentina = pd.DataFrame(np.array(get_summary_n(squad_list, squad_name, [Argentina])).reshape(-1,4), columns = [Nationality, Squad, Overall])Argentina.set_index(Nationality, inplace = True)Argentina[Overall] = Argentina[Overall].astype(float)print (Argentina)

對於阿根廷球員來說,3-4-3 和 4-3-3 陣型都是非常好的選擇,我選擇 3-4-3 陣型。

rating_343_ARG_Overall, best_list_343_ARG_Overall = get_best_squad_n(squad_343_strict, Argentina, Overall)print(-Overall-)print(Average rating: {:.1f}.format(rating_343_ARG_Overall))print(best_list_343_ARG_Overall)

從數據上看,阿根廷隊的整體排名得分為 84.3.

7——比利時隊

雖然是歐洲小國,但比利時足球人才輩出,有不殺頂級球員在曼聯和切爾西效力,而且是英超最好的球員。不過和英國隊很像,在國家隊層面上,比利時隊同樣並不出色。埃登·阿扎爾和德布勞內這次能幫比利時隊走的更遠嗎?

Belgium = pd.DataFrame(np.array(get_summary_n(squad_list, squad_name, [Belgium])).reshape(-1,4), columns = [Nationality, Squad, Overall])Belgium.set_index(Nationality, inplace = True)Belgium[Overall] = Belgium[Overall].astype(float)print (Belgium)

同樣,比利時隊的最佳陣型為 4-3-3.

rating_433_BEL_Overall, best_list_433_BEL_Overall = get_best_squad_n(squad_433_strict, Belgium, Overall)print(-Overall-)print(Average rating: {:.1f}.format(rating_433_BEL_Overall))print(best_list_433_BEL_Overall)

從數據上看,比利時隊的整體排名得分為 84.3.

8——葡萄牙隊

最後一隊葡萄牙隊,實力不容小覷。葡萄牙隊不僅是 2016 歐洲杯冠軍,而且還擁有 3 次獲得歐冠年度最佳球員的 C 羅。

Portugal = pd.DataFrame(np.array(get_summary_n(squad_list, squad_name, [Portugal])).reshape(-1,4), columns = [Nationality, Squad, Overall])Portugal.set_index(Nationality, inplace = True)Portugal[Overall] = Portugal[Overall].astype(float)print (Portugal)

對於葡萄牙隊,我認為最佳陣型為 4-2-3-1.

rating_4231_POR_Overall, best_list_4231_POR_Overall = get_best_squad_n(squad_4231_strict, Portugal, Overall)print(-Overall-)print(Average rating: {:.1f}.format(rating_4231_POR_Overall))print(best_list_4231_POR_Overall)

從數據上看,葡萄牙隊的整體排名得分為 83.5.

最終比較

Ok,最後我們根據目前的球員排名和個人數據,對追逐 2018 世界盃冠軍的這 8 支最強出線球隊做個比較。

那麼通過對《 FIFA18 》中的數據進行分析:

  • 西班牙隊的平均整體得分最高,其次為德國隊和巴西隊。
  • 德國隊的整體球員價值最高,其次為西班牙隊和法國隊。
  • 西班牙隊的球員平均薪水最高,其次為德國隊和巴西隊。

因此,就我個人而言,我認為最終會是西班牙隊和德國隊爭奪冠軍,巴西隊和法國隊爭奪季軍。你對本屆世界盃的奪冠球隊有什麼看法?歡迎在評論區分享你的觀點。

本項目代碼請參見我的GitHub庫:

github.com/khanhnamle19


參考資料:

towardsdatascience.com/


推薦閱讀:

梅西接班人索千萬年薪遭拒,然後讓皇馬尤文大巴黎都頭疼
哈維·阿隆索為何不與皇馬續約?他接下來有可能去哪支球隊?
多特蒙德為什麼在大賽決賽前宣布自己的當家球星轉會死敵拜仁?
黃健翔,張璐,詹俊這樣的足球解說員如果去做教練會取得成功嗎?
點球大戰中,什麼影響了守門員的撲球方向?

TAG:世界盃WorldCup | 足球 | 集智sjizhiim |