Bootstrap

天池赛:世界杯数据可视化分析

目录

前言

一、数据集介绍

二、读取数据,去重

三、夺冠球队进失球率展示

1.  计算进球数、进球率及场次

2.  计算失球数、失球率及场次

3.  夺冠国家进失球率矩阵图

四、夺冠球队顺逆风球情况

1. 构造胜负关系

2. 主、客队胜负类别可视化

3. 顺、逆风球球队柱图

4. 夺冠国家胜负类别可视化

五、其余可视化部分展示


前言

本次只是针对世界杯比赛比分汇总表做了两个专题分析展示,一个是夺冠球队进失球率,一个是夺冠球队顺逆风球情况


一、数据集介绍

赛事数据链接:世界杯数据可视化分析赛题与数据-天池大赛-阿里云天池

本次数据分析项目包括3张来自FIFA官方数据整理的基础数据表

世界杯成绩信息表:WorldCupsSummary

包含了所有21届世界杯赛事(1930-2018)的比赛主办国、前四名队伍、总参赛队伍、总进球数、现场观众人数等汇总信息,包括如下字段:

  • Year: 举办年份
  • HostCountry: 举办国家
  • Winner: 冠军队伍
  • Second: 亚军队伍
  • Third: 季军队伍
  • Fourth: 第四名队伍
  • GoalsScored: 总进球数
  • QualifiedTeams: 总参赛队伍数
  • MatchesPlayed: 总比赛场数
  • Attendance: 现场观众总人数
  • HostContinent: 举办国所在洲
  • WinnerContinent: 冠军国家队所在洲

世界杯比赛比分汇总表:WorldCupMatches.csv

包含了所有21届世界杯赛事(1930-2014)单场比赛的信息,包括比赛时间、比赛主客队、比赛进球数、比赛裁判等信息。包括如下字段:

  • Year: 比赛(所属世界杯)举办年份
  • Datetime: 比赛具体日期
  • Stage: 比赛所属阶段,包括 小组赛(GroupX)、16进8(Quarter-Final)、半决赛(Semi-Final)、决赛(Final)等
  • Stadium: 比赛体育场
  • City: 比赛举办城市
  • Home Team Name: 主队名
  • Away Team Name: 客队名
  • Home Team Goals: 主队进球数
  • Away Team Goals: 客队进球数
  • Attendance: 现场观众数
  • Half-time Home Goals: 上半场主队进球数
  • Half-time Away Goals: 上半场客队进球数
  • Referee: 主裁
  • Assistant 1: 助理裁判1
  • Assistant 2: 助理裁判2
  • RoundID: 比赛所处阶段ID,和Stage字段对应
  • MatchID: 比赛ID
  • Home Team Initials: 主队名字缩写
  • Away Team Initials: 客队名字缩写

世界杯球员信息表:WorldCupPlayers.csv

  • RoundID: 比赛所处阶段ID,同比赛信息表的RoundID字段
  • MatchID: 比赛ID
  • Team Initials: 队伍名
  • Coach Name: 教练名
  • Line-up: 首发/替补
  • Shirt Number: 球衣号码
  • Player Name: 队员名
  • Position: 比赛角色,包括:C=Captain, GK=Goalkeeper
  • Event: 比赛事件,包括进球、红/黄牌等

二、读取数据,去重

import pandas as pd
df=pd.read_csv("/WorldCupMatches.csv")
df.shape
# (852, 19)

df[df.duplicated()] # 筛选重复值  16个重复值
df=df.drop_duplicates() #删除重复项
df.shape
#(836, 19)

三、夺冠球队进失球率展示

1.  计算进球数、进球率及场次

# 主队进球数
data1=pd.DataFrame(df.groupby("Home Team Name")["Home Team Goals"].agg(["count",'sum']).sort_values('sum',ascending=False).reset_index())
data1.rename(columns={'Home Team Name': '球队','count': '场次','sum':'进球数'}, inplace=True)
# 客队进球数
data2=pd.DataFrame(df.groupby("Away Team Name")["Away Team Goals"].agg(["count",'sum']).sort_values('sum',ascending=False).reset_index())
data2.rename(columns={'Away Team Name': '球队','count': '场次','sum':'进球数'}, inplace=True)
# 合并
data3=data1.merge(data2,on="球队",how="outer")
data3=data3.fillna(0) # 因为部分球队没有作为主队出场过,所以合并后会有NaN,用0填充
data3

