手把手带你可视化分析 NBA 季后赛

作者 | 石晓文

来源 | 小小挖掘机

NBA激战正酣,首轮除掘金和马刺的较量还没有结束外,其余对决都已经结束,本文将手把手带你可视化分析下各球队的首轮表现,同时将对次轮最受瞩目的火勇大战进行一个简单的前瞻分析!

通过本文,你将学会python中使用matplotlib库绘制柱状图、散点图、雷达图的相关知识!咱们开始吧!

01 数据获取及准备

我们首先获取各球队季后赛首轮的数据,网址是:https://www.basketball-reference.com/playoffs/NBA_2019.html。首先选择Playoffs:

640?wx_fmt=png
img

然后,下拉到球队技术统计这里,导出csv,如果无法直接倒出,可以复制到txt文件里面(我就是这么干的):

640?wx_fmt=png
img

然后,我们再把对手表现的数据导出,这样基础数据就准备好了:

640?wx_fmt=png
img

好了,我们使用代码将数据进行读取,首先导入所需要的库:

1import pandas as pd
2import matplotlib.pyplot as plt
3import numpy as np

将数据使用pandas进行读取,看看数据如何:

1team_stats_df = pd.read_csv('data/nba1.txt',sep=',')
2team_stats_df
640?wx_fmt=png
img

同样,将对手表现的数据读入,但是这里列名需要修改一下:

1team_opp_stats_df = pd.read_csv('data/nba2.txt',sep=',')
2team_opp_stats_df.columns = ['Rk','Team','G'] + ['opp' + x for x in team_opp_stats_df.columns[3:]]

将两个表按照队名进行merge,这样oppPTS列,可以表示场均失分,这也是我们在对手表现数据里面主要关注的列:

1mergedf = pd.merge(team_stats_df,team_opp_stats_df,on=['Team'])

02 柱状图分析球队场均得失分

绘制柱状图,需要使用的是plt.bar方法,其主要输入的有两个参数,一个是x轴的值,一个是高度,比如,我们绘制一下各球队首轮平均得分的柱状图:

1pts = np.array(mergedf[['PTS','oppPTS']].values.tolist())
2index = np.arange(pts.shape[0])
3plt.bar(index,pts[:,1])
4plt.show()

结果如下:

640?wx_fmt=png
img

上面的图还是有几个问题的,首先,我们不希望X显示的是数值,我们希望展示各个球队名称的缩写,同时刻度可以不从0开始,这样看上去区分度不是十分的明显。

针对第一个问题,我们需要首先按顺序得到各个球队名称的缩写:

1team_name = ['DEN','SA','GSW','PHI','LAC','BKN','POR','HOU','TOR','OKC','UTA','MIL','ORL','BOS','DET','IND']

随后,将x轴的刻度设置为相应的队名:

1plt.xticks(index,team_name) # 设置x轴的刻度

针对第二个问题,我们需要限定y轴的范围,使用ylim方法:

1plt.ylim(80,140) # y轴的范围

这样,我们得到了下面的图片:

640?wx_fmt=png
img

上面这部分的完整代码如下:

