接着前几天发的关于kaggle中NBA球员投篮数据探索性数据分析和可视化分析之后,小编本打算对这13万的投篮数据跑几个机器学习模型预测一下投篮的,可是电脑内存不给力,试了几次之后便作罢了。还打算第一次试一下kaggle上被传的神乎其技的大杀器xgboost的呢。机器学习的模型都写好了,有图为证:
于是便转而去做特征构造,毕竟知乎和Quora上都认为特征工程作为kaggle的核心技能。前几天NBA颁奖大会本赛季的最佳防守球员是勇士队的追梦.格林,于是便从防守端的角度出发,利用特征工程手段来分析2014-15赛季哪些球员才算NBA里拥有顶级防守水平的球员。
不了解特征工程的同学看这篇文章就够了:
https://www.zhihu.com/question/29316149
小编这里就不分条条框框了,直接上代码来的舒适。
读入数据,进行特征观察与变量筛选:
nbashots<-read.csv("D:/Rdata/kaggle_nbashots/shot_logs.csv")
str(nbashots)
attach(nbashots)
#剔除触球时间小于0的记录
nbashots <- nbashots[TOUCH_TIME > 0,]
#因与FGM变量含义一致,删除Shot Result变量
nbashots <- nbashots[,-14]
数据集中有两个关于时间的变量,一个是比赛时间变量GAME_CLOCK,另一个是投篮时间变量SHOT_CLOCK,二者格式并不统一,我们可以使用gsub函数进行处理:
player_name <- as.character(player_name)
player_name <- factor(player_name)
#处理比赛时间变量
GAME_CLOCK <- as.character(GAME_CLOCK)
GAME_CLOCK <- gsub(":", ".", GAME_CLOCK)
#与投篮时间变量类型一致
GAME_CLOCK <- as.numeric(GAME_CLOCK)
下面就进入到特征工程的表演时间了。我们首先定义比赛中所谓的关键时刻,将投篮时间在第四节最后一分钟以内且双方最终分差在五分以内的投篮定义为关键投篮。且看特征构造过程:
nbashots$Crucial_time <- "No"
nbashots$Crucial_time[nbashots$GAME_CLOCK <= 1 &
nbashots$PERIOD >= 4 & abs(nbashots$FINAL_MARGIN) <= 5] <- "Yes"
nbashots$Crucial_time <- factor(nbashots$Crucial_time)
再通过运球次数和投篮距离来定义相应的投篮类型。我们将投篮类型分为六种:接球就投、空切、突破上篮、单打、长时间单打和定点三分。
nbashots$shot_type[nbashots$DRIBBLES <= 1 &
nbashots$SHOT_DIST > 4] <- 'Catch and Shoot'
nbashots$shot_type[nbashots$DRIBBLES <= 1 &
nbashots$SHOT_DIST <= 4] <- 'Cut'
nbashots$shot_type[nbashots$DRIBBLES > 1 &
nbashots$SHOT_DIST <= 4] <- 'Drive'
nbashots$shot_type[nbashots$DRIBBLES > 4] <- 'ISO'
nbashots$shot_type[nbashots$DRIBBLES > 20] <- 'Long ISO'
nbashots$shot_type[nbashots$DRIBBLES <=1 &
nbashots$PTS_TYPE == 3] <- 'Spot Up Three'
nbashots$shot_type <- factor(nbashots$shot_type)
看一下统计结果:
summary(nbashots$shot_type)
Catch and Shoot Cut Drive ISO Long ISO Spot Up Three
34134 17025 4665 18109 507 28090
NA's
22181
长时间ISO的球霸毕竟还是少的哈。
根据防守人距投篮人距离来定义投篮质量。将投篮质量分为open(空位)wide open(大空位)tightly contested(无死角盯防)contested(全面盯防到位)四种:
nbashots$shot_quality <- 'Open'
nbashots$shot_quality[nbashots$CLOSE_DEF_DIST <= 2]
<- 'Tightly Contested'
nbashots$shot_quality[nbashots$CLOSE_DEF_DIST <= 3.5] <- 'Contested'
nbashots$shot_quality[nbashots$CLOSE_DEF_DIST > 6] <- 'Wide Open'
nbashots$shot_quality <- factor(nbashots$shot_quality)
看一下统计结果:
summary(nbashots$shot_quality)
Contested Open Wide Open
58965 44404 21342
看来坊间传说的在NBA里任何时间你拿到球都有一个七尺大汉张牙舞爪的站在你身前的说法不是虚的啊。
下面为了定义一名NBA球员的防守有哪些指标构成,我们需要通过变量之间的关系构造被防守人投篮命中率(OppFG)、被防守人每回合得分(OppPPP)、与投篮人距离(OppDist)、每名防守人防守的投篮次数(ShotsCont)、防守投篮时与篮筐的平均距离(RimDist)以及每名球员作为离投篮人最近的防守投篮次数(ShotsNear),在构造这些防守变量前,需要创建一些空的向量来存储这些变量内容。数据集中包括473名防守球员,我们利用rep函数如下:
OppFG <- rep(1, 473)
OppPPP <- rep(1, 473)
OppDist <- rep(1, 473)
ShotsCont <- rep(1, 473)
RimDist <- rep(1, 473)
ShotsNear <- rep(1, 473)
FGM <- nbashots$FGM
PTS <- nbashots$PTS
CLOSE_DEF_DIST <- nbashots$CLOSE_DEF_DIST
SHOT_DIST <- nbashots$SHOT_DIST
CLOSEST_DEFENDER <- nbashots$CLOSEST_DEFENDER
for (i in 1:473) {
OppFG[i] = sum(FGM[CLOSEST_DEFENDER == DefenderList[i]])
/length(FGM[CLOSEST_DEFENDER == DefenderList[i]])
OppPPP[i] = sum(PTS[CLOSEST_DEFENDER == DefenderList[i]])
/length(FGM[CLOSEST_DEFENDER == DefenderList[i]])
OppDist[i] = sum(CLOSE_DEF_DIST[CLOSEST_DEFENDER ==
DefenderList[i]])/length(FGM[CLOSEST_DEFENDER == DefenderList[i]])
ShotsCont[i] = length(FGM[CLOSEST_DEFENDER == DefenderList[i]
& CLOSE_DEF_DIST <= 3.5])
RimDist[i] = sum(SHOT_DIST[CLOSEST_DEFENDER == DefenderList[i]])
/length(FGM[CLOSEST_DEFENDER == DefenderList[i]])
ShotsNear[i] = length(FGM[CLOSEST_DEFENDER == DefenderList[i]])
}
创建球员防守能力指标的数据框nba_def并进行统计:
nba_def <- data.frame(DefenderList, OppFG, OppPPP,
OppDist, ShotsCont, RimDist, ShotsNear)
summary(nba_def)
DefenderList OppFG OppPPP OppDist ShotsCont
Acy, Quincy : 1 Min. :0.0000 Min. :0.0000 Min. : 1.000 Min. : 0.0
Adams, Jordan : 1 1st Qu.:0.4233 1st Qu.:0.9348 1st Qu.: 3.888 1st Qu.: 42.0
Adams, Steven : 1 Median :0.4524 Median :1.0026 Median : 4.165 Median :112.0
Adrien, Jeff : 1 Mean :0.4579 Mean :1.0194 Mean : 4.187 Mean :124.7
Afflalo, Arron: 1 3rd Qu.:0.4821 3rd Qu.:1.0749 3rd Qu.: 4.454 3rd Qu.:187.0
Ajinca, Alexis: 1 Max. :1.0000 Max. :2.6667 Max. :18.900 Max. :423.0
(Other) :467
RimDist ShotsNear
Min. : 4.20 Min. : 1.0
1st Qu.:11.99 1st Qu.: 96.0
Median :14.84 Median :253.0
Mean :14.09 Mean :263.7
3rd Qu.:16.30 3rd Qu.:406.0
Max. :23.25 Max. :791.0
简单用几个指标看下2014-15赛季哪些球员的防守表现较为突出。先通过限制对手命中率和限制对手每回合得分数来看一下,ggplot2作图展示:
ggplot(data = nba_def[ShotsCont >= 150 & OppFG <= .41,],
aes(OppFG, OppPPP)) +
geom_point(colour = "black", size = 2) +
geom_point(aes(colour = DefenderList)) +
geom_smooth(method = "lm", se = FALSE) +
geom_text(aes(label = DefenderList), size = 3, vjust = 0,
check_overlap = TRUE) + guides(colour = FALSE) +
labs(x = "Opponent Field Goal Percentage",
y = "Opponent Points per Possesion")
在防守对方投篮150次以上并且限制对方命中率在41%以下的优秀防守球员中,对手的命中率和每回合得分数表现如下图:
一些以防守凶悍著称的球员包括今年首轮给登哥造成麻烦的罗伯森、爵士的戈伯特、勇士的博格特、德拉蒙德.格林等球员。当然图中也有库里和蒙塔这类防守一般的球员,通过限制对手命中率和每回合得分数的线性关系可以看出来。
再来看一个与投篮人距离和每回合得分数之间的关系图:
ggplot(EliteDef, aes(OppDist, OppPPP)) +
geom_point(colour = "black", size = 2) +
geom_point(aes(colour = DefList)) +
geom_smooth(method = "lm", se = FALSE) +
geom_text(aes(label = DefenderList), size = 3, vjust = 0,
check_overlap = TRUE) +
guides(colour = FALSE) +
labs(x = "Average Distance of Contest",
y = "Opponent Points per Possession")
由图中也可以看出,二者也呈现出较强的线性关系。NBA里一些长手长脚的球员即使你离他4英尺远以上,他的长臂干扰仍然可以使得你的命中率极低。比如雷霆的安德烈.罗伯森、鹈鹕的戴维斯等。
总体写的比较乱,仅分析了一点内容,对于构造的防守指标里面的其他没用到的指标也大有文章可做。这里小编仅展示一些特征工程的方法,毕竟这才是kaggle的核心。部分参考了kaggle用户Stefanlangen的结果,并对部分代码做了优化。kaggle给的每个数据集都有太多可供挖掘的部分,有兴趣的同学可以深入探索下啦。最后放一张我麦的照片吧。
一个数据科学践行者的学习日记