data3["总场次"]=data3["场次_x"]+data3["场次_y"]
data3["总进球数"]=data3["进球数_x"]+data3["进球数_y"]
data3["进球率"]=(data3["总进球数"]/data3["总场次"]).round(2)
data3.sort_values("进球率",ascending=False)[:10]

球队场次_x进球数_x场次_y进球数_y总场次总进球数进球率
Hungary1873141432872.72
Brazil7817626451042212.12
Germany FR43991932621312.11
Germany3266122744932.11
Turkey21081010202
France29663040591061.8
Netherlands2949213750861.72
Soviet Union1843131031531.71
Argentina521092522771311.7
Denmark71391416271.69

进球率排名前十的球队。

2.  计算失球数、失球率及场次

# 主队失球数
data4=pd.DataFrame(df.groupby("Home Team Name")["Away Team Goals"].agg(["count",'sum']).sort_values('sum',ascending=False).reset_index())
data4.rename(columns={'Home Team Name': '球队','count': '场次','sum':'失球数'}, inplace=True)
# 客队失球数
data5=pd.DataFrame(df.groupby("Away Team Name")["Home Team Goals"].agg(["count",'sum']).sort_values('sum',ascending=False).reset_index())
data5.rename(columns={'Away Team Name': '球队','count': '场次','sum':'失球数'}, inplace=True)
# 合并填充
data6=data4.merge(data5,on="球队",how="outer")
data6=data6.fillna(0)
# 失球率
data6["总场次"]=data6["场次_x"]+data6["场次_y"]
data6["总失球数"]=data6["失球数_x"]+data6["失球数_y"]
data6["失球率"]=(data6["总失球数"]/data6["总场次"]).round(2)
data6.sort_values("失球率",ascending=True)[:10]
球队场次_x失球数_x场次_y失球数_y总场次总失球数失球率
Angola1121320.67
rn">Republic of Ireland528813100.77
Wales1143540.8
German DR3233650.83
England3520273662560.9
Italy5741263683770.93
Netherlands2920212850480.96
Brazil786626361041020.98
Norway1078881
Serbia1122331

失球率由低到高排名前十的球队。

3.  夺冠国家进失球率矩阵图

# 合并数据表
data7=data3.merge(data6,on="球队",how="outer")
data7=data7[['球队','总场次_x','总进球数','进球率','总失球数','失球率']]
data7.rename(columns={'总场次_x': '总场次'}, inplace=True)
# 画图
import numpy as np
col=["Brazil","Italy","Germany FR","Argentina","France","Uruguay","England","Germany","Spain"]
result=[]
for i in col:
    result.append(data7[data7["球队"]==i])
result=np.array(result)  
result=result.reshape(9,6)
result=pd.DataFrame(result,index=col,columns=data7.columns)
result=result.iloc[:,1:].astype('float')  

