Call of Duty

Tentang Games

Call of Duty merupakan salah satu permainan populer yang sudah ada sejak console playstation 2, dengan berkembangnya jaman Call of Duty (COD) mulai masuk ke dalam ranah yang lebih luas yaitu secara online. Hal tersebut memberikan kenyamanan pemain untuk berinteraksi dengan pemain lainnya. Perkembangan game yang sangat cepat juga memunculkan kompetisi baru bertema game online. Saat ini terdapat beberapa tim yang sering berkompetisi pada permainan yang memiliki kemiripan tipe permainan dengan COD. Sebagai salah satu tim e-sport sangat penting untuk dapat merekrut pemain yang memang diatas rata-rata pemain lain untuk memiliki kontrak profesional. Sebagai data scientist, kebutuhan dari tim e-sport tersebut dapat dibantu oleh machine learning untuk mengelompokkan permainan suatu pemain sehingga tim tersebut dapat memilih pemain yang dapat mewakili dalam suatu kompetisi.

Data

Data berisi beberapa kolom penting untuk mengelompokkan pemain yang berada diatas rata-rata antara lain

  1. name : berisi nama pemain dalam game dan kode pemain
  2. wins : jumlah kemenangan dalam permainan
  3. kdRation : perbandingan jumlah membunuh dan terbunuh dalam game
  4. killstreak : jumlah pemain membunuh berturut-turut tanpa terbunuh
  5. losses : jumlah kekalan dalam permainan
  6. timePlayed : jumlah waktu bermain pemain dalam jam
  7. Gameplayed : Jumlah permainan yang telah dimainkan
  8. headshot : jumlah pemain membunuh dengan tepat menembak pada bagian kepala
  9. kills : jumlah membunuh dalam permainan
  10. jumlah : jumlah terbunuh dalam permainan

Data Preparation

Library

Sebelum mengolah data kita perlu memanggil library dan package yang nantinya kita gunakan dalam analisis dan membuat machine learning.

library(dplyr)
library(tidyverse)
library(cluster)
library(factoextra)
library(GGally)
library(scales)
library(cowplot)
library(FactoMineR)
library(factoextra)
library(plotly)

Persiapan Data

Pertama kita harus memanggil data dan melihat struktur dari data yang kita miliki.

cod <- read.csv("cod.csv")
glimpse(cod)
## Rows: 1,558
## Columns: 19
## $ name           <chr> "RggRt45#4697369", "JohniceRex#9176033", "bootybootykil~
## $ wins           <int> 0, 0, 0, 3, 0, 684, 4, 186, 741, 26, 0, 0, 188, 0, 15, ~
## $ kills          <int> 0, 0, 66, 2, 2, 27011, 162, 1898, 21803, 349, 0, 26, 19~
## $ kdRatio        <dbl> 0.0000000, 0.0000000, 1.0312500, 0.4000000, 0.2000000, ~
## $ killstreak     <int> 0, 0, 0, 0, 0, 18, 4, 13, 26, 7, 0, 0, 22, 0, 7, 10, 17~
## $ level          <int> 1, 1, 9, 1, 1, 177, 6, 37, 185, 12, 1, 6, 53, 1, 5, 40,~
## $ losses         <int> 0, 0, 0, 0, 0, 10, 2, 7, 29, 4, 0, 0, 4, 0, 4, 9, 11, 1~
## $ prestige       <int> 0, 110, 110, 0, 110, 110, 0, 2, 111, 0, 0, 110, 57, 0, ~
## $ hits           <int> 0, 0, 0, 0, 0, 98332, 568, 5111, 81361, 996, 0, 0, 3333~
## $ timePlayed     <int> 0, 7, 32, 3, 5, 1366, 8, 550, 2442, 44, 0, 37, 409, 1, ~
## $ headshots      <int> 0, 0, 16, 0, 1, 5113, 35, 485, 3894, 40, 0, 3, 536, 0, ~
## $ averageTime    <dbl> 0.000000, 7.000000, 32.000000, 3.000000, 5.000000, 2.32~
## $ gamesPlayed    <int> 0, 0, 0, 0, 0, 588, 4, 150, 864, 15, 0, 0, 25, 0, 6, 12~
## $ assists        <int> 0, 0, 1, 0, 0, 6063, 68, 488, 4029, 138, 0, 4, 150, 0, ~
## $ misses         <int> 0, 0, 0, 0, 0, 305319, 4836, 39978, 327230, 4844, 0, 0,~
## $ xp             <int> 0, 700, 48300, 1150, 1000, 3932335, 24485, 458269, 4269~
## $ scorePerMinute <dbl> 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 255.67204,~
## $ shots          <int> 0, 0, 0, 0, 0, 403651, 5404, 45089, 408591, 5840, 0, 0,~
## $ deaths         <int> 0, 16, 64, 5, 10, 25321, 256, 3332, 21032, 786, 0, 77, ~

