美文网首页
小数据小分析——谁是本赛季最佳后卫?

小数据小分析——谁是本赛季最佳后卫?

作者: 张伟松 | 来源:发表于2017-07-09 23:04 被阅读64次

    学习数据分析一月有余,终于鼓起勇气开启了自己的实战演练。本次练习的文件从BasketballReference 上下载,2016~16赛季球员数据,自定义了几个分析任务,通过R对数据框、字符、数字的操作,熟悉和掌握数据分析的基本方法。

    本篇原本是在知乎上操作的。熬夜到2点写的文章因为知乎平台一个未知错误,导致图片代码全部消失,这里我只想说¥%(&%…,于是果断放弃知乎

    数据分析的一遍流程是:

    业务理解=>数据准备/预处理=>分析/挖掘=>评估=>应用/部署/报告/决策

    获取数据

    表格的主要字段有球员姓名,位置,出场次数,首发次数等,如下图。

    2016~16赛季球员数据

    明确目标

    分析任务是:

    1. 算出得分最多的前十名
    2. 各个位置(PG,SG,SF,PF,C)的最佳球员
    3. 算出每个球队在16~17赛季的总得分
    4. 绘制年龄和命中率的趋势图
    5. 答案在最后

    数据预处理

    首先在windows下读取excel文件,这里有一些坑:

    • 需要用到的包是openxlsx,但是有时会安装失败,这时就需要先安装Rtools
      然后在R中运行
    Sys.setenv("R_ZIPCMD" = "C:/Rtools/bin/zip.exe")
    
    • library导入所需的包之后,openxlsx中的函数read.xlsx()可以很方便的读取文件,函数中的文件路径,可以是相对路径,亦可以是绝对路径。如果使用相对路径,相对的是当前的工作目录getwd()可查看。后来发现可以使用file.choose()来直接拉取windows的文件浏览器。
    nbaData <- read.xlsx(file.choose())
    

    下载的原始数据感觉不是美美哒,需要进行数据预处理,预处理的主要工作包含重命名列,处理缺失值,处理日期,数值转换,排序

    1. 处理缺失值
      函数na.omit()用来删除数据框中含有缺失值的记录
      nbaData <- na.omit(nbaData)
    2. 在原始数据中,姓名带斜杠,后面有一些标志:

    好像是每个球员的某种唯一编码,不太懂。去掉好处理。

    library(stringr)
    fixednames <- str_split_fixed(nbaData$Player,'\\\\',n=2)[,1]
    nbaData$Player <- fixednames
    

    斜杠\是R中的转义字符,使用\\\\\\\\才能正确表达使用斜杠截取的含义,str_split_fixed是stringr中的函数,看名字就能才出来它是str_split的加强版,返回的是含有n个元素的矩阵。

    • 这里遇到一个问题,某些球员如 Quincy Acy 先后在三个球队服役,这里为了方便处理,只保留第一个
    nbaData <- nbaData[!duplicated(nbaData[,c("Player")]),]
    

    计算关键指标

    算出得分最多的前十名

    各个位置(PG,SG,SF,PF,C)的最佳球员

    每个位置的评判 标准不一样,比如控后PG就更看重助攻AST而不是篮板TRB,而中锋C的核心指标应该是篮板和盖帽BLK。况且每个字段的值域还都不一样,这就比较蛋疼了。我想到一个办法——标准化。

    这里我们做一些简单的规定,对于每个位置,篮板数TRB、助攻AST、盖帽BLK、场均得分PS/G、失误PF,各自权重如下:

    weightPG  <- c(0,4,0,3,-1)
    weightSG <- c(0,2,1,4,-2)
    weightSF <- c(2,1,2,4,-1)
    weightPF <- c(3,1,3,3,-1)
    weightC <- c(4,2,4,3,-1)
    

    可能不是很合理,凑合用吧先
    发现严重问题
    并不是每个人的位置都是固定的,比如杰弗瑞·洛文吉这货,就既是中锋,又是大前。我想知道还有那些人担任着多种角色,进行了如下尝试:
    首先定义全部的位置
    allpos <- c('PG','SG','SF','PF','C')
    然后查看在所有球员中,哪些人的位置在这个向量里面is.element(nbaData$Pos,allpos)
    返回的是一堆逻辑向量,在总表中
    nbaData[!is.element(nbaData$Pos,allpos),]
    输出的结果如下

       Rk            Player  Pos Age  Tm  G GS MP  FG FGA  FG%  3P 3PA   3P%
    310 254 Joffrey Lauvergne PF-C  25 TOT 70  1 14 2.1 4.8 0.44 0.5 1.4 0.337
         2P 2PA   2P% eFG%  FT FTA  FT% ORB DRB TRB AST STL BLK TOV  
    310 1.6 3.4 0.483 0.49 0.7   1 0.63   1 2.6 3.6   1 0.4 0.1 0.8 1.2  5.4
        score
    310   378
    

    就只有你一个。好吧去掉。
    nbaData <- nbaData[is.element(nbaData$Pos,allpos),]
    把所有的球员按位置分组

    PG <- nbaData[nbaData$Pos=='PG',]
    SG <- nbaData[nbaData$Pos=='SG',]
    SF <- nbaData[nbaData$Pos=='SF',]
    PF <- nbaData[nbaData$Pos=='PF',]
    C <- nbaData[nbaData$Pos=='C',]
    

    然后用函数scale算出他们篮板数TRB、助攻AST、盖帽BLK、场均得分PS/G、失误PF的标准差,与权重相乘,求和,是他们的最终得分。
    基于每个位置的方法大同小异,我以控球后卫PG为例。

    valueName <-c('TRB','AST','BLK','PS/G','PF')
    sd <- t(t(scale(PG[valueName ]))*weightPG)
    PG$est<-  round(apply(sd,1,sum),digits=2)
    PG <- PG[order(PG$est,decreasing = T),]
    firstPG <- PG[1,]
    

    好吧,这样算下来还是威斯布鲁克。
    按这个步骤算出其他位置:

    firstSG <- 'DeMar DeRozan'
    firstSF <- 'Kevin Durant'
    firstPF <- 'Kristaps Porzingis'
    firstC <- 'Anthony Davis'
    

    除了杜兰特,其他人是谁?

    算出每个球队在16~17赛季的总得分

    数据表中只有每个球员的得分,和所在球队,我要做的就是根据球队,计算球员的总得分,我想到了可以用SQL中的SELECT sum(score) FROM nbaData GROUP BY Tm的方法,不过既然要学习R,就要用R的方法,找了一早上,发现了tapply这个函数可以进行分组计算。

    teamscore <- tapply(nbaData$score, nbaData$Tm, sum)
    

    然后进行绘图

    • paste函数默认以空格分隔,设置sep=""可以避免空格
    • text函数用来为plot图表添加坐标上的数值。
    • X轴上的名字总是显示不全,谁能教教我?
    filename <- paste('score of each team','.png',sep="")
    png(file=filename)
    barplot(height=teamscore,names.arg=teams,xlab="team",ylab="score",col="blue",
            main="score of each team",border="red") 
    text(x,teamscore,labels=teamscore,cex=.7,pos=1,col='orange')
    dev.off()
    
    score of each team.png

    很丑我知道。

    绘制年龄和命中率的趋势图

    计算命中率,图表中有2P%(2分球命中率)、3P%(3分球命中率),和FT%(罚篮命中率),罚球不参与讨论。2P%和3P%打算取平局值,能说明问题就行。
    nbaData$AvePR <- apply(nbaData[c('2P%','3P%')],1,mean)
    首次是求出了平均值,然后绘制散点图,并根据散点图拟合出回归线。起初使用attach和detach会报错The following objects are masked _by_.GlobalEnv:查了一下原来是因为attach出来的变量有重名的,并推荐使用with。

    
    with(nbaData,{ 
      filename <- paste('各年龄球员命中率','.png',sep="")
      png(file=filename)
      plot(Age,AvePR,pch=16,xlab="年龄",ylab="命中率",col="blue",
           main="各年龄球员命中率")
      abline(lm(AvePR~Age)) 
      dev.off() 
    }) 
    

    猜一下那个年龄最大的球员是谁。

    各年龄球员命中率.png
    有点意外,命中率竟然和年龄没多大关系

    nbaData[nbaData$Age == max(nbaData$Age),]

    40岁的卡特

    答案

    1. 算出得分最多的前十名
      他们是威斯布鲁克、 哈登、小托马斯 、安东尼·戴维斯、22岁的卡尔·安东尼·唐斯、利拉德 、德玛尔·德罗赞、库里、我詹 、德马库斯·考辛斯,不服来辩。

    2. 各个位置(PG,SG,SF,PF,C)的最佳球员
      控后:威斯布鲁克
      分后: 德玛尔·德罗赞
      小前: 杜兰特
      大前:克里斯塔普斯·波尔津吉斯
      中锋: 安东尼·戴维斯

    3. 算出每个球队在16~17赛季的总得分
      参看上面的图。

    4. 绘制年龄和命中率的趋势图
      参看上一题。

    总结

    6月27号开始本次本次实践,中间断断续续发生一些事情,本不该影响到学习的,到做完已经花费10多天,是不是有点慢了?恩姆。好歹自己坚持下来做完了,小小一张表竟然蕴含了这么多信息,简直太有意思,体会到所谓冰山一角的含义了。所以,慢就是快

    相关文章

      网友评论

          本文标题:小数据小分析——谁是本赛季最佳后卫?

          本文链接:https://www.haomeiwen.com/subject/ffrrhxtx.html