setwd("~/rtemp/LBB2")
library(tidyverse)
library(ggplot2)
library(lubridate)
library(stringr)

Berikut LBB 2 - Steam Games yang fokus pada data visualisasi. Dataset Steam Games disediakan oleh The Devestator di Kaggle. Dataset bisa diunduh di Kaggle.

Dataset Steam Games adalah kumpulan video games yang memiliki informasi rating metacritic, harga, dan jumlah rekomendasi. Tersedia juga informasi mengenai jenis genre video game-nya.

Dataset steam

steam <- read_csv('games-features-edit.csv') |> na.omit()
str(steam)
## tibble [12,538 × 19] (S3: tbl_df/tbl/data.frame)
##  $ ResponseName               : chr [1:12538] "Counter-Strike" "Team Fortress Classic" "Day of Defeat" "Deathmatch Classic" ...
##  $ ReleaseDate                : chr [1:12538] "Nov 1 2000" "Apr 1 1999" "May 1 2003" "Jun 1 2001" ...
##  $ Metacritic                 : num [1:12538] 88 0 79 0 0 0 96 65 65 71 ...
##  $ RecommendationCount        : num [1:12538] 68991 2439 2319 888 2934 ...
##  $ IsFree                     : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsNonGame             : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsIndie               : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsAction              : logi [1:12538] TRUE TRUE TRUE TRUE TRUE TRUE ...
##  $ GenreIsAdventure           : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsCasual              : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsStrategy            : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsRPG                 : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsSimulation          : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsEarlyAccess         : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsFreeToPlay          : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsSports              : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsRacing              : logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsMassivelyMultiplayer: logi [1:12538] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ PriceInitial               : num [1:12538] 9.99 4.99 4.99 4.99 4.99 4.99 9.99 9.99 9.99 4.99 ...
##  - attr(*, "na.action")= 'omit' Named int [1:86] 263 264 265 266 338 449 530 573 621 633 ...
##   ..- attr(*, "names")= chr [1:86] "263" "264" "265" "266" ...

Dari pembacaan str(...) diketahui terdapat 19 variabel/kolom dan 12,624 observasi. Kolom ResponseName merupakan nama Video Games. Penjelasan kolom lainnya, rasanya tidak diperlukan dikarenakan nama kolom cukup deskriptif dan jelas untuk dipahami.

Di halaman Kaggle tidak ada informasi mengenai harga regional yang digunakan. Jadi diasumsikan bahwa harga yang tersedia merupakan harga regional di US.

Dikarenakan dataset memiliki informasi tanggal, saya akan membuatkan kolom terpisah dimana informasi tanggal tersebut terbagi menjadi hari, bulan, dan tahun. Hal ini digunakan untuk memvisualisasikan ketika ingin berbicara spesifik mengenai hari/bulan/tahun tertentu saja.

Berikut asumsi yang digunakan untuk visualisasi di LBB ini:

  • Baris yang memiliki <NA> akan langsung dihapus dari dataset.
  • Tanggal yang gagal di parsing akan dihapus dari dataset. Tanggal tersebut yang tidak teridentifikasi. Contohnya, "Coming Soon", "Q4 2022", dll.
  • Nama game yang sama akan dihapus dari dataset.
  • Sebelum melakukan visualisasi, dipastikan tidak ada baris yang memiliki nilai <NA>.
order_format <- c(
  "Y", "B Y", "b d Y"
)
steam_clean <- steam |> 
  mutate(
    OldReleaseDate = ReleaseDate,
  ) |> 
  mutate(
    ReleaseDate = parse_date_time(OldReleaseDate, order_format),
    TempReleaseYear = year(ReleaseDate),
    ReleaseDate = if_else(
      TempReleaseYear <= 18, 
      parse_date_time(OldReleaseDate, "B Y"), 
      ReleaseDate
    )
  ) |> 
  na.omit() |> 
  distinct(ResponseName, .keep_all = TRUE) |> 
  select(-c(TempReleaseYear, OldReleaseDate))