kita memilki 19 kolom dengan satu kolom nama yang bersifat character sedangkan yang lainnya numeric. Tipe data yang kita lihat sudah sesuai dengan apa yang kita butuhkan sehingga tidak diperlukan pengubahan tipe data. Namun sebelum menggunakan data kita harus memastikan data tidak memiliki nilai NA.

colSums(is.na(cod))
##           name           wins          kills        kdRatio     killstreak 
##              0              0              0              0              0 
##          level         losses       prestige           hits     timePlayed 
##              0              0              0              0              0 
##      headshots    averageTime    gamesPlayed        assists         misses 
##              0              0              0              0              0 
##             xp scorePerMinute          shots         deaths 
##              0              0              0              0

Kita tidak menemukan adanya nilai NA pada data kita, oleh karena itu kita dapat melakukan analisis dan eksploratory data sebelum membuat machine learning yang membantu mengelompokan dan mengidentifikasi pemain yang memiliki potensi menjadi pemain profesional.

EDA

Mari kita lakukan sedikit eksploratori dan analisis data. Orang yang memiliki permainan yang baik pasti memiliki tingkat kills tinggi dan death yang rendah sehingga bisa kita lihat dari kdRation. Kita urutkan pemain menurut kdRatio yang nanti dapat kita pastikan dalam machine learning berada pada kelompok yang pemain diatas rata-rata.

cod_kd <- cod[order(cod$kdRatio, decreasing = T),]
cod_kd %>% head(10)
ggplot(cod_kd[1:10,], aes(x = kdRatio, y = reorder(name, kdRatio))) +
  geom_col(aes(fill = kdRatio))+
  scale_fill_gradient(high = "#173F5f",
                      low = "#3caea3") +
  geom_label(mapping = aes(label = kdRatio), 
            data = cod_kd[1:3,],
            nudge_x = 0.15, 
            size = 4) +
  labs(
    title = "Top 10 Pemain",
    subtitle = "Berdasarkan nilai Kill Death Ratio",
    y = "Nama Pemain"
  ) +
  geom_vline(data = cod_kd, aes(xintercept = mean(kdRatio)))

Dari grafik tersebut terlihat bahwa akun dengan nama Lucky, Shadow9World, dan black bird memiliki kdRatio paling tinggi dibanding pemain lain. Sedangkan garis hitam menunjukkan rata-rata kdRatio semua pemain.

hist(cod$timePlayed)

Pada histogram tersebut terlihat jelas tidak banyak pemain yang bermain lebih dari 2000 jam dan paling banyak berada pada kisaran 0-400 jam saja.

plot(cod$gamesPlayed, cod$level)

Kita pasti berpikir bahwa lamanya waktu bermain juga seiring dengan tingginya level yang dimiliki pemain, namun haltersebut juga berkaitan pada cara bermain dan jumlah kemenangan pemain untuk menambah xp setiap levelnya. Terdapat salah satu akun yang memiliki waktu bermain paling tinggi (>3000 jam) namun levelnya tidak terlalu tinggi dibandingkan beberapa pemain yang bermain yang di dalam persebaran rata-rata (< 1000 jam) namun memiliki level yang lebih tinggi atau setara.

