1 Background

Ketika menyelesaikan atau sedang memainkan suatu game, ada rasa penasaran atau sekedar pertanyaan “Kirakira, ada tidak ya game seperti ini lagi?”. Alternatif yang kita cari ini bisa memberikan informasi untuk merasakan pengalaman bermain sesuai dengan preferensi kita. Mengacu pada artikel dari nationaltoday.com, tercatat saat ini ada lebih dari 5 juta games. Pastinya akan sangat mustahil jika kita mencoba atau menelusuri satu per satu 5 juta games tersebut.

Jika membandingkan antara jumlah game yang beredar saat ini dengan rata-rata waktu yang kita habiskan untuk bermain game, tentulah kita harus memilah game mana yang akan kita mainkan. Artikel pada forbes.com mengatakan rata-rata player menghabiskan 8.6 jam dalam seminggu untuk bermain video games.

“Based on data gathered from 800 gamers around the world, players spend 8.6 hours per week playing video games, roughly equating to 1.2 hours a day. Presuming this is consistent, that’s 2.5 weeks each year, and 2.8 years across the standard lifetime–around 4% of our time on Earth.”

Dari pertimbangan banyaknya jumlah game dengan rata-rata durasi yang kita habiskan untuk bermain, tentunya kita harus dapat memilah mana game yang akan kita mainkan berikutnya. Terkadang proses pemilihan ini sangatlah banyak faktor yang dipertimbangkan, mulai dari genre, fitur dalam game, rating games, review sesama player, atau bahkan developer game. Adanya sebuah sistem rekomendasi yang dapat memberikan alternatif pilihan tentunya akan sangat membantu kita untuk memilih game yang akan kita mainkan.

1.1 Project Goals

Pada project kali ini, kita akan mencoba membuat dashboard rekomendasi untuk games. Dashboard akan menerima input berupa preferensi dari player, dan memberikan output berupa sekelompok rekomendasi games yang sesuai dengan preferensi. Selain itu, dashboard juga akan memberikan informasi dari hasil Exploratory Data Analysis, misal games dengan rating positive terbanyak, atau games dengan user terbanyak.

1.2 Business Impact

Melalui project ini diharapkan dapat memberi dampak berikut:

  • Player
    • Mempersingkat waktu untuk mencari game yang sesuai dengan preferensinya
  • Developer/Creator
    • Memanfaatkan data preferensi player dalam memubuat game berikutnya
  • Team Marketing Developer/Creator
    • Memanfaatkan sistem untuk menjangkau kelompok yang belum mencoba game mereka.
    • Dapat menjadi alternatif wadah untuk advertisement pada games yang mirip

2 Data Collection

Project kali ini akan menggunakan data dari platform games, yaitu Steam. Data yang akan digunakan berasal dari Kaggle. Pada dataset ini terdapat kolom berikut:

  • appid : id dari games
  • name : nama games
  • release_date : tanggal rilis games
  • english : games tersedia dalam english
  • developer : developer dari games
  • publisher : publisher dari games
  • platforms : platform OS yang mendukung games
  • required_age : batas usia memainkan games
  • categories : kategori games
  • genres : genre dari games
  • steamspy_tags : tags dari platform steam untuk games
  • achievements : berapa banyak acheivements dari games
  • positive_ratings : jumlah rating positive yang diperoleh games
  • negative_ratings : jumlah rating negative yang diperoleh games
  • average_playtime : rata-rata waktu memainkan games
  • median_playtime : median waktu memainkan games
  • owners : rentang jumlah orang yang memiliki games
  • price : harga dari games.

Untuk model machine learning yang akan digunakan adalah K-Medoids Clustering (PAM) dan K-Means Clustering.

Catatan: Pendekatan lain yang mungkin akan digunakan, yaitu collaborative filtering/content base filtering dengan package recommenderlab jika memungkinkan.

3 Data Preparation

Data yang didapatkan masih berupa raw data, dan harus disiapkan sebelum dilanjutkan ke tahap analisis.

3.1 Library

Berikut adalah library yang akan digunakan pada propsal project ini.

