1 Eksplorasi dan Visualisasi Data dengan R

Praktikum ini membahas penerapan eksplorasi dan visualisasi data menggunakan R, mulai dari pengenalan karakteristik data, eksplorasi univariate dan bivariate, hingga eksplorasi multivariate menggunakan cluster analysis, heatmap korelasi, Principal Component Analysis (PCA), dan Multidimensional Scaling (MDS).

2 Persiapan

2.1 Package

Package yang digunakan pada praktikum ini adalah:

library(dplyr)
library(ggplot2)
library(corrplot)

Jika package belum tersedia, jalankan terlebih dahulu:

install.packages("dplyr")
install.packages("ggplot2")
install.packages("corrplot")

Fungsi dist(), hclust(), kmeans(), prcomp(), dan cmdscale() tersedia pada R sehingga tidak membutuhkan package tambahan.

2.2 Data

Pada praktikum ini digunakan Mall Customer Segmentation Data.

Sumber data: Kaggle
Dataset: Customer Segmentation Tutorial in Python
Download: https://www.kaggle.com/datasets/vjchoudhary7/customer-segmentation-tutorial-in-python
File: Mall_Customers.csv

Simpan file Mall_Customers.csv pada folder yang sama dengan file R Markdown ini.

customer <- read.csv("Mall_Customers.csv")

names(customer) <- c(
  "CustomerID",
  "Gender",
  "Age",
  "AnnualIncome",
  "SpendingScore"
)

head(customer)
##   CustomerID Gender Age AnnualIncome SpendingScore
## 1          1   Male  19           15            39
## 2          2   Male  21           15            81
## 3          3 Female  20           16             6
## 4          4 Female  23           16            77
## 5          5 Female  31           17            40
## 6          6 Female  22           17            76

3 Pertemuan 1 — Pengenalan Eksplorasi dan Visualisasi Data

Kenali datanya sebelum menganalisisnya.

Eksplorasi data dilakukan untuk memperoleh pemahaman awal mengenai karakteristik, kualitas, pola, dan hubungan yang terdapat dalam data sebelum dilakukan analisis lebih lanjut.

3.1 Mengenal Data

cat("1. DIMENSI DATA\n")
## 1. DIMENSI DATA
dim(customer)
## [1] 200   5
cat("\n2. NAMA PEUBAH\n")
## 
## 2. NAMA PEUBAH
names(customer)
## [1] "CustomerID"    "Gender"        "Age"           "AnnualIncome" 
## [5] "SpendingScore"
cat("\n3. STRUKTUR DATA\n")
## 
## 3. STRUKTUR DATA
str(customer)
## 'data.frame':    200 obs. of  5 variables:
##  $ CustomerID   : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Gender       : chr  "Male" "Male" "Female" "Female" ...
##  $ Age          : int  19 21 20 23 31 22 35 23 64 30 ...
##  $ AnnualIncome : int  15 15 16 16 17 17 18 18 19 19 ...
##  $ SpendingScore: int  39 81 6 77 40 76 6 94 3 72 ...
cat("\n4. RINGKASAN DATA\n")
## 
## 4. RINGKASAN DATA
summary(customer)
##    CustomerID           Gender         Age         AnnualIncome   
##  Min.   :  1.00   Length   :200   Min.   :18.00   Min.   : 15.00  
##  1st Qu.: 50.75   N.unique :  2   1st Qu.:28.75   1st Qu.: 41.50  
##  Median :100.50   N.blank  :  0   Median :36.00   Median : 61.50  
##  Mean   :100.50   Min.nchar:  4   Mean   :38.85   Mean   : 60.56  
##  3rd Qu.:150.25   Max.nchar:  6   3rd Qu.:49.00   3rd Qu.: 78.00  
##  Max.   :200.00                   Max.   :70.00   Max.   :137.00  
##  SpendingScore  
##  Min.   : 1.00  
##  1st Qu.:34.75  
##  Median :50.00  
##  Mean   :50.20  
##  3rd Qu.:73.00  
##  Max.   :99.00

dim() menunjukkan ukuran dataset, str() digunakan untuk melihat struktur dan tipe data setiap peubah, sedangkan summary() memberikan ringkasan statistik awal.

