Tugas Visualisasi Data Analisis Penjualan LEGO

1. Eksplorasi Data Awal Tampilkan informasi umum dataset (jumlah data, kolom, tipe data). Lakukan pembersihan data sederhana jika diperlukan (null values, duplikat, dll).

#install.packages("dsbox")
library(dsbox)
data(lego_sales)                                      # Memuat dataset lego_sales
names(lego_sales)                                     # Menampilkan nama kolom
##  [1] "first_name"   "last_name"    "age"          "phone_number" "set_id"      
##  [6] "number"       "theme"        "subtheme"     "year"         "name"        
## [11] "pieces"       "us_price"     "image_url"    "quantity"
str(lego_sales)                                       # Menampilkan struktur dataset (jumlah data, tipe)
## Classes 'spec_tbl_df', 'tbl_df', 'tbl' and 'data.frame': 620 obs. of  14 variables:
##  $ first_name  : chr  "Kimberly" "Neel" "Neel" "Chelsea" ...
##  $ last_name   : chr  "Beckstead" "Garvin" "Garvin" "Bouchard" ...
##  $ age         : num  24 35 35 41 41 41 19 19 37 37 ...
##  $ phone_number: chr  "216-555-2549" "819-555-3189" "819-555-3189" NA ...
##  $ set_id      : num  24701 25626 24665 24695 25626 ...
##  $ number      : chr  "76062" "70595" "21031" "31048" ...
##  $ theme       : chr  "DC Comics Super Heroes" "Ninjago" "Architecture" "Creator" ...
##  $ subtheme    : chr  "Mighty Micros" "Rise of the Villains" NA NA ...
##  $ year        : num  2018 2018 2018 2018 2018 ...
##  $ name        : chr  "Robin vs. Bane" "Ultra Stealth Raider" "Burj Khalifa" "Lakeside Lodge" ...
##  $ pieces      : num  77 1093 333 368 1093 ...
##  $ us_price    : num  9.99 119.99 39.99 29.99 119.99 ...
##  $ image_url   : chr  "http://images.brickset.com/sets/images/76062-1.jpg" "http://images.brickset.com/sets/images/70595-1.jpg" "http://images.brickset.com/sets/images/21031-1.jpg" "http://images.brickset.com/sets/images/31048-1.jpg" ...
##  $ quantity    : num  1 1 1 1 1 1 1 3 1 2 ...
##  - attr(*, "spec")=List of 3
##   ..$ cols   :List of 14
##   .. ..$ first_name  : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ last_name   : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ age         : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ phone_number: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ set_id      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ number      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ theme       : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ subtheme    : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ year        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ name        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ pieces      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ us_price    : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ image_url   : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ quantity    : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   ..$ default: list()
##   .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
##   ..$ skip   : num 1
##   ..- attr(*, "class")= chr "col_spec"
summary(lego_sales)                                   # Menampilkan ringkasan statistik dataset
##   first_name         last_name              age        phone_number      
##  Length:620         Length:620         Min.   :16.00   Length:620        
##  Class :character   Class :character   1st Qu.:25.00   Class :character  
##  Mode  :character   Mode  :character   Median :33.00   Mode  :character  
##                                        Mean   :34.36                     
##                                        3rd Qu.:41.00                     
##                                        Max.   :68.00                     
##                                                                          
##      set_id         number             theme             subtheme        
##  Min.   :24548   Length:620         Length:620         Length:620        
##  1st Qu.:24725   Class :character   Class :character   Class :character  
##  Median :24805   Mode  :character   Mode  :character   Mode  :character  
##  Mean   :25125                                                           
##  3rd Qu.:25640                                                           
##  Max.   :26060                                                           
##                                                                          
##       year          name               pieces          us_price     
##  Min.   :2018   Length:620         Min.   :  13.0   Min.   :  3.99  
##  1st Qu.:2018   Class :character   1st Qu.:  70.0   1st Qu.:  9.99  
##  Median :2018   Mode  :character   Median : 114.0   Median : 19.99  
##  Mean   :2018                      Mean   : 254.2   Mean   : 29.04  
##  3rd Qu.:2018                      3rd Qu.: 313.0   3rd Qu.: 29.99  
##  Max.   :2018                      Max.   :4634.0   Max.   :349.99  
##                                    NA's   :69                       
##   image_url            quantity    
##  Length:620         Min.   :1.000  
##  Class :character   1st Qu.:1.000  
##  Mode  :character   Median :1.000  
##                     Mean   :1.437  
##                     3rd Qu.:2.000  
##                     Max.   :5.000  
## 
sum(is.na(lego_sales))                                # Mengecek jumlah nilai null dalam dataset
## [1] 392
lego_sales <- lego_sales[!duplicated(lego_sales), ]   # Menghapus data duplikat

