> library(pacman)
> p_load(dplyr, readr, caret)
1、数据准备与数据理解
数据集的行是游戏玩家们玩的每一次游戏,列是某个玩家玩游戏时的速度、能力和决策,都是数值型变量。
任务是根据这些表现的衡量指标来预测某个玩家当前被分配到8个联赛中的哪一个,输出变量(LeagueIndex)是一个有序的类别变量,序号从1到8,最后一个对应的是技术最高的玩家组成的联赛。
> skillcraft <- read_csv("data_set/SkillCraft1_Dataset.csv")
> attr(skillcraft, "problems") <- NULL
> attr(skillcraft, "spec") <- NULL
> str(skillcraft)
## tibble [3,395 × 20] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ GameID : num [1:3395] 52 55 56 57 58 60 61 72 77 81 ...
## $ LeagueIndex : num [1:3395] 5 5 4 3 3 2 1 7 4 4 ...
## $ Age : num [1:3395] 27 23 30 19 32 27 21 17 20 18 ...
## $ HoursPerWeek : num [1:3395] 10 10 10 20 10 6 8 42 14 24 ...
## $ TotalHours : chr [1:3395] "3000" "5000" "200" "400" ...
## $ APM : num [1:3395] 144 129 70 108 123 ...
## $ SelectByHotkeys : num [1:3395] 0.00352 0.0033 0.0011 0.00103 0.00114 ...
## $ AssignToHotkeys : num [1:3395] 0.00022 0.000259 0.000336 0.000213 0.000327 ...
## $ UniqueHotkeys : num [1:3395] 7 4 4 1 2 2 6 6 2 8 ...
## $ MinimapAttacks : num [1:3395] 1.10e-04 2.94e-04 2.94e-04 5.33e-05 0.00 ...
## $ MinimapRightClicks : num [1:3395] 0.000392 0.000432 0.000461 0.000543 0.001329 ...
## $ NumberOfPACs : num [1:3395] 0.00485 0.00431 0.00293 0.00378 0.00237 ...
## $ GapBetweenPACs : num [1:3395] 32.7 32.9 44.6 29.2 22.7 ...
## $ ActionLatency : num [1:3395] 40.9 42.3 75.4 53.7 62.1 ...
## $ ActionsInPAC : num [1:3395] 4.75 4.84 4.04 4.92 9.37 ...
## $ TotalMapExplored : num [1:3395] 28 22 22 19 15 16 15 45 29 27 ...
## $ WorkersMade : num [1:3395] 0.001397 0.001193 0.000745 0.000426 0.001174 ...
## $ UniqueUnitsMade : num [1:3395] 6 5 6 7 4 6 5 9 7 6 ...
## $ ComplexUnitsMade : num [1:3395] 0 0 0 0 0 ...
## $ ComplexAbilitiesUsed: num [1:3395] 0.00 2.08e-04 1.89e-04 3.84e-04 1.93e-05 ...
一种对待序号输出的可能方式是把它们当作一个数值型变量,作为回归任务来建模,并构建一个回归树。GameID列表示唯一的游戏标识符,跟模型无关,可以丢弃;另外TotalHours列被识别为字符型,需要修正为数值型。
> skillcraft <- skillcraft[, -1] %>%
+ mutate(TotalHours = as.numeric(TotalHours))
>
> DataExplorer::profile_missing(skillcraft)
## # A tibble: 19 x 3
## feature num_missing pct_missing
## <fct> <int> <dbl>
## 1 LeagueIndex 0 0
## 2 Age 55 0.0162
## 3 HoursPerWeek 56 0.0165
## 4 TotalHours 57 0.0168
## 5 APM 0 0
## 6 SelectByHotkeys 0 0
## 7 AssignToHotkeys 0 0
## 8 UniqueHotkeys 0 0
## 9 MinimapAttacks 0 0
## 10 MinimapRightClicks 0 0
## 11 NumberOfPACs 0 0
## 12 GapBetweenPACs 0 0
## 13 ActionLatency 0 0
## 14 ActionsInPAC 0 0
## 15 TotalMapExplored 0 0
## 16 WorkersMade 0 0
## 17 UniqueUnitsMade 0 0
## 18 ComplexUnitsMade 0 0
## 19 ComplexAbilitiesUsed 0 0
Age、HoursPerWeek和TotalHours存在缺失值,直接删除带有缺失值的行。(虽然树模型可以自动处理缺失值,但是后面还会使用其他模型来对比,那些模型不一定能处理缺失值)
> skillcraft <- na.omit(skillcraft)
> dim(skillcraft)
## [1] 3338 19
2、拆分训练集和测试集
> set.seed(123)
> ind <- createDataPartition(skillcraft$LeagueIndex, p = 0.8, list = F)
> dtrain <- skillcraft[ind, ]
> dtest <- skillcraft[-ind, ]
3、建模
使用rpart包构建回归树模型。
> set.seed(123)
> fit.rpart <- train(LeagueIndex ~ ., data = dtrain, method = "rpart")
> fit.rpart$finalModel
## n= 2672
##
## node), split, n, deviance, yval
## * denotes terminal node
##
## 1) root 2672 5577.5000 4.124626
## 2) APM< 102.5727 1214 2019.7440 3.213344
## 4) ActionLatency>=76.38525 541 686.5767 2.626617 *
## 5) ActionLatency< 76.38525 673 997.2184 3.684993 *
## 3) APM>=102.5727 1458 1710.1780 4.883402 *
4、树模型中的变量重要性
对于输入特征,我们会关注它用在树里任何地方时产生的优化准则(例如偏差或SSE)里的约简,将树里所有分裂的这个量值汇总起来,就得到变量重要性的相对数量。
越重要的变量会越早用来分裂数据(离根节点更近),也会更常用到。如果一个变量从来没有用过,那么就是不重要的,通过这种方式,可以用来做特征选择,但是这种方法对特征中的相关性敏感。
> varImp(fit.rpart)
## rpart variable importance
##
## Overall
## ActionLatency 100.00
## APM 99.44
## NumberOfPACs 75.95
## GapBetweenPACs 65.78
## SelectByHotkeys 53.74
## TotalHours 27.69
## AssignToHotkeys 0.00
## ComplexAbilitiesUsed 0.00
## MinimapAttacks 0.00
## Age 0.00
## ComplexUnitsMade 0.00
## UniqueHotkeys 0.00
## ActionsInPAC 0.00
## UniqueUnitsMade 0.00
## TotalMapExplored 0.00
## WorkersMade 0.00
## MinimapRightClicks 0.00
## HoursPerWeek 0.00
5、计算均方误差
> compute_sse <- function(correct, prediction) {
+ return(sum(correct - prediction) ^ 2)
+ }
>
> dtrain.sse <- compute_sse(predict(fit.rpart, newdata = dtrain), dtrain$LeagueIndex)
> dtest.sse <- compute_sse(predict(fit.rpart, newdata = dtest), dtest$LeagueIndex)
> tibble(train_sse = dtrain.sse, test_sse = dtest.sse)
## # A tibble: 1 x 2
## train_sse test_sse
## <dbl> <dbl>
## 1 2.75e-25 4.46
网友评论