3.2 Eksplorasi Kualitas Data

cat("1. MISSING VALUE PER PEUBAH\n")
## 1. MISSING VALUE PER PEUBAH
colSums(is.na(customer))
##    CustomerID        Gender           Age  AnnualIncome SpendingScore 
##             0             0             0             0             0
cat("\n2. TOTAL MISSING VALUE\n")
## 
## 2. TOTAL MISSING VALUE
sum(is.na(customer))
## [1] 0
cat("\n3. DATA DUPLIKAT\n")
## 
## 3. DATA DUPLIKAT
sum(duplicated(customer))
## [1] 0

Tahap ini digunakan untuk melihat apakah terdapat masalah data yang perlu ditangani sebelum eksplorasi lebih lanjut.

4 Pertemuan 2 — Eksplorasi Univariate dan Bivariate

Dari satu peubah menuju hubungan antarpeubah.

Eksplorasi univariate digunakan untuk memahami karakteristik satu peubah, sedangkan eksplorasi bivariate digunakan untuk melihat pola hubungan antara dua peubah.

5 Eksplorasi Univariate

5.1 Menyiapkan Peubah Numerik

CustomerID tidak digunakan dalam eksplorasi distribusi karena hanya berfungsi sebagai identifier.

data_sebaran <- stack(
  customer[c(
    "Age",
    "AnnualIncome",
    "SpendingScore"
  )]
)

names(data_sebaran) <- c(
  "Nilai",
  "Peubah"
)

head(data_sebaran)
##   Nilai Peubah
## 1    19    Age
## 2    21    Age
## 3    20    Age
## 4    23    Age
## 5    31    Age
## 6    22    Age

5.2 Histogram

Bagaimana nilai pada setiap peubah tersebar?

ggplot(
  data_sebaran,
  aes(x = Nilai)
) +
  geom_histogram(
    bins = 10,
    fill = "steelblue",
    color = "white"
  ) +
  facet_wrap(
    ~ Peubah,
    scales = "free",
    nrow = 1
  ) +
  labs(
    title = "Distribusi Peubah Numerik",
    x = "Nilai",
    y = "Frekuensi"
  ) +
  theme_minimal()

Histogram membantu melihat bentuk distribusi, rentang data, dan konsentrasi observasi.

5.3 Boxplot

Di mana pusat data berada dan apakah terdapat nilai yang ekstrem?

ggplot(
  data_sebaran,
  aes(
    x = Peubah,
    y = Nilai
  )
) +
  geom_boxplot(
    fill = "lightblue"
  ) +
  facet_wrap(
    ~ Peubah,
    scales = "free_y",
    nrow = 1
  ) +
  labs(
    title = "Boxplot Peubah Numerik",
    x = NULL,
    y = "Nilai"
  ) +
  theme_minimal()

Boxplot memberikan informasi mengenai median, kuartil, sebaran data, dan kemungkinan pencilan.

5.4 Density Plot

5.4.1 Naive Density

Melihat kepadatan data melalui interval nilai.

ggplot(
  customer,
  aes(x = Age)
) +
  geom_histogram(
    aes(y = after_stat(density)),
    bins = 10,
    fill = "lightblue",
    color = "white"
  ) +
  labs(
    title = "Naive Density Umur Pelanggan",
    x = "Age",
    y = "Density"
  ) +
  theme_minimal()

5.4.2 Kernel Density

Melihat pola distribusi secara lebih halus.

ggplot(
  data_sebaran,
  aes(x = Nilai)
) +
  geom_density(
    fill = "steelblue",
    alpha = 0.4
  ) +
  facet_wrap(
    ~ Peubah,
    scales = "free",
    nrow = 1
  ) +
  labs(
    title = "Kernel Density Peubah Numerik",
    x = "Nilai",
    y = "Density"
  ) +
  theme_minimal()

5.5 Perbandingan Sebaran

Apakah distribusi sebuah peubah berbeda antar kelompok?

Sebagai contoh, SpendingScore dibandingkan berdasarkan Gender.

customer %>%
  group_by(Gender) %>%
  summarise(
    Jumlah = n(),
    Rata_rata = mean(SpendingScore),
    Median = median(SpendingScore),
    SD = sd(SpendingScore)
  )
