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

目录

前言

一、数据集介绍

二、读取数据,去重

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

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 总场次 总进球数 进球率
Hungary 18 73 14 14 32 87 2.72
Brazil 78 176 26 45 104 221 2.12
Germany FR 43 99 19 32 62 131 2.11
Germany 32 66 12 27 44 93 2.11
Turkey 2 10 8 10 10 20 2
France 29 66 30 40 59 106 1.8
Netherlands 29 49 21 37 50 86 1.72
Soviet Union 18 43 13 10 31 53 1.71
Argentina 52 109 25 22 77 131 1.7
Denmark 7 13 9 14 16 27 1.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 总场次 总失球数 失球率
Angola 1 1 2 1 3 2 0.67
rn">Republic of Ireland 5 2 8 8 13 10 0.77
Wales 1 1 4 3 5 4 0.8
German DR 3 2 3 3 6 5 0.83
England 35 20 27 36 62 56 0.9
Italy 57 41 26 36 83 77 0.93
Netherlands 29 20 21 28 50 48 0.96
Brazil 78 66 26 36 104 102 0.98
Norway 1 0 7 8 8 8 1
Serbia 1 1 2 2 3 3 1

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

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())

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

作为主队结果 作为客队结果 类别说明
5 269 -2 269 5 上半场赢,全场赢
-1 176 1 176 -1 上半场平,全场赢
0 134 0 134 0 上半场平,全场平
-2 97 5 97 -2 上半场输,全场输
1 70 -1 70 1 上半场平,全场输
-4 34 7 34 -4 上半场输,全场赢
-3 27 6 27 -3 上半场输,全场平
6 25 -3 25 6 上半场赢,全场平
7 4 -4 4 7 上半场赢,全场输

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个表格,可以选择自己感兴趣的方向分析,总的来说是一次不错的数据分析锻炼。


猜你喜欢

转载自blog.csdn.net/weixin_46685991/article/details/128329960
今日推荐