2. Visualisasi Wajib Buat minimal 5 visualisasi dari kategori berikut:

10 Customer dengan Jumlah Transaksi terbanyak

library(ggplot2)

top_customers <- aggregate(quantity ~ first_name + last_name, data = lego_sales, sum)
top_customers <- top_customers[order(-top_customers$quantity), ][1:10, ]

ggplot(top_customers, aes(y = reorder(paste(first_name, last_name), quantity),
                          x = quantity,
                          fill = ifelse(quantity == max(quantity), "Tertinggi", "Lainnya"))) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values = c("Tertinggi" = "green", "Lainnya" = "grey")) +
  labs(title = "10 Customer dengan Jumlah Transaksi Terbanyak",
       y = "Customer", x = "Jumlah Transaksi") +
  scale_x_continuous(breaks = seq(0, max(top_customers$quantity), by = 2)) +
  theme_minimal() +
  theme(legend.position = "none")

10 Tema LEGO Terpopuler Berdasarkan Penjualan

top_themes <- aggregate(quantity ~ theme, data = lego_sales, sum)
top_themes <- top_themes[order(-top_themes$quantity), ][1:10, ]

ggplot(top_themes, aes(y = reorder(theme, quantity), x = quantity)) +
  geom_bar(stat = "identity", fill = ifelse(top_themes$quantity == max(top_themes$quantity), "green", 
                                            ifelse(top_themes$quantity == min(top_themes$quantity), "red", "gray"))) +
  labs(title = "10 Tema LEGO Terpopuler Berdasarkan Penjualan", x = "Jumlah Penjualan", y = "Tema") +
  theme_minimal() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1))

Sebaran Jumlah Pieces dan Harga

ggplot(lego_sales, aes(x = pieces, y = us_price)) +
  geom_point(alpha = 0.3, color = "orange", size = 2) +
  geom_smooth(method = "lm", se = FALSE, color = "darkblue", linetype = "solid") +
  labs(title = "Sebaran Jumlah Pieces dan Harga LEGO Set",
       x = "Jumlah Pieces", y = "Harga (USD)") +
  theme_minimal()

Komposisi Penjualan Berdasarkan Usia

library(dplyr)

lego_sales %>%
  mutate(age_group = cut(age,
                         breaks = seq(0, 70, by = 5),
                         labels = c("0–5", "6–10", "11–15", "16–20", "21–25", "26–30", "31–35",
                                    "36–40", "41–45", "46–50", "51–55", "56–60", "61–65", "66–70"),
                         right = FALSE)) %>%
  group_by(age_group) %>%
  summarise(total_quantity = sum(quantity)) %>%
  mutate(warna = case_when(
    total_quantity == max(total_quantity) ~ "Tertinggi",
    total_quantity == min(total_quantity) ~ "Terendah",
    TRUE ~ "Biasa"
  )) %>%
  ggplot(aes(x = age_group, y = total_quantity, fill = warna)) +
  geom_col() +
  geom_text(aes(label = total_quantity), vjust = -0.3, size = 3) +
  scale_fill_manual(values = c("Tertinggi" = "green", "Terendah" = "red", "Biasa" = "grey")) +
  labs(title = "Total Barang Terjual Berdasarkan Kelompok Usia",
       x = "Kelompok Usia", y = "Jumlah Barang Terjual") +
  theme_minimal() +
  theme(legend.position = "none")

