程序员怎样出版一本技术书,程序员副业那些事:聊聊出书和录视频
kaggle竞赛分享:NFL大数据碗 – 上
竞赛简介
一年一度的NFL大数据碗,今年的预测目标是通过两队球员的静态数据,预测该次进攻推进的码数,并转换为该概率分布;
竞赛链接
https://www.kaggle.com/c/nfl-big-data-bowl-2020
项目链接,该项目代码已经public,大家可以copy下来直接运行
https://www.kaggle.com/holoong9291/nfl-big-data-bowl
github仓库链接,更多做的过程中的一些思考、问题等可以在我的github中看到
一些基本概念
- 美式足球:进攻方目的是通过跑动、传球等尽快抵达对方半场,也就是达阵,而防守方的目的则是相反,尽全力去阻止对方的前进以及尽可能断球;
- 球场长120码(109.728米),宽53码(48.768米),周长是361.992米;
- 球员:双方场上共22人,进攻方11人,防守方11人,进攻方持球;
- 进攻机会:进攻方共有四次机会,需要推进至少十码;
- 进攻方:进攻方的职责是通过四次机会,尽可能的向前推进10码或者达阵,以获得下一个四次机会,否则就需要交出球权;
- 防守方:防守方则是相反,尽可能的阻止对方前进,如果能够断球那更好,直接球权交换;
- handoff:传球;
- snap:发球;
- 橄榄球基本知识点我了解;
- QB:四分卫,通常是发球后接球的那个人,一般口袋阵的中心,但是也不乏有像拉马尔-杰克逊这样的跑传结合的QB,目前古典QB代表是新英格兰爱国者NE的汤姆-布雷迪;
- RB:跑卫,通常发球后进行冲刺、摆脱等,试图接住本方QB的传球后尽可能远的冲刺;
球场码线图
一个常见的开球前站位图
数据字段介绍、绘图分析
字段信息:
GameId
– a unique game identifier – 比赛IDPlayId
– a unique play identifier –Team
– home or away – 主场还是客场X
– player position along the long axis of the field. See figure below. – 在球场的位置xY
– player position along the short axis of the field. See figure below. – 在球场的位置yS
– speed in yards/second – 速度,码/秒A
– acceleration in yards/second^2Dis
– distance traveled from prior time point, in yardsOrientation
– orientation of player (deg) 球员面向Dir
– angle of player motion (deg) 球员移动方向NflId
– a unique identifier of the player – NFL球员IDDisplayName
– player’s name – 球员名JerseyNumber
– jersey number – 球衣号码Season
– year of the seasonYardLine
– the yard line of the line of scrimmageQuarter
– game quarter (1-5, 5 == overtime) – 当前是第几节比赛,5为加时GameClock
– time on the game clock – 比赛时间PossessionTeam
– team with possession – 持球方Down
– the down (1-4) – 达阵Distance
– yards needed for a first down – 距离拿首攻所需距离FieldPosition
– which side of the field the play is happening onHomeScoreBeforePlay
– home team score before play started – 赛前主队分数VisitorScoreBeforePlay
– visitor team score before play started – 赛前客队分数NflIdRusher
– the NflId of the rushing playerOffenseFormation
– offense formationOffensePersonnel
– offensive team positional groupingDefendersInTheBox
– number of defenders lined up near the line of scrimmage, spanning the width of the offensive lineDefensePersonnel
– defensive team positional groupingPlayDirection
– direction the play is headedTimeHandoff
– UTC time of the handoff – 传球时间TimeSnap
– UTC time of the snap – 发球时间Yards
– the yardage gained on the play (you are predicting this) – 目标PlayerHeight
– player height (ft-in) – 球员身高PlayerWeight
– player weight (lbs) – 球员体重PlayerBirthDate
– birth date (mm/dd/yyyy) – 生日、岁数PlayerCollegeName
– where the player attended college – 大学Position
– the player’s position (the specific role on the field that they typically play) – 场上位置HomeTeamAbbr
– home team abbreviation – 主队缩写VisitorTeamAbbr
– visitor team abbreviation – 客队缩写Week
– week into the seasonStadium
– stadium where the game is being played – 体育场Location
– city where the game is being player – 城市StadiumType
– description of the stadium environment – 体育场类型Turf
– description of the field surface – 草皮GameWeather
– description of the game weather – 比赛天气Temperature
– temperature (deg F) – 温度Humidity
– humidity – 湿度WindSpeed
– wind speed in miles/hour – 风速WindDirection
– wind direction – 风向
定义问题
回归预测,Target是码数,但是最终结果需要转换为条件概率分布;
Evaluation Function
Continuous Ranked Probability Score (CRPS);
项目流程分享
定义模型输出结果到概率分布的转换类
这里竞赛需要的并不是具体的码数,而是码数对应的概率分布,也就是所有码数在一次进攻中的概率,所以需要这样一个转换类,如下:
【UWP】使用 LiteDB 存储数据
缺失值处理
训练数据上看,缺失情况不严重,缺失字段如下:
这里对缺失的处理根据不同类型的字段采取不同的方式:
- 天气相关字段,由于天气具有连续性,因此采用前向填充较为合理:
- 体育场类型,严格来说应该是通过baidu、google等去搜索,但是NFL的相关信息baidu搜到的太少,google上看也没找到,所以用取值最多的来填充:
- FieldPosition,这个字段的缺失不同于以上两个,通过对数据的分析,它的缺失源于在中线开球时,此时没法明确指出是在哪个半场,所以缺失,这里用一个特别的值来填充,“Middle”;
- OffenseFormation,进攻队形,实际缺失了5条,统一用取值最多的来填充即可;
- DefendersInTheBox,防守方在混战线附近的人数,通过观察数据可以通过球队、对手、以及防守组成员来填充DefendersInTheBox:
- Orientation 球员方位-角度,Dir 球员移动-角度,只有一条缺失,且该球员正常上场了的,应该是技术型缺失,用mean填充即可;
异常、重复等处理
- StadiumType:存在不同名但是同意思的情况,这里要整理后归一处理,避免对模型产生干扰;
- 存在PossessionTeam既不是HomeTeamAbbr也不是VisitorTeamAbbr,共有120场比赛中出现这种情况;
- 草皮字段处理;
- Location字段也存在重复含义但是不同值的情况需要归一;
EDA:探索性数据分析
下面是通过matplotlib绘制的一场比赛中的多个进攻防守回合的展示图,黑色三角形是QB,红色是进攻方,淡蓝色是防守方:
可以清楚的看到每次进攻不同的站位,以及整个推进的过程,这里我记录的一份NFL比赛手记,爱国者vs乌鸦,新老QB的正面交锋,非常精彩,可以对照着看一下;
特征工程
这里由于我个人对橄榄球的了解也并不是很多(强推电影弱点),所以特征工程部分做的并不是很好,从结果看Top61%也反映除了这个问题,但是我依然觉得具有一定的参考意义,下面我会分析每个新特征构建的目的,以及我的想法;
- WindSpeed,WindDirection:直观看,对比赛影响应该不大,可能存在某些传球手喜欢顺风或者逆风,但是影响应该很小,所以我这里选择丢弃;
- PlayerHeight:转为球员身高,身高无疑对比赛是有关系的;
- PlayerBirthDate:生日转为岁数,岁数可以表示一个球员的身体状况是否处于巅峰等;
- 开球到传球的时间 – (TimeHandoff-TimeSnap):我认为这一时间的长短一定程度上决定了战术的选择,而战术肯定是影响了进攻码数的;
- 比赛进行时间 – (15-GameClock+Quarter*15):比赛进行了多久对球员们的体力、战术选择等都有很大影响;
- Position_XX:用于统计当前进攻中场上各个角色的人数组成,这也跟战术选择密切关系;
- goal区:码线对方半场10码或10码内,此时距离达阵不到10码,一般这种情况下战术选择会变得与之前不太一样,不管是防守方还是进攻方;
- 首攻危险:这是我自己定义的,即当目前进攻方仅有一次进攻机会,而所需继续进攻的码数大于5时,我认为是有首攻危险的,此时很可能丢失球权,down为4,且distance大于5;
- 距离达阵还有多少码:一般距离的不同,防守方的防守策略会有不同,距离较远一般会较为保守,距离较近则会比较激进;
- 其余object特征做label encode处理;
聚合数据并整理聚体统计特征
这里要注意,训练数据每一行表示的是一次进攻中一个球员的情况,我们预测的是每次进攻,因此需要把每22条数据聚合为1条,这个过程中会有一些数据统计特征的产生,下面简介整个流程:
- 延迟特征:即每个球员分别在之后0.5s,1s,2s,3s后的位置信息;
- 平均特征:分为进攻方和防守方,平均速度、平均加速度、平均身高、平均体重、平均年龄;
- 持球人为中心特征:当前、延迟0.5s,1s,2s,3s时,进攻方和防守方球员与他的平均距离;
- 持球人为中心特征2:当前、延迟0.5s,1s,2s,3s时,进攻方和防守方球员在持球人3码、5码内的人数估计;
一次进攻的成败,大部分情况下取决于四分卫的发挥,而对其发挥其重要作用的,除了他自己,就是他身边的队友以及对手的数量,这一定程度上影响了他的可选择空间大小;
这一段的处理代码较多,只截取了一部分,如下:
测试数据处理
测试数据处理与训练数据保持一致即可;
建模
到此,数据处理完毕,后续就是建模、调参、combine等优化处理了,这一步我没有花太多精力,模型选择ExtraTreesRegressor,由于其使用了oob,因此不需要CV,结果如下:
最后
大家可以到我的Github上看看有没有其他需要的东西,目前主要是自己做的机器学习项目、Python各种脚本工具、数据分析挖掘项目以及Follow的大佬、Fork的项目等:
https://github.com/NemoHoHaloAi
150行代码打造.net core生产力工具,你值得拥有