#data wrangling
library(tidyverse) 
library(lubridate)

#EDA&visualisasi
library(plotly)
library(glue)

Catatan: library yang dituliskan hanya untuk kebutuhan proposal, belum memasukan library untuk project nantinya.

3.2 Data Wrangling

3.2.1 Read Files

Kita akan membaca file data dan memberi nama sebagai steam.

#read file
steam <- read.csv(file = "data/steam/steam.csv")
steam

Terdapat 27.075 baris, dan 18 kolom. Penjelasan mengenai kolom tersebut dapat merujuk pada bagian Data Collection.

3.2.2 Data Types

Terdapat kolom yang masih dalam tipe belum sesuai dan kita akan mengubah ke tipe yang lebih tepat.

str(steam)
#> 'data.frame':    27075 obs. of  18 variables:
#>  $ appid           : int  10 20 30 40 50 60 70 80 130 220 ...
#>  $ name            : chr  "Counter-Strike" "Team Fortress Classic" "Day of Defeat" "Deathmatch Classic" ...
#>  $ release_date    : chr  "2000-11-01" "1999-04-01" "2003-05-01" "2001-06-01" ...
#>  $ english         : int  1 1 1 1 1 1 1 1 1 1 ...
#>  $ developer       : chr  "Valve" "Valve" "Valve" "Valve" ...
#>  $ publisher       : chr  "Valve" "Valve" "Valve" "Valve" ...
#>  $ platforms       : chr  "windows;mac;linux" "windows;mac;linux" "windows;mac;linux" "windows;mac;linux" ...
#>  $ required_age    : int  0 0 0 0 0 0 0 0 0 0 ...
#>  $ categories      : chr  "Multi-player;Online Multi-Player;Local Multi-Player;Valve Anti-Cheat enabled" "Multi-player;Online Multi-Player;Local Multi-Player;Valve Anti-Cheat enabled" "Multi-player;Valve Anti-Cheat enabled" "Multi-player;Online Multi-Player;Local Multi-Player;Valve Anti-Cheat enabled" ...
#>  $ genres          : chr  "Action" "Action" "Action" "Action" ...
#>  $ steamspy_tags   : chr  "Action;FPS;Multiplayer" "Action;FPS;Multiplayer" "FPS;World War II;Multiplayer" "Action;FPS;Multiplayer" ...
#>  $ achievements    : int  0 0 0 0 0 0 0 0 0 33 ...
#>  $ positive_ratings: int  124534 3318 3416 1273 5250 2758 27755 12120 3822 67902 ...
#>  $ negative_ratings: int  3339 633 398 267 288 684 1100 1439 420 2419 ...
#>  $ average_playtime: int  17612 277 187 258 624 175 1300 427 361 691 ...
#>  $ median_playtime : int  317 62 34 184 415 10 83 43 205 402 ...
#>  $ owners          : chr  "10000000-20000000" "5000000-10000000" "5000000-10000000" "5000000-10000000" ...
#>  $ price           : num  7.19 3.99 3.99 3.99 3.99 3.99 7.19 7.19 3.99 7.19 ...
#change data types

steam_clean <- steam %>%
  mutate_at(
    vars(
      english,
      categories,
      platforms,
      genres,
      steamspy_tags,
      required_age,
      owners
    ), as.factor
  )

steam_clean$release_date <- ymd(steam_clean$release_date)
head(steam_clean)
steam_clean %>% 
  str()