## # A tibble: 2 × 5
##   Gender Jumlah Rata_rata Median    SD
##   <chr>   <int>     <dbl>  <dbl> <dbl>
## 1 Female    112      51.5     50  24.1
## 2 Male       88      48.5     50  27.9

5.5.1 Boxplot Antargrup

ggplot(
  customer,
  aes(
    x = Gender,
    y = SpendingScore,
    fill = Gender
  )
) +
  geom_boxplot() +
  labs(
    title = "Spending Score Berdasarkan Gender",
    x = "Gender",
    y = "Spending Score"
  ) +
  guides(fill = "none") +
  theme_minimal()

5.5.2 Density Antargrup

ggplot(
  customer,
  aes(
    x = SpendingScore,
    fill = Gender
  )
) +
  geom_density(
    alpha = 0.4
  ) +
  labs(
    title = "Distribusi Spending Score Berdasarkan Gender",
    x = "Spending Score",
    y = "Density"
  ) +
  theme_minimal()

5.6 Outlier Detection

Apakah terdapat observasi yang jauh dari pola umum data?

ggplot(
  customer,
  aes(y = AnnualIncome)
) +
  geom_boxplot(
    fill = "lightblue"
  ) +
  labs(
    title = "Outlier Detection pada Annual Income",
    x = NULL,
    y = "Annual Income"
  ) +
  theme_minimal()

Q1 <- quantile(
  customer$AnnualIncome,
  0.25
)

Q3 <- quantile(
  customer$AnnualIncome,
  0.75
)

IQR_income <- IQR(
  customer$AnnualIncome
)

batas_bawah <- Q1 - 1.5 * IQR_income
batas_atas <- Q3 + 1.5 * IQR_income

cat("Batas bawah:", batas_bawah, "\n")
## Batas bawah: -13.25
cat("Batas atas :", batas_atas, "\n\n")
## Batas atas : 132.75
customer %>%
  filter(
    AnnualIncome < batas_bawah |
      AnnualIncome > batas_atas
  )
##   CustomerID Gender Age AnnualIncome SpendingScore
## 1        199   Male  32          137            18
## 2        200   Male  30          137            83

Tidak ditemukannya pencilan juga merupakan hasil eksplorasi yang valid.

6 Eksplorasi Bivariate

Ketika dua peubah dilihat bersama, pola baru dapat muncul.

6.1 Plot Tebaran

ggplot(
  customer,
  aes(
    x = AnnualIncome,
    y = SpendingScore
  )
) +
  geom_point(
    size = 2,
    alpha = 0.7
  ) +
  labs(
    title = "Annual Income dan Spending Score",
    x = "Annual Income",
    y = "Spending Score"
  ) +
  theme_minimal()

cor(
  customer$AnnualIncome,
  customer$SpendingScore
)
## [1] 0.009902848

Scatterplot membantu melihat pola hubungan yang tidak selalu dapat diringkas hanya oleh satu nilai korelasi.

6.2 Plot Tebaran Bertanda

Tambahkan informasi kelompok pada scatterplot.

ggplot(
  customer,
  aes(
    x = AnnualIncome,
    y = SpendingScore,
    color = Gender,
    shape = Gender
  )
) +
  geom_point(
    size = 2.5,
    alpha = 0.8
  ) +
  labs(
    title = "Plot Tebaran Bertanda Berdasarkan Gender",
    x = "Annual Income",
    y = "Spending Score"
  ) +
  theme_minimal()

6.3 2D Density Plot

Di wilayah mana observasi paling terkonsentrasi?

ggplot(
  customer,
  aes(
    x = AnnualIncome,
    y = SpendingScore
  )
) +
  stat_density_2d(
    aes(
      fill = after_stat(level)
    ),
    geom = "polygon",
    alpha = 0.6
  ) +
  geom_point(
    alpha = 0.3,
    size = 1
  ) +
  labs(
    title = "2D Density Plot",
    x = "Annual Income",
    y = "Spending Score",
    fill = "Density"
  ) +
  theme_minimal()

6.4 Bubble Plot

Satu visualisasi dapat membawa lebih dari dua informasi.