Heatmap Korelasi Antar Variabel Numerik

library(tidyr)
library(reshape2)
library(ggplot2)
library(ggcorrplot)

data <- na.omit(dsbox::lego_sales[, c("pieces", "us_price", "quantity")])
cor_matrix <- cor(data)
melted_cor <- melt(cor_matrix)

ggplot(melted_cor, aes(Var1, Var2, fill = value)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(value, 2)), size = 5) +
  scale_fill_gradient2(low = "blue", high = "grey", mid = "white",
                       midpoint = 0, limit = c(-1, 1)) +
  labs(title = "Heatmap Korelasi Antar Variabel Numerik") +
  theme_minimal() +
  coord_fixed() +
  theme(
    axis.text.x = element_text(angle = 0, vjust = 1, hjust = 1),
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    legend.position = "none",
    axis.text = element_text(size = 12),
    axis.title = element_blank()
  )

3. Insight dan Narasi Tuliskan 3–5 insight menarik dari visualisasi yang dibuat. Contoh: Apakah tema tertentu mendominasi revenue? Apakah set dengan lebih banyak pieces selalu lebih mahal? Apakah ada preferensi tema LEGO pada kelompok usia tertentu?

-Dominasi tema-tema populer dalam penjualan LEGO
Visualisasi tema LEGO terpopuler menunjukkan bahwa tema seperti Star Wars, Nexo Knights, dan Mixels menempati posisi teratas dalam jumlah penjualan. Star Wars mendominasi dengan margin signifikan, yang menunjukkan pengaruh kuat dari franchise besar terhadap daya tarik konsumen. Tema-tema ini kemungkinan mendapat dukungan dari media populer seperti film dan serial, yang memperluas jangkauan pasar LEGO dan menarik penggemar lintas usia.

-Jumlah pieces dan harga LEGO memiliki hubungan yang sangat kuat
Scatter plot dan heatmap korelasi memperlihatkan bahwa terdapat korelasi positif yang sangat kuat antara jumlah pieces dan harga set LEGO (nilai korelasi 0.94). Ini menunjukkan bahwa semakin kompleks dan besar sebuah set (diukur dari banyaknya pieces), semakin mahal pula harganya. Hal ini mengindikasikan bahwa ukuran dan kompleksitas menjadi faktor utama dalam penentuan harga produk LEGO.

-Preferensi produk tidak dipengaruhi secara langsung oleh usia
Heatmap korelasi antar variabel numerik menunjukkan bahwa variabel usia (diwakili oleh quantity sebagai indikator pembelian) tidak memiliki korelasi yang signifikan terhadap harga ataupun jumlah pieces. Artinya, tidak ada kecenderungan kelompok usia tertentu lebih memilih set yang lebih mahal atau kompleks. Ini menunjukkan bahwa LEGO adalah produk yang disukai lintas usia, baik anak-anak maupun dewasa.

-Kelompok usia 36–40 tahun menjadi pembeli terbesar
Grafik penjualan berdasarkan kelompok usia menunjukkan bahwa kelompok usia 36–40 tahun merupakan pembeli terbanyak, disusul kelompok 21–25 dan 31–35 tahun. Hal ini membuktikan bahwa LEGO bukan hanya mainan anak-anak, tapi juga menarik bagi kalangan dewasa muda hingga dewasa mapan, baik untuk koleksi, hobi, maupun nostalgia. Ini membuka peluang strategi pemasaran yang lebih menyasar segmen dewasa.

-Segelintir pelanggan mendominasi transaksi
Dari grafik 10 pelanggan dengan jumlah transaksi terbanyak, terlihat bahwa satu pelanggan (Jackson Dominguez) memiliki jumlah transaksi yang jauh lebih tinggi dibanding yang lain. Ini mengindikasikan adanya ketimpangan atau distribusi tidak merata, di mana sebagian besar penjualan disumbang oleh pelanggan loyal tertentu. Strategi retensi seperti loyalty program bisa dimanfaatkan untuk mempertahankan pelanggan dengan kontribusi tinggi ini.