#> 'data.frame':    27075 obs. of  18 variables:
#>  $ appid           : int  10 20 30 40 50 60 70 80 130 220 ...
#>  $ name            : chr  "Counter-Strike" "Team Fortress Classic" "Day of Defeat" "Deathmatch Classic" ...
#>  $ release_date    : Date, format: "2000-11-01" "1999-04-01" ...
#>  $ english         : Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...
#>  $ developer       : chr  "Valve" "Valve" "Valve" "Valve" ...
#>  $ publisher       : chr  "Valve" "Valve" "Valve" "Valve" ...
#>  $ platforms       : Factor w/ 7 levels "linux","mac",..: 7 7 7 7 7 7 7 7 7 7 ...
#>  $ required_age    : Factor w/ 6 levels "0","3","7","12",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ categories      : Factor w/ 3333 levels "Captions available",..: 330 330 498 330 2487 457 2292 2487 624 3062 ...
#>  $ genres          : Factor w/ 1552 levels "Accounting;Animation & Modeling;Audio Production;Design & Illustration;Education;Photo Editing;Software Trainin"| __truncated__,..: 3 3 3 3 3 3 3 3 3 3 ...
#>  $ steamspy_tags   : Factor w/ 6423 levels "1980s;Great Soundtrack;Retro",..: 225 225 2583 225 2554 225 2562 225 2554 2554 ...
#>  $ achievements    : int  0 0 0 0 0 0 0 0 0 33 ...
#>  $ positive_ratings: int  124534 3318 3416 1273 5250 2758 27755 12120 3822 67902 ...
#>  $ negative_ratings: int  3339 633 398 267 288 684 1100 1439 420 2419 ...
#>  $ average_playtime: int  17612 277 187 258 624 175 1300 427 361 691 ...
#>  $ median_playtime : int  317 62 34 184 415 10 83 43 205 402 ...
#>  $ owners          : Factor w/ 13 levels "0-20000","100000-200000",..: 4 12 12 12 12 12 12 4 12 4 ...
#>  $ price           : num  7.19 3.99 3.99 3.99 3.99 3.99 7.19 7.19 3.99 7.19 ...

Tipe data tiap kolom sudah sesuai dengan yang diinginkan.

3.2.3 Parsing Column

#parsing column
steam_parse <- steam_clean %>% 
  separate(col = platforms, into = c('windows', 'mac','linux'),sep = ";") %>% 
  separate(col = categories, into = c('categories1','categories2'),sep = ";") %>% 
  separate(col = steamspy_tags, into = c('steamtags1', 'steamtags2', 'steamtags3'), 
           sep = ";")

head(steam_parse)

Pada kolom windows, mac, dan linux dapat diubah menjadi 1 dan 0 untuk memudahkan analisis.

  • 1 jika game dapat dimainkan pada platform tersebut
  • 0 jika game tidak dapat dimainkan pada platform tersebut
#changing into 1 and 0
steam_parse$windows <- ifelse(steam_parse$windows == "windows", 1, 0)
steam_parse$mac <- ifelse(steam_parse$mac == "mac", 1, 0)
steam_parse$linux <- ifelse(steam_parse$linux == "linux", 1,0)

head(steam_parse)

3.2.4 Missing Values

Proses imputasi dibutuhkan jika terdapat missing values pada kolom.

#check missing value after parsing
colSums(is.na(steam_parse))
#>            appid             name     release_date          english 
#>                0                0                0                0 
#>        developer        publisher          windows              mac 
#>                0                0                0            18402 
#>            linux     required_age      categories1      categories2 
#>            22452                0                0             6331 
#>           genres       steamtags1       steamtags2       steamtags3 
#>                0                0              558             2665 
#>     achievements positive_ratings negative_ratings average_playtime 
#>                0                0                0                0 
#>  median_playtime           owners            price 
#>                0                0                0

Terdapat missing values untuk kolom mac dan linux yang merupakan hasil parsing dari kolom platforms. Kolom dengan value NA berarti tidak termasuk dalam mac ataupun linux, maka akan diimputasi dengan nilai 0. Untuk steamtag2 dan steamtags3 missing value disebabkan ada games yang hanya memiliki 1 tags saja, dan akan diimputasi dengan notags. Untuk categories2 missing value disebabkan ada games yang hanya memiliki 1 tags saja, dan akan diimputasi dengan nocat.

#fill NA
steam_parse_clean <- 
  steam_parse %>%
    mutate(mac = if_else(is.na(mac), 0, mac)) %>% 
    mutate(linux = if_else(is.na(linux), 0, linux)) %>% 
    mutate(steamtags2 = if_else(is.na(steamtags2), 'notags', steamtags2)) %>%
    mutate(steamtags3 = if_else(is.na(steamtags3), 'notags', steamtags3))%>%
    mutate(categories2 = if_else(is.na(categories2), 'nocat', categories2))