ggplot(
  customer,
  aes(
    x = AnnualIncome,
    y = SpendingScore,
    size = Age
  )
) +
  geom_point(
    alpha = 0.5
  ) +
  labs(
    title = "Bubble Plot",
    x = "Annual Income",
    y = "Spending Score",
    size = "Age"
  ) +
  theme_minimal()

6.5 Local Regression

Hubungan antarpeubah tidak selalu berbentuk garis lurus.

ggplot(
  customer,
  aes(
    x = AnnualIncome,
    y = SpendingScore
  )
) +
  geom_point(
    alpha = 0.4
  ) +
  geom_smooth(
    method = "loess",
    se = FALSE
  ) +
  labs(
    title = "Local Regression",
    x = "Annual Income",
    y = "Spending Score"
  ) +
  theme_minimal()

7 Pertemuan 3 — Eksplorasi Multivariate

Menemukan struktur yang tidak terlihat ketika peubah dianalisis satu per satu.

7.1 Menyiapkan Data Numerik

customer_num <- customer %>%
  select(
    Age,
    AnnualIncome,
    SpendingScore
  )

head(customer_num)
##   Age AnnualIncome SpendingScore
## 1  19           15            39
## 2  21           15            81
## 3  20           16             6
## 4  23           16            77
## 5  31           17            40
## 6  22           17            76

7.2 Standardisasi Data

customer_scaled <- scale(
  customer_num
)

head(customer_scaled)
##             Age AnnualIncome SpendingScore
## [1,] -1.4210029    -1.734646    -0.4337131
## [2,] -1.2778288    -1.734646     1.1927111
## [3,] -1.3494159    -1.696572    -1.7116178
## [4,] -1.1346547    -1.696572     1.0378135
## [5,] -0.5619583    -1.658498    -0.3949887
## [6,] -1.2062418    -1.658498     0.9990891

Standardisasi dilakukan agar peubah dengan skala numerik lebih besar tidak mendominasi analisis berbasis jarak.

8 Cluster Analysis

Apakah terdapat kelompok alami dalam data?

8.1 Jarak Antarobjek

jarak <- dist(
  customer_scaled,
  method = "euclidean"
)
jarak5 <- dist(
  customer_scaled[1:5, ],
  method = "euclidean"
)

round(
  as.matrix(jarak5),
  2
)
##      1    2    3    4    5
## 1 0.00 1.63 1.28 1.50 0.86
## 2 1.63 0.00 2.91 0.21 1.74
## 3 1.28 2.91 0.00 2.76 1.53
## 4 1.50 0.21 2.76 0.00 1.54
## 5 0.86 1.74 1.53 1.54 0.00

Semakin kecil jarak antara dua observasi, semakin mirip karakteristik keduanya berdasarkan peubah yang digunakan.

8.2 Hierarchical Clustering

hc <- hclust(
  jarak,
  method = "ward.D2"
)

8.2.1 Dendrogram

plot(
  hc,
  labels = FALSE,
  hang = -1,
  main = "Dendrogram Pelanggan",
  xlab = "Pelanggan",
  ylab = "Dissimilarity"
)

rect.hclust(
  hc,
  k = 5,
  border = 2:6
)

cluster_hc <- cutree(
  hc,
  k = 5
)

table(cluster_hc)
## cluster_hc
##  1  2  3  4  5 
## 22 66 45 39 28

8.3 K-Means Clustering

set.seed(123)

km <- kmeans(
  customer_scaled,
  centers = 5,
  nstart = 25
)

km$size
## [1] 40 54 39 47 20
customer$Cluster <- factor(
  km$cluster
)

head(customer)
##   CustomerID Gender Age AnnualIncome SpendingScore Cluster
## 1          1   Male  19           15            39       2
## 2          2   Male  21           15            81       2
## 3          3 Female  20           16             6       5
## 4          4 Female  23           16            77       2
## 5          5 Female  31           17            40       2
## 6          6 Female  22           17            76       2

8.3.1 Visualisasi Cluster

ggplot(
  customer,
  aes(
    x = AnnualIncome,
    y = SpendingScore,
    color = Cluster
  )
) +
  geom_point(
    size = 3,
    alpha = 0.8
  ) +
  labs(
    title = "K-Means Clustering",
    x = "Annual Income",
    y = "Spending Score",
    color = "Cluster"
  ) +
  theme_minimal()