boxplot(cod$kdRatio)

Sebelumnya kita telah membuat urutan 10 pemain tertinggi dalam kdRatio, mari kita lihat persebarannya dalam boxplot. Tentu beberapa diantara 10 pemain sebelumnya menjadi outlier tersebut. Rerata pemain memiliki kdRatio dibawah 1.

hist(cod$killstreak)

Dari histogram killstreak kita dapat mengetahui bahwa rerata pemain memiliki killstreak diantara 0 - 20, sedangkan beberapa orang yang lebih baik bermainnya memiliki killstreak lebih dari 20.

ggplot(cod, aes(x = kills, y = deaths, size = gamesPlayed)) + 
    geom_point(alpha = 0.5) + theme_minimal() +
  labs(title = "Kills vs Deaths")

Pada grafik terhilat bahwa Kills yang meningkat juga diikuti oleh deaths yang meningkat dan pada tingkatan yang tinggi menunjukkan banyak permainan yang sudah dijalani pemain. Salah satu pemain denga kills tertinggi memiliki deaths yang lebih rendah dibanding beberapa pemain dengan kills sebanyak 6000. Dari grafik tersebut juga terlihat persebaran yang jelas antara pemain yang memiliki kemampuan bermain baik berdasarkan jumlah kills maupun deaths. Kita ingin mengelompokkan minimal 3 kelompok pemain dengan target utama mendapatkan pemain-pemain yang memiliki kemampuan diatas rata-rata

Modeling

Scale

Setelah melakukan eksploratori dan analisis data kita mendapat informasi yang sangat beragam, untuk menjawab tujuan kita untuk menemukan pemain dengan kemampuan diatas rata-rata maka kita akan membuat machine learning secara unsupervised dari semua data. Sebelumnya kita perlu melakukan “scaling” atau penyamaan sebaran nilai sehingga memudahkan model dalam mempelajari data.

cod_s <- cod %>% remove_rownames %>% column_to_rownames(var="name") %>% 
  scale()

K-means

Setelah proses “scaling” maka kita ingin melihat rekomendasi berdasarkan grafik untuk melihat jumlah kelompok yang bisa kita bedakan sebagai landasan untuk mesin kita.

fviz_nbclust(cod_s,
             FUNcluster = kmeans,
             method = "wss")

seperti kita lihat dari grafik bahwa secara optimal kita dapat membagi menjadi 6 kelompok berbeda untuk mendapatkan 6 kelompok dengan ciri-ciri yang berbeda. Namun berdasarkan apa yang kita ingin ketahui dari data tersebut, kita ingin mengelompokkan menjadi 3 kelompok saja. Kita buat kedua model

kita melakukan pengelompokkan data dengan rekomendasi jumlah kelompok 5 terlebih dahulu.

cod_cl <- kmeans(cod_s, centers = 6)
cod$clu <- cod_cl$cluster
cod %>% 
  group_by(clu) %>% 
  summarise_all(mean)
## Warning in mean.default(name): argument is not numeric or logical: returning NA

## Warning in mean.default(name): argument is not numeric or logical: returning NA

## Warning in mean.default(name): argument is not numeric or logical: returning NA

## Warning in mean.default(name): argument is not numeric or logical: returning NA

## Warning in mean.default(name): argument is not numeric or logical: returning NA

## Warning in mean.default(name): argument is not numeric or logical: returning NA

Dari clustering kita dapat kategorikan menjadi 6, dari keenam kelompok terdapat satu kelompok yang paling menonjol yaitu kelompok nomor 5 dengan kdRatio dan killstreak paling menonjol dibanding kelompok lain.

fviz_cluster(object = cod_cl,
             data = cod_s)