colSums(is.na(steam_parse_clean))
#>            appid             name     release_date          english 
#>                0                0                0                0 
#>        developer        publisher          windows              mac 
#>                0                0                0                0 
#>            linux     required_age      categories1      categories2 
#>                0                0                0                0 
#>           genres       steamtags1       steamtags2       steamtags3 
#>                0                0                0                0 
#>     achievements positive_ratings negative_ratings average_playtime 
#>                0                0                0                0 
#>  median_playtime           owners            price 
#>                0                0                0

Sudah tidak ada missing value pada dataset yang akan digunakan.

3.2.5 Data Types Parsed Column

Kolom yang merupakan hasil dari parsing belum disesuaikan tipe datanya, dan harus diubah ke tipe data yang lebih sesuai.

#changing datatypes from parsing
steam_parse_final <- steam_parse_clean %>% 
  mutate_at(
    vars(
      windows,
      mac,
      linux,
      steamtags1,
      steamtags2,
      steamtags3,
      categories1,
      categories2
    ), as.factor
  )

steam_parse_final
steam_parse_final %>%
  str()
#> 'data.frame':    27075 obs. of  23 variables:
#>  $ appid           : int  10 20 30 40 50 60 70 80 130 220 ...
#>  $ name            : chr  "Counter-Strike" "Team Fortress Classic" "Day of Defeat" "Deathmatch Classic" ...
#>  $ release_date    : Date, format: "2000-11-01" "1999-04-01" ...
#>  $ english         : Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...
#>  $ developer       : chr  "Valve" "Valve" "Valve" "Valve" ...
#>  $ publisher       : chr  "Valve" "Valve" "Valve" "Valve" ...
#>  $ windows         : Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...
#>  $ mac             : Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...
#>  $ linux           : Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...
#>  $ required_age    : Factor w/ 6 levels "0","3","7","12",..: 1 1 1 1 1 1 1 1 1 1 ...
#>  $ categories1     : Factor w/ 23 levels "Captions available",..: 11 11 11 11 16 11 16 16 16 16 ...
#>  $ categories2     : Factor w/ 26 levels "Captions available",..: 15 15 25 15 12 15 12 12 13 19 ...
#>  $ genres          : Factor w/ 1552 levels "Accounting;Animation & Modeling;Audio Production;Design & Illustration;Education;Photo Editing;Software Trainin"| __truncated__,..: 3 3 3 3 3 3 3 3 3 3 ...
#>  $ steamtags1      : Factor w/ 206 levels "1980s","1990's",..: 8 8 74 8 74 8 74 8 74 74 ...
#>  $ steamtags2      : Factor w/ 284 levels "1980s","1990's",..: 88 88 282 88 10 88 43 88 10 10 ...
#>  $ steamtags3      : Factor w/ 323 levels "1980s","1990's",..: 173 173 173 173 239 173 14 173 239 239 ...
#>  $ achievements    : int  0 0 0 0 0 0 0 0 0 33 ...
#>  $ positive_ratings: int  124534 3318 3416 1273 5250 2758 27755 12120 3822 67902 ...
#>  $ negative_ratings: int  3339 633 398 267 288 684 1100 1439 420 2419 ...
#>  $ average_playtime: int  17612 277 187 258 624 175 1300 427 361 691 ...
#>  $ median_playtime : int  317 62 34 184 415 10 83 43 205 402 ...
#>  $ owners          : Factor w/ 13 levels "0-20000","100000-200000",..: 4 12 12 12 12 12 12 4 12 4 ...
#>  $ price           : num  7.19 3.99 3.99 3.99 3.99 3.99 7.19 7.19 3.99 7.19 ...

4 Exploratory Data Analysis

Tahap ini akan membantu memahami atau mencari insight dari dataset.