str(steam_clean)
## tibble [12,159 × 19] (S3: tbl_df/tbl/data.frame)
##  $ ResponseName               : chr [1:12159] "Counter-Strike" "Team Fortress Classic" "Day of Defeat" "Deathmatch Classic" ...
##  $ ReleaseDate                : POSIXct[1:12159], format: "2000-11-01" "1999-04-01" ...
##  $ Metacritic                 : num [1:12159] 88 0 79 0 0 0 96 65 71 96 ...
##  $ RecommendationCount        : num [1:12159] 68991 2439 2319 888 2934 ...
##  $ IsFree                     : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsNonGame             : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsIndie               : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsAction              : logi [1:12159] TRUE TRUE TRUE TRUE TRUE TRUE ...
##  $ GenreIsAdventure           : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsCasual              : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsStrategy            : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsRPG                 : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsSimulation          : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsEarlyAccess         : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsFreeToPlay          : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsSports              : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsRacing              : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsMassivelyMultiplayer: logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ PriceInitial               : num [1:12159] 9.99 4.99 4.99 4.99 4.99 4.99 9.99 9.99 4.99 9.99 ...
##  - attr(*, "na.action")= 'omit' Named int [1:223] 2492 2628 2675 2938 3059 3103 3269 3325 3552 3556 ...
##   ..- attr(*, "names")= chr [1:223] "2492" "2628" "2675" "2938" ...
colSums(is.na(steam_clean))
##                ResponseName                 ReleaseDate 
##                           0                           0 
##                  Metacritic         RecommendationCount 
##                           0                           0 
##                      IsFree              GenreIsNonGame 
##                           0                           0 
##                GenreIsIndie               GenreIsAction 
##                           0                           0 
##            GenreIsAdventure               GenreIsCasual 
##                           0                           0 
##             GenreIsStrategy                  GenreIsRPG 
##                           0                           0 
##           GenreIsSimulation          GenreIsEarlyAccess 
##                           0                           0 
##           GenreIsFreeToPlay               GenreIsSports 
##                           0                           0 
##               GenreIsRacing GenreIsMassivelyMultiplayer 
##                           0                           0 
##                PriceInitial 
##                           0

Informasi Tambahan

Ditambahkan informasi tambahan untuk tanggal ReleaseDate menjadi hari, bulan, dan tahun. Untuk memudahkan nanti visualisasi terhadap hari/bulan/tahun tertentu.

steam_complete <- steam_clean |> 
  mutate(
    ReleaseYear = year(ReleaseDate),
    ReleaseMonth = month(ReleaseDate),
    ReleaseMonthLabel = month(ReleaseDate, label = TRUE),
    ReleaseMonthFull = month(ReleaseDate, label = TRUE, abbr = FALSE),
    ReleaseDay = day(ReleaseDate),
    ReleaseWDay = wday(ReleaseDate),
    ReleaseWDayLabel = wday(ReleaseDate, label = TRUE),
    ReleaseWDayFull = wday(ReleaseDate, label = TRUE, abbr = FALSE)
  )
steam_complete |> head(10)

Rekapan Data

str(steam_complete)
## tibble [12,159 × 27] (S3: tbl_df/tbl/data.frame)
##  $ ResponseName               : chr [1:12159] "Counter-Strike" "Team Fortress Classic" "Day of Defeat" "Deathmatch Classic" ...
##  $ ReleaseDate                : POSIXct[1:12159], format: "2000-11-01" "1999-04-01" ...
##  $ Metacritic                 : num [1:12159] 88 0 79 0 0 0 96 65 71 96 ...
##  $ RecommendationCount        : num [1:12159] 68991 2439 2319 888 2934 ...
##  $ IsFree                     : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsNonGame             : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsIndie               : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsAction              : logi [1:12159] TRUE TRUE TRUE TRUE TRUE TRUE ...
##  $ GenreIsAdventure           : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsCasual              : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsStrategy            : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsRPG                 : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsSimulation          : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsEarlyAccess         : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsFreeToPlay          : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsSports              : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsRacing              : logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ GenreIsMassivelyMultiplayer: logi [1:12159] FALSE FALSE FALSE FALSE FALSE FALSE ...
##  $ PriceInitial               : num [1:12159] 9.99 4.99 4.99 4.99 4.99 4.99 9.99 9.99 4.99 9.99 ...
##  $ ReleaseYear                : num [1:12159] 2000 1999 2003 2001 1999 ...
##  $ ReleaseMonth               : num [1:12159] 11 4 5 6 11 11 11 3 6 11 ...
##  $ ReleaseMonthLabel          : Ord.factor w/ 12 levels "Jan"<"Feb"<"Mar"<..: 11 4 5 6 11 11 11 3 6 11 ...
##  $ ReleaseMonthFull           : Ord.factor w/ 12 levels "January"<"February"<..: 11 4 5 6 11 11 11 3 6 11 ...
##  $ ReleaseDay                 : int [1:12159] 1 1 1 1 1 1 8 1 1 16 ...
##  $ ReleaseWDay                : num [1:12159] 4 5 5 6 2 4 1 2 6 3 ...
##  $ ReleaseWDayLabel           : Ord.factor w/ 7 levels "Sun"<"Mon"<"Tue"<..: 4 5 5 6 2 4 1 2 6 3 ...
##  $ ReleaseWDayFull            : Ord.factor w/ 7 levels "Sunday"<"Monday"<..: 4 5 5 6 2 4 1 2 6 3 ...
##  - attr(*, "na.action")= 'omit' Named int [1:223] 2492 2628 2675 2938 3059 3103 3269 3325 3552 3556 ...
##   ..- attr(*, "names")= chr [1:223] "2492" "2628" "2675" "2938" ...