Selanjutnya kita coba menggunakan k dengan nilai 3 sesuai dengan kebutuhan kita ingin mengelompokkan pemain yang berada diatas rata-rata, pemain biasa, dan pemain baru.

cod_cl_1 <- kmeans(cod_s, centers = 3)
cod$cl1 <- cod_cl_1$cluster
cod %>% 
  group_by(cl1) %>% 
  select(-20) %>% 
  summarise_all(mean)
## Warning in mean.default(name): argument is not numeric or logical: returning NA

## Warning in mean.default(name): argument is not numeric or logical: returning NA

## Warning in mean.default(name): argument is not numeric or logical: returning NA

Kelompok 1 menunjukkan nilai kdRatio, killstreak, level, dan wins paling tinggi dibanding kelompok lain sedangkan kelompok 2 memiliki nilai terendah di semua kriteria kecuali averageTime. Dari hal tersebut kita melihat bahwa kelompok 1 memiliki kemampuan yang lebih baik dengan jem terbang bermain yang juga lebih tinggi sehingga dapat dikatakan berpengalaman. sedangkan pemain baru dikategorikan pada kelompok 2 sedangkan pemain yang biasa berada pada kelompok 3.

fviz_cluster(object = cod_cl_1,
             data = cod_s)

Dari kedua hasil k-means terlihat bahwa pembagian cluster berdasarkan rekomendasi grafik (k=6) dapat membagi kelompok dengan baik sehingga memiliki karakter-karater spesifik. Dengan begitu kita dapat melihat manakah kelompok yang memenuhi persyaratan kita untuk menjadi pemain profesional.

PCA

Selanjutnya kita akan mencoba melakukan PCA yaitu salah satu tahap untuk mereduksi dimensi data namun tetap dapat mengambil informasi sebanyak-banyaknya.

cod_pca_2 <- PCA(cod %>% select(c(-name, -clu, -cl1)), scale.unit = T, ncp = 18, graph = F, 
    quali.sup = 18)