summary(steam_parse_final)
#>      appid             name            release_date        english  
#>  Min.   :     10   Length:27075       Min.   :1997-06-30   0:  511  
#>  1st Qu.: 401230   Class :character   1st Qu.:2016-04-04   1:26564  
#>  Median : 599070   Mode  :character   Median :2017-08-08            
#>  Mean   : 596204                      Mean   :2016-12-31            
#>  3rd Qu.: 798760                      3rd Qu.:2018-06-06            
#>  Max.   :1069460                      Max.   :2019-05-01            
#>                                                                     
#>   developer          publisher         windows   mac       linux    
#>  Length:27075       Length:27075       0:    5   0:19013   0:22452  
#>  Class :character   Class :character   1:27070   1: 8062   1: 4623  
#>  Mode  :character   Mode  :character                                
#>                                                                     
#>                                                                     
#>                                                                     
#>                                                                     
#>  required_age              categories1                        categories2   
#>  0 :26479     Single-player      :25678   Steam Achievements        :10769  
#>  3 :   11     Multi-player       :  774   nocat                     : 6331  
#>  7 :   12     Online Multi-Player:  272   Multi-player              : 3200  
#>  12:   73     Local Multi-Player :   88   Steam Trading Cards       : 1222  
#>  16:  192     Steam Achievements :   46   Partial Controller Support:  957  
#>  18:  308     MMO                :   44   Online Multi-Player       :  942  
#>               (Other)            :  173   (Other)                   : 3654  
#>                     genres             steamtags1        steamtags2  
#>  Action;Indie          : 1852   Action      :5579   Indie     :7255  
#>  Casual;Indie          : 1482   Indie       :4713   Action    :3286  
#>  Action;Adventure;Indie: 1229   Adventure   :3176   Casual    :3151  
#>  Adventure;Indie       : 1170   Early Access:2955   Adventure :2714  
#>  Action;Casual;Indie   : 1004   Casual      :2394   Strategy  :1359  
#>  Action                :  843   Strategy    :1927   Simulation:1151  
#>  (Other)               :19495   (Other)     :6331   (Other)   :8159  
#>       steamtags3     achievements     positive_ratings  negative_ratings
#>  Indie     : 4264   Min.   :   0.00   Min.   :      0   Min.   :     0  
#>  notags    : 2665   1st Qu.:   0.00   1st Qu.:      6   1st Qu.:     2  
#>  Casual    : 2660   Median :   7.00   Median :     24   Median :     9  
#>  Adventure : 1880   Mean   :  45.25   Mean   :   1001   Mean   :   211  
#>  Action    : 1457   3rd Qu.:  23.00   3rd Qu.:    126   3rd Qu.:    42  
#>  Simulation: 1220   Max.   :9821.00   Max.   :2644404   Max.   :487076  
#>  (Other)   :12929                                                       
#>  average_playtime   median_playtime               owners          price        
#>  Min.   :     0.0   Min.   :     0.0   0-20000       :18596   Min.   :  0.000  
#>  1st Qu.:     0.0   1st Qu.:     0.0   20000-50000   : 3059   1st Qu.:  1.690  
#>  Median :     0.0   Median :     0.0   50000-100000  : 1695   Median :  3.990  
#>  Mean   :   149.8   Mean   :   146.1   100000-200000 : 1386   Mean   :  6.078  
#>  3rd Qu.:     0.0   3rd Qu.:     0.0   200000-500000 : 1272   3rd Qu.:  7.190  
#>  Max.   :190625.0   Max.   :190625.0   500000-1000000:  513   Max.   :421.990  
#>                                        (Other)       :  554

Informasi yang diperoleh dari hasil summary adalah sebagai berikut:

  • Hampir mayoritas game tidak memiliki batasan usia (required age = 0)
  • Mayoritas game menggunakan bahasa inggris (english), mungkin dikarenakan game bersifat universal
  • Steamtags indie mendapatkan jumlah terbanyak. Hal ini mungkin menandakan banyaknya developer/publisher independent pada platform Steam.
  • Hampir semua games dapat dijalankan pada platform windows. Hal ini menandakan Windows merupakan operating system yang baik jika kita ingin memainkan banyak games.

4.1 Positive Rating Games