8.3.2 Profiling Cluster

Cluster baru menjadi bermakna setelah karakteristiknya diketahui.

customer %>%
  group_by(Cluster) %>%
  summarise(
    Jumlah = n(),
    Rata_Umur = mean(Age),
    Rata_Income = mean(AnnualIncome),
    Rata_Spending = mean(SpendingScore)
  )
## # A tibble: 5 × 5
##   Cluster Jumlah Rata_Umur Rata_Income Rata_Spending
##   <fct>    <int>     <dbl>       <dbl>         <dbl>
## 1 1           40      32.9        86.1          81.5
## 2 2           54      25.2        41.1          62.2
## 3 3           39      39.9        86.1          19.4
## 4 4           47      55.6        54.4          48.9
## 5 5           20      46.2        26.8          18.4

9 Heatmap Korelasi

Melihat banyak hubungan antarpeubah dalam satu visualisasi.

cor_customer <- cor(
  customer_num
)

round(
  cor_customer,
  2
)
##                 Age AnnualIncome SpendingScore
## Age            1.00        -0.01         -0.33
## AnnualIncome  -0.01         1.00          0.01
## SpendingScore -0.33         0.01          1.00
corrplot(
  cor_customer,
  method = "color",
  type = "upper",
  addCoef.col = "black",
  tl.col = "black",
  tl.srt = 45
)

Nilai mendekati 1 menunjukkan hubungan positif kuat, nilai mendekati -1 menunjukkan hubungan negatif kuat, sedangkan nilai mendekati 0 menunjukkan hubungan linier yang lemah.

10 Reduksi Dimensi — Principal Component Analysis

Merangkum informasi multivariat ke dalam komponen utama.

10.1 Data PCA

customer_pca <- customer %>%
  select(
    Age,
    AnnualIncome,
    SpendingScore
  )

summary(customer_pca)
##       Age         AnnualIncome    SpendingScore  
##  Min.   :18.00   Min.   : 15.00   Min.   : 1.00  
##  1st Qu.:28.75   1st Qu.: 41.50   1st Qu.:34.75  
##  Median :36.00   Median : 61.50   Median :50.00  
##  Mean   :38.85   Mean   : 60.56   Mean   :50.20  
##  3rd Qu.:49.00   3rd Qu.: 78.00   3rd Qu.:73.00  
##  Max.   :70.00   Max.   :137.00   Max.   :99.00

Ketiga peubah memiliki skala yang berbeda. Oleh karena itu, PCA dilakukan dengan pemusatan dan standardisasi.

10.2 Melakukan PCA

pca_customer <- prcomp(
  customer_pca,
  center = TRUE,
  scale. = TRUE
)

pca_customer
## Standard deviations (1, .., p=3):
## [1] 1.1523823 0.9996256 0.8202217
## 
## Rotation (n x k) = (3 x 3):
##                       PC1         PC2          PC3
## Age            0.70638235  0.03014116 -0.707188441
## AnnualIncome  -0.04802398  0.99883160 -0.005397916
## SpendingScore -0.70619946 -0.03777499 -0.707004506

Dengan center = TRUE dan scale. = TRUE, PCA dilakukan setara dengan menggunakan matriks korelasi.

10.3 Keragaman Komponen Utama

summary(
  pca_customer
)
## Importance of components:
##                           PC1    PC2    PC3
## Standard deviation     1.1524 0.9996 0.8202
## Proportion of Variance 0.4427 0.3331 0.2243
## Cumulative Proportion  0.4427 0.7758 1.0000

Untuk menampilkan hasil secara lebih terstruktur:

# Menghitung eigenvalue
eigenvalue <- pca_customer$sdev^2

# Menghitung proporsi varians
proporsi_varians <- eigenvalue /
  sum(eigenvalue)

# Membuat tabel ringkasan
hasil_varians <- data.frame(
  Komponen = paste0(
    "PC",
    seq_along(eigenvalue)
  ),
  Eigenvalue = eigenvalue,
  Persen = proporsi_varians * 100,
  Kumulatif = cumsum(
    proporsi_varians
  ) * 100
)