Terdapat \(12,519\) observasi/baris pada dataset steam_complete.

summary(steam_complete)
##  ResponseName        ReleaseDate                       Metacritic   
##  Length:12159       Min.   :1997-06-30 00:00:00.00   Min.   : 0.00  
##  Class :character   1st Qu.:2014-07-01 00:00:00.00   1st Qu.: 0.00  
##  Mode  :character   Median :2015-09-23 00:00:00.00   Median : 0.00  
##                     Mean   :2014-12-27 06:18:08.97   Mean   :12.85  
##                     3rd Qu.:2016-06-16 00:00:00.00   3rd Qu.: 0.00  
##                     Max.   :2018-02-01 00:00:00.00   Max.   :96.00  
##                                                                     
##  RecommendationCount   IsFree        GenreIsNonGame  GenreIsIndie   
##  Min.   :      0     Mode :logical   Mode :logical   Mode :logical  
##  1st Qu.:      0     FALSE:11224     FALSE:11870     FALSE:5115     
##  Median :      0     TRUE :935       TRUE :289       TRUE :7044     
##  Mean   :   1200                                                    
##  3rd Qu.:    272                                                    
##  Max.   :1427633                                                    
##                                                                     
##  GenreIsAction   GenreIsAdventure GenreIsCasual   GenreIsStrategy
##  Mode :logical   Mode :logical    Mode :logical   Mode :logical  
##  FALSE:7077      FALSE:8252       FALSE:8985      FALSE:9743     
##  TRUE :5082      TRUE :3907       TRUE :3174      TRUE :2416     
##                                                                  
##                                                                  
##                                                                  
##                                                                  
##  GenreIsRPG      GenreIsSimulation GenreIsEarlyAccess GenreIsFreeToPlay
##  Mode :logical   Mode :logical     Mode :logical      Mode :logical    
##  FALSE:10239     FALSE:10267       FALSE:10889        FALSE:11557      
##  TRUE :1920      TRUE :1892        TRUE :1270         TRUE :602        
##                                                                        
##                                                                        
##                                                                        
##                                                                        
##  GenreIsSports   GenreIsRacing   GenreIsMassivelyMultiplayer  PriceInitial    
##  Mode :logical   Mode :logical   Mode :logical               Min.   :  0.000  
##  FALSE:11677     FALSE:11714     FALSE:11811                 1st Qu.:  2.990  
##  TRUE :482       TRUE :445       TRUE :348                   Median :  6.990  
##                                                              Mean   :  9.386  
##                                                              3rd Qu.:  9.990  
##                                                              Max.   :449.990  
##                                                                               
##   ReleaseYear    ReleaseMonth    ReleaseMonthLabel  ReleaseMonthFull
##  Min.   :1997   Min.   : 1.000   Aug    :1553      August   :1553   
##  1st Qu.:2014   1st Qu.: 4.000   Sep    :1306      September:1306   
##  Median :2015   Median : 7.000   Oct    :1288      October  :1288   
##  Mean   :2014   Mean   : 6.645   Jul    :1143      July     :1143   
##  3rd Qu.:2016   3rd Qu.: 9.000   Jun    :1044      June     :1044   
##  Max.   :2018   Max.   :12.000   May    :1035      May      :1035   
##                                  (Other):4790      (Other)  :4790   
##    ReleaseDay     ReleaseWDay    ReleaseWDayLabel  ReleaseWDayFull
##  Min.   : 1.00   Min.   :1.000   Sun: 156         Sunday   : 156  
##  1st Qu.: 7.00   1st Qu.:3.000   Mon:2074         Monday   :2074  
##  Median :16.00   Median :4.000   Tue:2247         Tuesday  :2247  
##  Mean   :15.58   Mean   :4.176   Wed:1935         Wednesday:1935  
##  3rd Qu.:23.00   3rd Qu.:6.000   Thu:2634         Thursday :2634  
##  Max.   :31.00   Max.   :7.000   Fri:2974         Friday   :2974  
##                                  Sat: 139         Saturday : 139