summary(cod_pca_2)
## 
## Call:
## PCA(X = cod %>% select(c(-name, -clu, -cl1)), scale.unit = T,  
##      ncp = 18, quali.sup = 18, graph = F) 
## 
## 
## Eigenvalues
##                        Dim.1   Dim.2   Dim.3   Dim.4   Dim.5   Dim.6   Dim.7
## Variance              11.211   1.458   1.411   0.717   0.509   0.460   0.435
## % of var.             65.949   8.574   8.297   4.217   2.991   2.707   2.556
## Cumulative % of var.  65.949  74.523  82.821  87.038  90.029  92.736  95.292
##                        Dim.8   Dim.9  Dim.10  Dim.11  Dim.12  Dim.13  Dim.14
## Variance               0.307   0.246   0.089   0.044   0.041   0.023   0.021
## % of var.              1.807   1.449   0.524   0.256   0.241   0.137   0.121
## Cumulative % of var.  97.099  98.548  99.072  99.328  99.569  99.707  99.828
##                       Dim.15  Dim.16  Dim.17
## Variance               0.018   0.012   0.000
## % of var.              0.104   0.068   0.000
## Cumulative % of var.  99.932 100.000 100.000
## 
## Individuals (the 10 first)
##                    Dist    Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3
## 1              |  2.762 | -2.250  0.029  0.664 | -0.733  0.024  0.070 | -1.319
## 2              |  2.862 | -1.962  0.022  0.470 | -1.244  0.068  0.189 | -0.220
## 3              |  2.571 | -1.550  0.014  0.364 | -0.662  0.019  0.066 |  1.117
## 4              |  2.389 | -2.106  0.025  0.777 | -0.464  0.009  0.038 | -0.848
## 5              |  2.653 | -1.891  0.020  0.508 | -1.091  0.052  0.169 | -0.005
## 6              |  9.138 |  8.637  0.427  0.894 | -0.218  0.002  0.001 | -1.176
## 7              |  2.317 | -1.515  0.013  0.427 |  1.320  0.077  0.325 | -0.378
## 8              |  1.396 | -0.115  0.000  0.007 |  0.980  0.042  0.493 | -0.323
## 9              |  9.369 |  9.137  0.478  0.951 |  0.341  0.005  0.001 | -0.118
## 10             |  2.171 | -1.377  0.011  0.402 |  1.266  0.071  0.340 | -0.467
##                   ctr   cos2  
## 1               0.079  0.228 |
## 2               0.002  0.006 |
## 3               0.057  0.189 |
## 4               0.033  0.126 |
## 5               0.000  0.000 |
## 6               0.063  0.017 |
## 7               0.007  0.027 |
## 8               0.005  0.053 |
## 9               0.001  0.000 |
## 10              0.010  0.046 |
## 
## Variables (the 10 first)
##                   Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3    ctr
## wins           |  0.931  7.731  0.867 | -0.075  0.383  0.006 | -0.074  0.383
## kills          |  0.972  8.433  0.945 | -0.077  0.409  0.006 | -0.130  1.207
## kdRatio        |  0.507  2.290  0.257 |  0.370  9.415  0.137 |  0.581 23.912
## killstreak     |  0.592  3.128  0.351 |  0.435 12.987  0.189 |  0.300  6.383
## level          |  0.920  7.548  0.846 | -0.155  1.638  0.024 |  0.181  2.323
## losses         |  0.724  4.671  0.524 |  0.319  6.964  0.102 |  0.231  3.786
## prestige       |  0.451  1.814  0.203 | -0.269  4.955  0.072 |  0.590 24.638
## hits           |  0.945  7.966  0.893 | -0.031  0.064  0.001 | -0.197  2.749
## timePlayed     |  0.927  7.670  0.860 | -0.195  2.618  0.038 |  0.061  0.268
## headshots      |  0.958  8.187  0.918 | -0.072  0.355  0.005 | -0.098  0.681
##                  cos2  
## wins            0.005 |
## kills           0.017 |
## kdRatio         0.337 |
## killstreak      0.090 |
## level           0.033 |
## losses          0.053 |
## prestige        0.348 |
## hits            0.039 |
## timePlayed      0.004 |
## headshots       0.010 |
## 
## Supplementary categories (the 10 first)
##                     Dist     Dim.1    cos2  v.test     Dim.2    cos2  v.test  
## 0              |   2.742 |  -2.243   0.669 -10.491 |  -0.729   0.071  -9.455 |
## 1              |   2.229 |  -2.040   0.837  -2.449 |  -0.288   0.017  -0.960 |
## 2              |   2.292 |  -2.066   0.812  -4.150 |  -0.510   0.050  -2.844 |
## 3              |   2.336 |  -2.088   0.799  -1.876 |  -0.604   0.067  -1.505 |
## 4              |   2.265 |  -2.047   0.817  -2.608 |  -0.628   0.077  -2.219 |
## 5              |   2.347 |  -2.100   0.800  -1.989 |  -0.530   0.051  -1.392 |
## 6              |   2.197 |  -2.025   0.849  -2.353 |  -0.499   0.052  -1.608 |
## 7              |   2.285 |  -2.061   0.813  -1.745 |  -0.511   0.050  -1.199 |
## 8              |   2.389 |  -2.113   0.782  -1.673 |  -0.639   0.072  -1.403 |
## 9              |   2.218 |  -2.020   0.829  -1.913 |  -0.513   0.053  -1.346 |
##                  Dim.3    cos2  v.test  
## 0               -1.297   0.224 -17.101 |
## 1               -0.736   0.109  -2.492 |
## 2               -0.704   0.094  -3.985 |
## 3               -0.813   0.121  -2.060 |
## 4               -0.619   0.075  -2.223 |
## 5               -0.835   0.126  -2.229 |
## 6               -0.640   0.085  -2.096 |
## 7               -0.800   0.123  -1.910 |
## 8               -0.856   0.128  -1.911 |
## 9               -0.537   0.059  -1.435 |