# Membulatkan hanya kolom numerik
hasil_varians %>%
  mutate(
    across(
      where(is.numeric),
      ~ round(.x, 3)
    )
  )
##   Komponen Eigenvalue Persen Kumulatif
## 1      PC1      1.328 44.266    44.266
## 2      PC2      0.999 33.308    77.575
## 3      PC3      0.673 22.425   100.000

10.4 Scree Plot

Berapa banyak komponen yang masih membawa informasi penting?

screeplot(
  pca_customer,
  type = "lines",
  main = "Scree Plot PCA"
)

10.5 Loading

Peubah apa yang berkontribusi dalam pembentukan setiap komponen?

round(
  pca_customer$rotation,
  3
)
##                  PC1    PC2    PC3
## Age            0.706  0.030 -0.707
## AnnualIncome  -0.048  0.999 -0.005
## SpendingScore -0.706 -0.038 -0.707

rotation berisi loading masing-masing peubah. Nilai absolut loading yang relatif besar menunjukkan kontribusi yang lebih kuat terhadap pembentukan suatu komponen utama.

10.6 Score

Di mana posisi setiap observasi pada sistem koordinat baru?

head(
  pca_customer$x
)
##              PC1       PC2        PC3
## [1,] -0.61417879 -1.759067 1.32091743
## [2,] -1.66162301 -1.816189 0.06977714
## [3,]  0.33701620 -1.670607 2.17357077
## [4,] -1.45292726 -1.767993 0.07783381
## [5,] -0.03836892 -1.658578 0.68562168
## [6,] -1.47797641 -1.730659 0.15563214
score_pca <- as.data.frame(
  pca_customer$x
)

head(score_pca)
##           PC1       PC2        PC3
## 1 -0.61417879 -1.759067 1.32091743
## 2 -1.66162301 -1.816189 0.06977714
## 3  0.33701620 -1.670607 2.17357077
## 4 -1.45292726 -1.767993 0.07783381
## 5 -0.03836892 -1.658578 0.68562168
## 6 -1.47797641 -1.730659 0.15563214

10.6.1 Score Plot PC1 dan PC2

ggplot(
  score_pca,
  aes(
    x = PC1,
    y = PC2
  )
) +
  geom_point(
    size = 2.5,
    alpha = 0.7
  ) +
  labs(
    title = "Score Plot PCA",
    x = "Principal Component 1",
    y = "Principal Component 2"
  ) +
  theme_minimal()

10.7 Biplot PCA

Melihat observasi dan kontribusi peubah secara bersamaan.

biplot(
  pca_customer,
  scale = 0,
  cex = 0.6
)

11 Multidimensional Scaling

Menyederhanakan dimensi dengan mempertahankan kedekatan antarobjek.

MDS menggunakan informasi jarak antarobservasi untuk memetakan data ke ruang berdimensi lebih rendah.

11.1 MDS Dua Dimensi

mds <- cmdscale(
  jarak,
  k = 2
)
mds_data <- data.frame(
  Dimensi1 = mds[, 1],
  Dimensi2 = mds[, 2],
  Cluster = customer$Cluster
)

head(mds_data)
##      Dimensi1  Dimensi2 Cluster
## 1  0.61417879 -1.759067       2
## 2  1.66162301 -1.816189       2
## 3 -0.33701620 -1.670607       5
## 4  1.45292726 -1.767993       2
## 5  0.03836892 -1.658578       2
## 6  1.47797641 -1.730659       2

11.2 Visualisasi MDS

ggplot(
  mds_data,
  aes(
    x = Dimensi1,
    y = Dimensi2,
    color = Cluster
  )
) +
  geom_point(
    size = 3,
    alpha = 0.8
  ) +
  labs(
    title = "Multidimensional Scaling",
    x = "Dimensi 1",
    y = "Dimensi 2",
    color = "Cluster"
  ) +
  theme_minimal()

Secara praktis, PCA merangkum variasi peubah ke dalam komponen utama, sedangkan MDS memetakan observasi dengan mempertahankan informasi kedekatan atau jarak antarobservasi sejauh mungkin.