import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['font.family']='sans-serif'
mpl.rcParams['font.sans-serif']=[u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False

minx = min(result["失球率"])
maxx = max(result["失球率"])
miny = min(result["进球率"])
maxy = max(result["进球率"])

plt.figure(figsize=(8,8),dpi=100)
for i in range(result.shape[0]):  
    plt.scatter(x=result["失球率"][i],y=result["进球率"][i],s=result["总场次"][i]*20,alpha=0.65,cmap='viridis')
plt.xlim(xmin= maxx+0.1,xmax=minx-0.1) # 将失球率从大到小设定X轴
plt.vlines(x=result['失球率'].mean(), ymin=miny-0.1, ymax=maxy+0.1,
           colors='black', linewidth=1)
plt.hlines(y=result['进球率'].mean(), xmin=minx-0.1, xmax=maxx+0.1,
           colors='black', linewidth=1)
for x,y,z in zip(result["失球率"],result["进球率"],col):
    plt.text(x, y, z, ha='center',fontsize=10)
plt.xlabel("高<—————— 失球率(%) ——————>低",fontsize=15)
plt.ylabel("低<—————— 进球率(%) ——————>高",fontsize=15)
plt.title("夺冠国家进失球率-波士顿矩阵图", fontsize=20)
plt.show()

 这里可以看出,巴西及德国的攻守比较平衡,意大利和英格兰偏重防守。

四、夺冠球队顺逆风球情况

1. 构造胜负关系

df["Half-Goal-difference"]=df["Half-time Home Goals"]-df["Half-time Away Goals"] #半场净胜球
df["Away-Half-Goal-difference"]=df["Half-time Away Goals"]-df["Half-time Home Goals"] #作为客队半场净胜球
df["Goal-difference"]=df["Home Team Goals"]-df["Away Team Goals"] #全场净胜球
df["Away-Goal-difference"]=df["Away Team Goals"]-df["Home Team Goals"] #作为客队全场净胜球
# 半场输赢关系
df.loc[df["Half-Goal-difference"] >0 ,'Half-result'] = '6'   
df.loc[df["Half-Goal-difference"] ==0 ,'Half-result'] = '0'
df.loc[df["Half-Goal-difference"] <0 ,'Half-result'] = '-3' 
df.loc[df["Away-Half-Goal-difference"] >0 ,'Away-Half-result'] = '6'   
df.loc[df["Away-Half-Goal-difference"] ==0 ,'Away-Half-result'] = '0'
df.loc[df["Away-Half-Goal-difference"] <0 ,'Away-Half-result'] = '-3' 
# 全场输赢关系
df.loc[df["Goal-difference"] >0 ,'result'] = '1'
df.loc[df["Goal-difference"] ==0 ,'result'] = '0'
df.loc[df["Goal-difference"] <0 ,'result'] = '-1'
df.loc[df["Away-Goal-difference"] >0 ,'Away-result'] = '1'
df.loc[df["Away-Goal-difference"] ==0 ,'Away-result'] = '0'
df.loc[df["Away-Goal-difference"] <0 ,'Away-result'] = '-1'
# 相减后为字符串,转化为数字
df["Half-result"]=df["Half-result"].astype("int32")
df["result"]=df["result"].astype("int32")
df["Away-Half-result"]=df["Away-Half-result"].astype("int32")
df["Away-result"]=df["Away-result"].astype("int32")

赋值6,-3是为了区分胜、平、负三种关系,如果按照足球规则3分,1分,0分赋值则无法完全区分。

df["v1"]=df["Half-result"]-df["result"]
df["v2"]=df["Away-Half-result"]-df["Away-result"]
print(df["v1"].value_counts())
print(df["v2"].value_counts())

这里就得到了主客两种情况的结果统计

作为主队结果作为客队结果类别说明
5269-22695上半场赢,全场赢
-11761176-1上半场平,全场赢
013401340上半场平,全场平
-297597-2上半场输,全场输
170-1701上半场平,全场输
-434734-4上半场输,全场赢
-327627-3上半场输,全场平
625-3256上半场赢,全场平
74-447上半场赢,全场输

2. 主、客队胜负类别可视化

import matplotlib as mpl
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
mpl.rcParams["font.sans-serif"]=["SimHei"]  
mpl.rcParams["axes.unicode_minus"]=False   
df1=pd.DataFrame(df["v1"].value_counts()/df["v1"].count())
df2=pd.DataFrame(df["v2"].value_counts()/df["v2"].count())
g=["5","-1","0","-2","1","-4","-3","6","7"]
g1=["-2","1","0","5","-1","7","6","-3","-4"]
c=["red","yellow","violet","cyan","lightseagreen","silver","orange","olive","green"]
c1=["cyan","lightseagreen","violet","red","yellow","green","olive","orange","silver"]
t=df1["v1"]
t1=df2["v2"]
wedgeprops = {'width':0.3}
explode = (0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.15)  
fig = plt.figure(figsize=(15,15))
plt.subplot(121)
plt.pie(t,explode=explode,labels=g,autopct="%3.1f%%",startangle=60,colors=c,wedgeprops=wedgeprops)
plt.title("作为主队半场与全场胜负关系占比")
plt.subplot(122)
plt.pie(t1,explode=explode,labels=g1,autopct="%3.1f%%",startangle=60,colors=c1,wedgeprops=wedgeprops)
plt.title("作为客队半场与全场胜负关系占比")
plt.show()

 
 

作为主队,在上半场不败的前提下,全场获胜的场次占比达到53.3%。

作为客队,在上半场打平或者输球的情况下,全场输球的占比达到53.3%。

3. 顺、逆风球球队柱图

df3=df[df["v1"]==5]    # 顺风球
df3_away=df[df["v2"]==5]
df4=df[(df["v1"]==-3)|(df["v1"]==-4)]  # 逆风球
df4_away=df[(df["v2"]==-3)|(df["v2"]==-4)]
fig = plt.figure(figsize=(12,8))
plt.subplot(221)
df3["Home Team Name"].value_counts().sort_values(ascending=True)[-10:].plot(kind= 'barh')
plt.title("作为主队顺风球球队前十")
plt.subplot(222)
df3_away["Away Team Name"].value_counts().sort_values(ascending=True)[-10:].plot(kind= 'barh')
plt.title("作为客队顺风球球队前十")
plt.subplot(223)
df4["Home Team Name"].value_counts().sort_values(ascending=True)[-10:].plot(kind= 'barh')
plt.title("作为主队逆风球球队前十")
plt.subplot(224)
df4_away["Away Team Name"].value_counts().sort_values(ascending=True)[-10:].plot(kind= 'barh')
plt.title("作为客队逆风球球队前十")
plt.subplots_adjust(wspace=0.5,hspace=0.3)
plt.show()

其实世界杯是不分主客场的,小组赛只是针对双方球衣的选择问题,抽到主队的就穿该队的主场球衣,也就是该队的传统比赛服,如西班牙的红色、法国的三色球衣、巴西的黄色、阿根廷的蓝白色等。打到淘汰赛就不是了,16进8小组第一的是主队,而四分之一比如A1对C1,A1就是主队

4. 夺冠国家胜负类别可视化

4.1 作为主队时

plt.figure(figsize=(20,20))
for i, j in enumerate(col):
    df_home=df[df["Home Team Name"]==j]
    data=pd.DataFrame(df_home.loc[:,"v1"].value_counts()/df_home.loc[:,"v1"].count())
    plt.subplot(3,3,i+1)  
    plt.pie(data["v1"],labels=data.index,autopct="%3.1f%%",startangle=60,colors=c,\
              textprops={'fontsize': 15},wedgeprops={'width':0.3},pctdistance=0.7)
    plt.title(j, fontsize=18)
plt.show()

作为主队时,各个球队赢球的场次占比都比较多,例如巴西,作为主队(身着黄色球衣)时,在上半场领先的情况下,全场就没有输过球。且全场输球的场次占比只有8.9%,难道主场球衣真有胜负加持?

4.2 作为客队时

plt.figure(figsize=(20,20))
for i, j in enumerate(col):
    df_away=df[df["Away Team Name"]==j]
    data1=pd.DataFrame(df_away.loc[:,"v2"].value_counts()/df_away.loc[:,"v2"].count())
    plt.subplot(3,3,i+1) 
    plt.pie(data1["v2"],labels=data1.index,autopct="%3.1f%%",startangle=60,\
           colors=c1,textprops={'fontsize': 15},wedgeprops={'width':0.3},pctdistance=0.7)
    plt.title(j, fontsize=18)
plt.show()

 作为客队时,输球的场次占比高于作为主队,例如巴西:全场输的比例达到38.4%

五、其余可视化部分展示

 

 

 

 

 

总结

原始数据有3个表格,可以选择自己感兴趣的方向分析,总的来说是一次不错的数据分析锻炼。


;