1team_name = ['DEN','SA','GSW','PHI','LAC','BKN','POR','HOU','TOR','OKC','UTA','MIL','ORL','BOS','DET','IND']
2plt.ylabel('Score'# 设置y轴的label
3plt.xlabel('Team'# 设置x轴的label
4plt.xticks(index,team_name) # 设置x轴的刻度
5plt.yticks(np.arange(80,141,10)) #y轴的刻度
6plt.ylim(80,140# y轴的范围
7plt.bar(index,pts[:,0]) # 绘制直方图
8plt.rcParams['figure.figsize'] = (12.06.0# 修改图片大小
9plt.show()

此时,我们可能想要将球队的得失分表示出来,代码如下:

 1fig, ax = plt.subplots()
2bar_width = 0.35
3opacity = 0.4
4rects1 = ax.bar(index, pts[:,0], bar_width,alpha=opacity, color='b',label='OFFENSE')
5rects2 = ax.bar(index + bar_width, pts[:,1], bar_width,alpha=opacity, color='r',     label='DEFENSE')
6ax.set_xlabel('Team')
7ax.set_ylabel('PTS')
8ax.set_xticks(index + bar_width / 2)
9ax.set_xticklabels(team_name)
10ax.set_yticks(np.arange(80,141,10)) #y轴的刻度ax.set_ylim(80,140) # y轴的范围ax.legend()
11plt.show()

绘制的结果如下:

640?wx_fmt=png
img

03 散点图分析球队场均得失分

这一部分,我们使用散点图来分析球队场均得失分,使用plt.scatter函数,分别指定各个点的x和y值:

1plt.scatter(pts[:,0], pts[:,1])
2plt.xlabel('Offense PTS'# 设置x轴的label
3plt.ylabel('Defense PTS'# 设置y轴的label
4plt.show()

得到的效果如下:

640?wx_fmt=png
img

简单的绘制散点图,什么都看不出来,此时,我们提出两个需求,首先,能不能将各个球队的简称放到各个点的旁边,这样我们就能清楚知道哪个点代表哪个球队。其次,能不能在图中添加两条直线,分别表示球队得分和失分的平均值?我们一个一个来解决。

首先,将球队标记加入到图中,我们使用plt.annotate函数,该函数需要传入三个参数,依次是注释文本内容,被注释的坐标点,注释文字的坐标位置:

1plt.scatter(pts[:,0], pts[:,1])
2plt.xlabel('Offense PTS'# 设置x轴的label
3plt.ylabel('Defense PTS'# 设置y轴的label
4for i in range(len(pts[:,0])):    
5    plt.annotate(team_name[i], xy = (pts[i,0], pts[i,1]), xytext = (pts[i,0]+0.1, pts[i,1]+0.1)) # 这里xy是需要标记
6plt.show()

此时的效果就能满足我们的第一个需求:

640?wx_fmt=png
img

对于第二个需求,我们使用plt.vlines和plt.hlines方法,对于plt.vlines方法,它是在图中绘制一条竖直线,因此需要指定x轴的坐标,同时需要指定y轴的起始坐标和结束坐标,对于plt.hlines方法,它是在图中绘制一条水平线,因此需要指定y轴的坐标,同时需要指定x轴的起始坐标和结束坐标:

 1offense_mean = np.mean(pts[:,0])
2defense_mean = np.mean(pts[:,1])
3print(offense_mean,defense_mean)
4plt.scatter(pts[:,0], pts[:,1])
5plt.vlines(np.mean(pts[:,0]), np.min(pts[:,1])-5,np.max(pts[:,1])+5,colors = "r", linestyles = "dashed")
6plt.hlines(np.mean(pts[:,1]), np.min(pts[:,0])-5,np.max(pts[:,0])+5,colors = "r", linestyles = "dashed")
7plt.ylim(np.min(pts[:,1])-5,np.max(pts[:,1])+5# y轴的范围
8plt.xlim(np.min(pts[:,0])-5,np.max(pts[:,0])+5# x轴的范围plt.xlabel('Offense PTS') # 设置x轴的
9labelplt.ylabel('Defense PTS'# 设置y轴的label
10for i in range(len(pts[:,0])):    
11    plt.annotate(team_name[i], xy = (pts[i,0], pts[i,1]), xytext = (pts[i,0]+0.1, pts[i,1]+0.1)) # 这里xy是需要标记plt.show()

结果如下:

640?wx_fmt=png
img

基于上面的散点图,我们就能很快将十六支球队分为四个象限。
1)第一象限:进攻好,防守差,包含的球队有金州勇士、费城76人、洛杉矶快船、布鲁克林篮网
2)第二象限:进攻差,防守差,包含的球队有底特律活塞、俄克拉荷马雷霆、圣安东尼奥马刺
3)第三象限:进攻差,防守好,包含的球队有休斯顿火箭、奥兰多魔术、印第安纳步行者、犹他爵士、多伦多猛龙、波士顿凯尔特人
4)第四象限:进攻好,防守好,包含的球队有密尔沃基雄鹿、波特兰开拓者、丹佛掘金

哈哈,是不是跟你想象的不太一样,比如火箭怎么能说是进攻差的球队呢!因为他们的对手爵士是全联盟常规赛防守第一的球队,这种因素我们是无法通过这种图分析出来的。也就是说,数据不能表明一切!

04 基于雷达图的火勇对决前瞻

勇士在今天的比赛中,凭借杜兰特的神奇表现,击败快船与火箭会师西部半决赛,这也是半决赛对决中最受人瞩目的。那么,我们通过雷达图来分析下两队在季后赛首轮的表现吧。这里要说明的是,我们的数据是在勇船第六场之前获取的,因此只有勇士五场的数据。

我们先来看看两队的基础数据,我们挑选了场均得分,场均失分、命中率、三分命中率、篮板、助攻、抢断、盖帽、失误等九项数据:

1two_team_stats = mergedf[(mergedf['Team']=='Houston Rockets') | (mergedf['Team']=='Golden State Warriors')]
2hou_and_gsw_df = two_team_stats[['FG%','3P%','TRB','AST','STL','BLK','PTS','oppPTS','TOV']]
3print(hou_and_gsw_df)

结果如下,其中2代表勇士,7代表火箭:

640?wx_fmt=png
img

接下来,我们想通过雷达图来对比一下二者的这九项数据,matplotlib里面的雷达图貌似必须是统一刻度的,至少我目前还没有找到如何设置为不同刻度。因此,我们首先将二者的数据,用统一的标准,转换到0-1区间内:

1hou_and_gsw_data[:,0] = hou_and_gsw_data[:,0/ 0.55hou_and_gsw_data[:,1] = hou_and_gsw_data[:,1] / 0.55hou_and_gsw_data[:,2] = hou_and_gsw_data[:,2/ 55hou_and_gsw_data[:,3] = hou_and_gsw_data[:,3] / 40hou_and_gsw_data[:,4] = hou_and_gsw_data[:,4/ 12hou_and_gsw_data[:,5] = hou_and_gsw_data[:,5] / 12hou_and_gsw_data[:,6] = hou_and_gsw_data[:,6/ 130hou_and_gsw_data[:,7] = hou_and_gsw_data[:,7] / 130hou_and_gsw_data[:,8] = hou_and_gsw_data[:,8] / 20

绘制雷达图,使用的是极坐标系,因此,我们需要设置一下:

1fig=plt.figure(figsize=(14,8))
2ax1=fig.add_subplot(1,1,1,polar=True) #设置第一个坐标轴为极坐标体系

随后,我们获取勇士和火箭的数据,并取得对应的数据标签:

1gsw=hou_and_gsw_data[0,:] #提取GSW的信息
2hou=hou_and_gsw_data[1,:] #提取HOU的信息
3label=np.array([j for j in hou_and_gsw_df.columns]) #提取标签

随后,我们基于label的数量,对整圆进行切分,在切分的同时,我们需要加入切分后的第一个元素,以形成一个闭环:

1angle = np.linspace(02*np.pi, len(gsw), endpoint=False#有几个label,就把整圆360°分成几份angles = 
2np.concatenate((angle, [angle[0]])) #增加第一个angle到所有angle里,以实现闭合gsw = 
3np.concatenate((gsw, [gsw[0]])) #增加gsw的第一项数据,以实现闭合
4hou = np.concatenate((hou, [hou[0]])) #增加hou的第一项数据,以实现闭合

随后,便可以绘制我们的雷达图:

1ax1.set_thetagrids(angles*180/np.pi, label, fontproperties="Microsoft Yahei"#设置网格标签
2ax1.plot(angles,gsw,"o-",label='GSW')
3ax1.plot(angles,hou,"o-",label='HOU')ax1.set_theta_zero_location('NW'#设置极坐标0°位置
4ax1.set_rlim(0,1#设置显示的极径范围
5ax1.fill(angles,gsw,facecolor='g', alpha=0.2#填充颜色
6ax1.set_title("HOU VS GSW",fontproperties="SimHei",fontsize=16#设置标题
7plt.legend(loc = 'best')plt.show()

结果如下:

640?wx_fmt=png
img

从雷达图来看,火箭除了在抢断和失分上占据一定优势外,其他各项数据均落后于勇士。不过还是刚才的那句话,数据不能体现一切,希望火勇双方能给我们带来一场精彩绝伦的较量。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值