Kita ingin menggunakan dimensi yang masih mengandung data lebih dari 90%. sehingga kita menggunakan dimensi 1 sampai 5. Grafik berikut akan menunjukkan seberapa banyak informasi yang terseimpan dari tiap dimensi.

fviz_eig(cod_pca_2, addlabels = T, main = "Variance explained by each dimensions")

dimensi 1 selalu mengandung paling banyak informasi namun untuk memenuhi syarat yang kita gunakan yaitu minimal 90% harus menggunakan dimensi 1 hingga 5.

Setelah kita tentukan jumlah dimensi, kemudian kita memasukan kolom cluster yang berasal dari proses K-means untuk mempermudah kita mengelompokkan data.

df_pca <- data.frame(cod_pca_2$ind$coord[, 1:5]) %>% bind_cols(cluster = as.factor(cod$clu)) %>% 
    select(cluster, 1:5)
df_pca

Dengan prediktor yang sudah direduksi dimensinya kita dapat melihat kontribusi dari tiap prediktor terhadap dimensi yang kita ambil.

fviz_pca_var(cod_pca_2, select.var = list(contrib = 18), col.var = "contrib", 
    gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), repel = TRUE)
## Warning: ggrepel: 8 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

Grafik menarik tersebut menunjukkan beberapa prediktor yang paling berkontribusi/mempengaruhi. PC2 dipengaruhi oleh averageTime, prestige, scorePerMinute, killstreak, kdRatio, dan losses sedangkan cariabel lain mempengaruhi PC1. Untuk melihat lebih jelas kita dapat membuat histogram seperti berikut ini.

fviz_cos2(cod_pca_2, choice = "var", fill = "cos2") + scale_fill_viridis_c(option = "A")

Yang paling berperan dalam hasil PCA kita adalah kolom kills, headshots, shots, misses, hits, assists, wins, gamesPLayed, level, timePlayed, dan xp sedangkan yang berkontribusi paling kecil adalah averageTime. Berdasarkan data kita juga dapat melihat bahwa kolom yang kita gunakan sebagai acuan menentukan level (kdRatio) tidak memiliki kontribusi yang signifikan.

fviz_cluster(object = cod_cl, data = cod[,-1], labelsize = 0) + theme_minimal()

Berdasarkan label yang berasal dari k-means dan hasil PCA didapatkan pengelompokkan yang lebih baik secara visual dibandingkan plot dari k-means sebelumnya. Dari hasil k-means, nilai win tertinggi dimiliki oleh cluster 5 yang tergambarkan berwarna biru pada grafik.

Grafik berikut membantu kita melihat jelassecara 3 dimensi persebaran dan pengelompokan data kita.

plot_ly(df_pca, x = ~Dim.1, y = ~Dim.2, z = ~Dim.3, color = ~cluster, colors = c("black", "red", "yellow", "orange",
    "green", "blue")) %>% add_markers() %>% layout(scene = list(xaxis = list(title = "Dim.1"), 
    yaxis = list(title = "Dim.2"), zaxis = list(title = "Dim.3")))

Kesimpulan

Dari data serta pengolahan dengan metode k-means serta PCA dapat kita simpulkan bahwa

  1. Pengelompokkan paling baik dibagi menjadi 6 dengan dapat mendefinisikan salah satu cluster memiliki potensi paling tinggi untuk menjadi pemain profesional.

  2. Berdasarkan pengelompokkan yang sudah dilakukan, kelompok dengan potensipaling tinggi dapat menjadi pemain profesional adalah kelompok 5 dengan variable wins, Kills, serta kdRatio tertinggi.

  3. Penggunaan metode PCA membantu kita mereduksi dari sebelumnya 18 kolom menjadi 5 kolom baru yang dapat mencakup 90 % data. Dengan metode PCA kita dapat melihat lebih jelas pengelompokan yang terbentuk.