<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          太酷了,用Python制作足球可視化圖表!

          共 12865字,需瀏覽 26分鐘

           ·

          2021-09-30 14:50

          本期和大家分享一下,用Python和Matplotlib繪制一個足球運動員的數(shù)據(jù)可視化圖表。


          來看一下C羅的情況,跟老詹一樣高齡,真的佩服。



          數(shù)據(jù)來源于下面兩個網(wǎng)站,Understat和Fbref。



          鏈接:https://understat.com/

          鏈接:https://fbref.com/en/


          歐洲足球五大聯(lián)賽,英超、意甲、西甲、德甲、法甲。


          先看一下射門數(shù)據(jù)的可視化,本質(zhì)上和籃球的出手點圖差不多,都是散點圖類型。


          導入相關(guān)的Python庫。


          import requests
          from bs4 import BeautifulSoup as soup
          import json
          import pandas as pd
          import matplotlib.pyplot as plt
          import numpy as np
          import matplotlib as mpl


          從Understat網(wǎng)站爬取射門數(shù)據(jù),使用BeautifulSoup、JSON和pandas解析和處理數(shù)據(jù)。


          # 請求數(shù)據(jù), C羅的ID為2371
          url = 'https://understat.com/player/2371'
          html = requests.get(url)

          # 解析處理數(shù)據(jù)
          parse_soup = soup(html.content, 'lxml')
          scripts = parse_soup.find_all('script')
          strings = scripts[3].string

          ind_start = strings.index("('")+2
          ind_end = strings.index("')")
          json_data = strings[ind_start:ind_end]
          json_data = json_data.encode('utf8').decode('unicode_escape')
          data = json.loads(json_data)
          print(data)
          # 處理數(shù)據(jù), 包含射門位置、預期進球、射門結(jié)果、賽季
          x = []
          y = []
          xg = []
          result = []
          season = []
          for i, _ in enumerate(data):
              for key in data[i]:
                  if key == 'X':
                      x.append(data[i][key])
                  if key == 'Y':
                      y.append(data[i][key])
                  if key == 'xG':
                      xg.append(data[i][key])
                  if key == 'result':
                      result.append(data[i][key])
                  if key == 'season':
                      season.append(data[i][key])
          columns = ['X''Y''xG''Result''Season']
          df_understat = pd.DataFrame([x, y, xg, result, season], index=columns)
          df_understat = df_understat.T
          df_understat = df_understat.apply(pd.to_numeric, errors='ignore')
          # 得到最終的結(jié)果
          print(df_understat)


          此處的ID,通過查詢球員名字可知



          查詢中國球員武磊,點擊訪問,在地址欄處,可以看到球員ID。


          得到數(shù)據(jù)如下。



          包含射門位置(x、y)、xG(預期進球)、射門結(jié)果、賽季。


          其中x、y的坐標值為0~1之間,不適合在Matplotlib顯示,所以選擇放大100倍。


          df_understat['X'] = df_understat['X'].apply(lambda x: x*100)
          df_understat['Y'] = df_understat['Y'].apply(lambda x: x*100)
          print(df_understat)


          得到結(jié)果如下。



          既然已經(jīng)成功獲取Understat網(wǎng)站的數(shù)據(jù),就可以去獲取Fbref網(wǎng)站的數(shù)據(jù)啦。


          這里是球員的一些個人信息,以及賽季的平均數(shù)據(jù)。



          比如全名、國家、位置、俱樂部、聯(lián)賽、年齡、出生年份、上場時間、得分數(shù)據(jù)等等。


          因為網(wǎng)頁的數(shù)據(jù)是表格形式,所以直接使用pandas的read_html函數(shù),解析表格爬取數(shù)據(jù)。


          這個網(wǎng)站需要取消一下證書驗證,要不然連接不成功。


          # 全局取消證書驗證

          import ssl
          ssl._create_default_https_context = ssl._create_unverified_context


          獲取球員的相關(guān)數(shù)據(jù)。


          def readfromhtml(filepath):
              # 選擇第二個表格
              df = pd.read_html(filepath)[0]
              column_lst = list(df.columns)
              for index in range(len(column_lst)):
                  column_lst[index] = column_lst[index][1]
              df.columns = column_lst
              df.drop(df[df['Player'] == 'Player'].index, inplace=True)
              df = df.fillna('0')
              df.set_index('Rk', drop=True, inplace=True)
              try:
                  df['Comp'] = df['Comp'].apply(lambda x: ' '.join(x.split()[1:]))
                  df['Nation'] = df['Nation'].astype(str)
                  df['Nation'] = df['Nation'].apply(lambda x: x.split()[-1])
              except:
                  print('Error in uploading file:' + filepath)
              finally:
                  df = df.apply(pd.to_numeric, errors='ignore')
                  return df


          # 獲取2020-2021歐洲五大聯(lián)賽球員數(shù)據(jù)
          df_fbref = readfromhtml('https://fbref.com/en/comps/Big5/shooting/players/Big-5-European-Leagues-Stats')
          print(df_fbref)


          得到結(jié)果如下。



          數(shù)據(jù)都已經(jīng)準備好了,那么我們就可以將數(shù)據(jù)繪制到圖表上。


          # 安裝
          pip install -i https://pypi.tuna.tsinghua.edu.cn/simple mplsoccer
          pip install -i https://pypi.tuna.tsinghua.edu.cn/simple highlight_text


          裝mplsoccer、highlight_text這兩個Python庫



          其中mplsoccer庫可以自定義繪制足球場,無需我們自己繪制場地圖。


          想了解更多,可以訪問它的GitHub地址。


          https://github.com/andrewRowlinson/mplsoccer



          初始化一些設置,畫布背景色、字體顏色、默認字體,字體大小,此處選擇中文字體。


          from highlight_text import ax_text,fig_text
          import mplsoccer

          # 背景色
          background = '#D6DBD9'
          # 字體顏色
          text_color = 'black'
          mpl.rcParams['xtick.color'] = text_color
          mpl.rcParams['ytick.color'] = text_color
          mpl.rcParams['text.color'] = text_color
          # 中文字體
          mpl.rcParams['font.family'] = 'Songti SC'
          mpl.rcParams['legend.fontsize'] = 12


          新建一個畫布。


          # 新建畫布
          fig, ax = plt.subplots(figsize=(108))
          # 關(guān)閉坐標軸
          ax.axis('off')
          # 背景色填充
          fig.set_facecolor(background)
          plt.show()


          顯示如下。



          繪制19-20賽季,C羅的進球情況。


          # 垂直方向半個足球場
          pitch = mplsoccer.VerticalPitch(half=True, pitch_type='opta', line_zorder=3, pitch_color='grass')
          # 圖表大小
          ax_opta1 = fig.add_axes((0.050.060.450.4))
          ax_opta1.patch.set_facecolor(background)
          pitch.draw(ax=ax_opta1)
          plt.show()


          通過設置mplsoccer的參數(shù),繪制半個足球場。



          果然,左下方有半個足球場。


          將射門數(shù)據(jù)用散點圖表示,分為進球得分和未成功進球得分兩種情況。


          # 2019-2020賽季, C羅射門位置散點圖(未得分), 透明度0.6
          df_fil = df_understat.loc[df_understat['Season'] == 2019]

          pitch.scatter(df_fil[df_fil['Result'] != 'Goal']['X'], df_fil[df_fil['Result'] != 'Goal']['Y'],
                        s=np.sqrt(df_fil[df_fil['Result'] != 'Goal']['xG'])*100, marker='o', alpha=0.6,
                        edgecolor='black', facecolor='grey', ax=ax_opta1)
          plt.show()


          未得分射門散點圖。



          得分散點圖。


          # 2019-2020賽季, C羅射門位置散點圖(得分), 透明度0.9
          pitch.scatter(df_fil[df_fil['Result'] == 'Goal']['X'], df_fil[df_fil['Result'] == 'Goal']['Y'],
                        s=np.sqrt(df_fil[df_fil['Result'] == 'Goal']['xG'])*100, marker='o', alpha=0.9,
                        edgecolor='black', facecolor='#6778d0', ax=ax_opta1, label='Goal')

          plt.show()


          結(jié)果如下,失敗的比成功的多。



          這樣,我們就將C羅在2019-2020賽季的所有射門點數(shù)據(jù)可視化出來了。


          其中散點的大小,是預期進球的大小。


          添加標簽及圖例,設置相應的位置、文字、字體等設置。


          # 添加圖例
          ax_opta1.legend(loc='lower right').get_texts()[0].set_color("black")

          # 文字信息
          ax_opta1.text(3061'得分次數(shù) : '+str(len(df_fil[df_fil['Result'] == 'Goal'])), weight='bold', size=11)
          ax_opta1.text(3064f"預期進球 : {round(sum(df_fil['xG']),2)}", weight='bold', size=11)
          ax_opta1.text(3058'射門次數(shù) : '+str(len(df_fil)), weight='bold', size=11)
          ax_opta1.text(9060'2019-20賽季', weight='bold', size=14)

          plt.show()


          成功添加附加信息。



          顯示賽季、xG、得分次數(shù)、射門次數(shù)信息。


          同樣將20-21賽季的數(shù)據(jù)繪制出來,放置在19-20賽季的右側(cè)。


          # 2020-2021賽季, C羅射門位置散點圖
          ax_opta2 = fig.add_axes((0.500.060.450.4))
          ax_opta2.patch.set_facecolor(background)
          pitch.draw(ax=ax_opta2)

          # 根據(jù)條件, 篩選數(shù)據(jù)
          df_fil = df_understat.loc[df_understat['Season'] == 2020]
          # 未得分
          pitch.scatter(df_fil[df_fil['Result'] != 'Goal']['X'], df_fil[df_fil['Result'] != 'Goal']['Y'],
                        s=np.sqrt(df_fil[df_fil['Result']!='Goal']['xG'])*100, marker='o', alpha=0.6,
                        edgecolor='black', facecolor='grey', ax=ax_opta2)
          # 得分
          pitch.scatter(df_fil[df_fil['Result']=='Goal']['X'], df_fil[df_fil['Result'] == 'Goal']['Y'],
                        s=np.sqrt(df_fil[df_fil['Result'] == 'Goal']['xG'])*100, marker='o', alpha=0.9,
                        edgecolor='black', facecolor='#6778d0', ax=ax_opta2, label='Goal')

          # 添加圖例, 文字信息
          ax_opta2.legend(loc='lower right').get_texts()[0].set_color("black")

          ax_opta2.text(3061'得分次數(shù) : '+str(len(df_fil[df_fil['Result'] == 'Goal'])), weight='bold', size=11)
          ax_opta2.text(3064f"預期進球 : {round(sum(df_fil['xG']),2)}", weight='bold', size=11)
          ax_opta2.text(3058'射門次數(shù) : '+str(len(df_fil)), weight='bold', size=11)
          ax_opta2.text(9060'2020-21賽季', weight='bold', size=14)

          plt.show()


          結(jié)果如下。



          C羅老當益壯啊,狀態(tài)一點也沒有下滑。


          下面接著繪制所有球員的數(shù)據(jù)散點圖,看看C羅的數(shù)據(jù)能在哪一檔?


          # 初始化
          ax_scatter = fig.add_axes([0.520.570.40.35])
          ax_scatter.patch.set_facecolor(background)
          plt.show()


          創(chuàng)建一個坐標軸。



          首先對數(shù)據(jù)進行篩選,上場時間最少要有900s,而且位置為前鋒此類的。


          畢竟我們不能拿個守門員,跟C羅比數(shù)據(jù)吧,參考意義不大。


          # 得到散點圖的X, Y坐標值
          no_90s = 10
          df_fil = df_fbref[df_fbref['90s'] >= no_90s]
          # 前鋒位置
          df_fil = df_fil[df_fil['Pos'].apply(lambda x: x in ['FW''MF,FW''FW,MF'])]

          # 每90s預期進球和得分次數(shù)
          x, y = (df_fil['xG']/df_fil['90s']).to_list(), (df_fil['Gls']/df_fil['90s']).to_list()

          # 生成所有前鋒位置, 數(shù)據(jù)散點圖
          ax_scatter.scatter(x, y, alpha=0.3, c='#EF8804')

          plt.show()


          所有球員每90s預期進球和得分次數(shù)的數(shù)據(jù)情況。



          現(xiàn)在我們篩選出C羅的數(shù)據(jù),在散點圖上用不同的顏色及透明度來突出顯示它。


          # C羅的數(shù)據(jù)
          df_player = df_fil[df_fil['Player'] == 'Cristiano Ronaldo']
          ax_scatter.scatter(df_player['xG']/df_player['90s'], df_player['Gls']/df_player['90s'], c='blue')

          plt.show()


          結(jié)果如下。



          可以看到C羅的數(shù)據(jù)還是比較高效的,雖不是第一,但也是前幾的存在。


          最后給散點圖添加網(wǎng)格線,以及x軸和y軸標簽。


          # 添加網(wǎng)格線及標簽
          ax_scatter.grid(b=True, color='grey',
                          linestyle='-.', linewidth=0.5,
                          alpha=0.4)
          ax_scatter.set_xlabel('每90秒的預期進球', fontdict={'fontsize'12'weight''bold''color': text_color})
          ax_scatter.set_ylabel('每90秒得分', fontdict=dict(fontsize=12, weight='bold', color=text_color))

          plt.show()


          結(jié)果如下。



          不愧是C羅,在2020-21賽季幾乎每90秒就能進1顆球。


          18年就已經(jīng)有一個記錄!C羅成歷史第一位在90分鐘內(nèi)每分鐘都有進球的球員


          最后添加文本信息,包含標題,C羅的頭像,場上位置、年齡、效力球隊。


          此處使用hightlight-text庫,可以高亮文本。


          # 添加C羅的頭像
          ax_player = fig.add_axes([0.030.530.250.45])
          ax_player.axis('off')
          im = plt.imread('ronaldo.png')
          ax_player.imshow(im)

          # 添加標題信息
          fig_text(0.030.94"<克里斯蒂亞諾·羅納爾多(C羅)> 賽季數(shù)據(jù)", weight='heavy', size=19, highlight_textprops=[{'color''blue'}])
          fig_text(0.250.85'位置: <邊鋒>',weight='bold', size=15, highlight_textprops=[{'color':'#EF8804'}])
          fig_text(0.250.81'年齡: <36>',weight='bold', size=15, highlight_textprops=[{'color':'red'}])

          # 添加俱樂部logo
          ax_team = fig.add_axes([0.270.550.150.15])
          ax_team.axis('off')
          im = plt.imread('FCJ.png')
          ax_team.imshow(im)

          # 添加備注
          fig_text(0.070.03'本圖制作者:<小F>   數(shù)據(jù)來源:Fbref.com、Understat.com',
                  size=12, highlight_textprops=[{'color''#EF8804'}], weight='bold')
          plt.show()


          C羅的頭像、效力的隊伍logo,都是小F自己制作的。


          得到結(jié)果如下。



          保存為圖片。


          # 保存為圖片
          plt.savefig('ronaldo_viz.png', dpi=300, facecolor=background)


          看起來還不錯哦。



          好了,本期的分享就到此結(jié)束了,有興趣的小伙伴可以自行去實踐學習。


          使用到的代碼及文件都已上傳,公眾號回復「足球」即可獲取。


          快給自己喜歡的足球運動員,也制作一個賽季數(shù)據(jù)面板吧!


          圖書推薦:Python編程從入門到精通》本書通過趣味的生活案例幫助讀者理解編程中的專業(yè)概念,通過實用的程序?qū)W習編程中的邏輯方法,通過“理論 + 小案例”的形式對各個知識點進行講解,并結(jié)合各個知識點進行綜合實戰(zhàn)的演練。

          文章點贊超過100+

          我將在個人視頻號直播(老表Max)

          帶大家一起進行項目實戰(zhàn)復現(xiàn)

          贈送對應圖書1本



          掃碼即可加我微信

          老表朋友圈經(jīng)常有贈書/紅包福利活動


          學習更多:
          整理了我開始分享學習筆記到現(xiàn)在超過250篇優(yōu)質(zhì)文章,涵蓋數(shù)據(jù)分析、爬蟲、機器學習等方面,別再說不知道該從哪開始,實戰(zhàn)哪里找了
          點贊”就是對博主最大的支持 
          瀏覽 129
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产高潮免费观看 | 我去也最新无码 | 高清无码片 | 日韩二级片视频 | 超碰av在线观看 超碰免费在线97 超碰人人澡人人看 |