Salah satu indikasi sebuah games yang menarik atau bagus adalah jumlah owners yang banyak dan positive ratings yang tinggi.

a <- steam_parse_final %>% 
  select(name, positive_ratings, owners) %>%
  group_by(owners) %>% 
  arrange(desc(positive_ratings)) %>%
  head(15) %>% 
  ggplot(mapping = aes(x = positive_ratings,
                       y = reorder(name, positive_ratings),
                       text = glue("Total Positive Ratings:{positive_ratings}"))) +
  geom_col(aes(fill = owners))+
  labs(title = "Highest Positive Ratings Games",
       x = "Positive Ratings",
       y = "Game Title")+
  theme_minimal()+
  scale_fill_brewer(palette = "Set3")
ggplotly(a, tooltip = "text")

Dari visualisasi menunjukan Counter Strike: Global Offensive mendapatkan positive ratings sangat tinggi walaupun jumlah owners tidak sebanyak Dota 2. Dota 2 adalah games dengan jumlah owners terbanyak.

4.2 Game Owners Count

Kita akan memeriksa bagaimana persebaran data dari pemilik games.

b <- steam_parse_final %>% 
  group_by(owners) %>% 
  summarise(count = n()) %>%
  ggplot(mapping = aes(y = reorder(owners, count),
                       x = count,
                       text = glue("Total Owners:{count}"))) +
  geom_col(fill = "dodgerblue3")+
  labs(title = "Owners Count",
       x = "Total Count",
       y = "Owners Range")+
  theme_minimal()
ggplotly(b, tooltip = "text")

Rentang pemilik mayoritas games ada pada angka 0 - 20 ribu. Hanya beberapa games saja yang dimiliki lebih dari 5 juta player.

Catatan: Kita dapat memfilter data lebih lanjut untuk mendapatkan games dengan pemilik pada rentang diatas 5 juta player dan memberi label data tersebut sebagai game populer.

4.3 Platforms Count

Beberapa games dapat dimainkan hanya dengan platform operating system tertentu saja, tapi seperti yang kita tahu secara umum operating system Windows hampir dapat memainkan seluruh games.

steam_clean %>%
  group_by(platforms) %>% 
  summarise(count = n())

Mayoritas games dapat dimainkan oleh windows, dan hanya sedikit game yang hanya dapat dimainkan pada platform linux saja atau mac saja.

4.4 Game Price with Playtime

Beberapa games harus dibeli terlebih dahulu sebelum dapat kita mainkan. Games dengan harga 0 berarti dapat dimainkan secara gratis, namun games yang memiliki data harga maka harus dibeli dahulu.

#membuat kolom keterangan tambahan
steam_parse_final$details <- ifelse(steam_parse_final$price == 0.00, "Free","Purchase")

steam_parse_final %>% 
  group_by(details) %>% 
  summarise(count = n())

Terdapat 2560 games yang gratis, dan 24515 games yang harus dibeli jika ingin dimainkan. Lalu apakah ada perbedaan perilaku dalam bermain antara games gratis dengan games yang dibeli? Kita akan melihat dari sisi playtime.

steam_parse_final %>% 
  group_by(details) %>% 
  summarise(playtime = mean(median_playtime))

Secara rata-rata dapat kita lihat bahwa durasi bermain (playtime) lebih tinggi pada games yang gratis dibanding games yang berbayar. Tapi karena pendekatan yang kita gunakan adalah rata-rata, dan jumlah games antara free dan purchase sangatlah timpang (beda jauh), maka kesimpulan ini masih perlu ditelaah kembali.

5 Dashboard Design

Berikut adalah rencana tampilan dashboard yang akan dibuat. Dashboard akan berisi 3 menu utama, yaitu :

  • Main Page : Sebagai tempat landing user pertama, berisi informasi secara umum mengenai dashboard dan cara menggunakannya.
  • Find Games : Tempat untuk mencari games sesuai dengan preferensi player.
  • About : Berisi mengenai proses machine learning, hasil dari EDA yang menarik untuk ditampilkan, serta data utama yang digunakan.