Visualisasi

Jumlah Video Game yang setiap tahunnya

Visualisasi ini akan menampilkan jumlah video game yang tersedia di dalam dataset steam_complete setiap tahunnya.

steam_complete |>
  group_by(ReleaseYear) |> 
  summarise(
    TotalGames = n()
  ) |> ungroup() |> 
  ggplot(aes(x = as.character(ReleaseYear), y = TotalGames)) +
  geom_col(aes(fill = TotalGames), show.legend = FALSE) +
  scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
  theme_light() +
  labs(
    x = "Tahun Rilis",
    y = "Jumlah Video Games",
    title = "Jumlah Video Games Setiap Tahunnya"
  )

Dari visualisasi diatas, diketahui bahwa dataset lebih banyak pada tahun 2016. Dengan informasi tersebut juga, diambil keputusan untuk mengevaluasi data dari tahun 2009-2016.

steam_visual <- steam_complete |> 
  subset(ReleaseYear >= 2009 & ReleaseYear <= 2016)

Distribusi Harga

Ditampilkan distribusi Harga dari tahun 2009-2016.

steam_visual |> 
  ggplot(aes(x = as.character(ReleaseYear), y = PriceInitial)) +
  geom_boxplot() +
  theme_bw() +
  labs(
    x = "Tahun Rilis",
    y = "Harga (USD)",
    title = "Boxplot Harga Video Game Tahun 2009-2016"
  )

Jika dihapus nilai diatas 100 Dolar, maka visualisasi seperti ini:

steam_visual |> 
  subset(PriceInitial <= 100) |> 
  ggplot(aes(x = as.character(ReleaseYear), y = PriceInitial)) +
  geom_boxplot() +
  theme_bw() +
  labs(
    x = "Tahun Rilis",
    y = "Harga (USD)",
    title = "Boxplot Harga Video Game Tahun 2009-2016 (Dibawah 100 USD)"
  )

Bisa dilihat beberapa informasi dari boxplot diatas, median harga pada tahun 2016 bisa dibilang lebih kecil dibandingkan tahun-tahun sebelumnya. Hal tersebut bisa benar, akan tetapi dari visualisasi awal yang menunjukkan bahwa dataset tahun 2016 terbanyak, membuat pernyataan tersebut perlu dievaluasi lebih lanjut.

Tahun 2016

Visualisasi berikutnya akan fokus pada tahun 2016.

steam_2016 <- steam_complete |> subset(ReleaseYear == 2016)

Distribusi Metacritic Score

steam_2016 |>
  ggplot(aes(x = Metacritic)) +
  geom_histogram(binwidth = 10) +
  theme_bw() +
  labs(
    x = "Skor Metacritic",
    y = "Jumlah",
    title = "Distribusi Skor Metacritic Tahun 2016"
  )

Diatas menunjukkan bahwa banyak video game yang memiliki skor dibawah 10 atau 0. Maka karena itu, dilakukan filter untuk nilai diatas 0.

steam_2016 |>
  filter(Metacritic > 0) |> 
  ggplot(aes(x = Metacritic)) +
  geom_histogram(binwidth = 10) +
  theme_bw() +
  labs(
    x = "Skor Metacritic",
    y = "Jumlah",
    title = "Distribusi Skor Metacritic Tahun 2016"
  )

Bagaimana jika dibandingkan tahun 3 tahun sebelumnya?

steam_visual |>
  filter(Metacritic > 0) |> 
  filter(ReleaseYear >= 2013) |> 
  ggplot(aes(x = Metacritic)) +
  geom_histogram(
    aes(fill = as.character(ReleaseYear)), position = "identity",
    binwidth = 10, alpha = 0.6) +
  theme_bw() +
  labs(
    x = "Skor Metacritic",
    y = "Jumlah",
    fill = "Tahun",
    title = "Distribusi Skor Metacritic Tahun 2013-2016"
  )

Ternyata nilai metacritic diantara 60 - 75 jumlahnya banyak pada tahun 2014.


Masih banyak yang bisa dieksplorasi lagi mengenai dataset ini. Seperti:

  • Bagaimana pembagian distribusinya untuk setiap genre-nya.
  • Hubungan Jumlah Rekomendasi dengan Skor Metacritic.
  • Apakah ada hubungannya game yang gratis (IsFree) dengan skor ataupun jumlah rekomendasi.
  • Hubungan antara harga dengan jumlah rekomendasi ataupun skor metacritic.

Tapi waktunya terbatas, sehingga untuk sementara pembahasan mengenai dataset ini cukup sekian. Terima kasih.