library(readxl)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tidyr)
library(ggplot2)
library(cluster)
library(factoextra)
## Welcome to factoextra!
## Want to learn more? See two factoextra-related books at https://www.datanovia.com/library/principal-component-methods
library(writexl)
set.seed(123)
data_asli <- read_excel(
"D:/STATISTIKA/SEM 5/Analisis Perancangan Survey/wesgo_dengan_skor_aspek.xlsx"
)
cat("\n========== INFORMASI DATA ==========\n")
##
## ========== INFORMASI DATA ==========
cat("Dimensi data:", dim(data_asli), "\n")
## Dimensi data: 157 37
cat("\nNama kolom:\n")
##
## Nama kolom:
print(names(data_asli))
## [1] "Q1" "Q2"
## [3] "Q4" "Q5"
## [5] "Q6" "Q7"
## [7] "Q9" "Q10"
## [9] "Q11" "Q12"
## [11] "Q13" "Q14"
## [13] "Q15" "Q16"
## [15] "Q18" "Q19"
## [17] "Q20" "Q21"
## [19] "Q23" "Q24"
## [21] "Q25" "Q26"
## [23] "Q28" "Q29"
## [25] "Q30" "Skor_Usabilitas"
## [27] "Skor_Ketersediaan_Akses" "Skor_Keamanan_Berkendara"
## [29] "Skor_Kenyamanan_Sepeda" "Skor_Kecepatan_Respons"
## [31] "Skor_Kepuasan_Keseluruhan" "Skor_X1_Usabilitas"
## [33] "Skor_X2_Ketersediaan_Akses" "Skor_X3_Keamanan_Berkendara"
## [35] "Skor_X4_Kenyamanan_Sepeda" "Skor_X5_Kecepatan_Respons"
## [37] "Skor_X6_Kepuasan_Keseluruhan"
cat("\nStruktur data:\n")
##
## Struktur data:
str(data_asli)
## tibble [157 × 37] (S3: tbl_df/tbl/data.frame)
## $ Q1 : num [1:157] 4 3 4 3 3 3 4 3 3 3 ...
## $ Q2 : num [1:157] 5 3 4 4 3 3 4 3 4 3 ...
## $ Q4 : num [1:157] 5 4 3 3 3 3 3 4 4 3 ...
## $ Q5 : num [1:157] 4 3 5 3 2 4 5 4 5 4 ...
## $ Q6 : num [1:157] 4 4 4 3 2 3 3 4 3 4 ...
## $ Q7 : num [1:157] 4 4 4 4 2 3 3 5 3 4 ...
## $ Q9 : num [1:157] 4 2 5 4 4 4 4 4 3 2 ...
## $ Q10 : num [1:157] 5 4 3 2 3 3 3 4 2 4 ...
## $ Q11 : num [1:157] 4 4 5 3 3 5 4 5 4 5 ...
## $ Q12 : num [1:157] 4 4 5 2 3 4 5 5 4 4 ...
## $ Q13 : num [1:157] 5 5 4 3 3 5 5 4 3 4 ...
## $ Q14 : num [1:157] 4 4 5 4 4 4 4 5 3 5 ...
## $ Q15 : num [1:157] 4 4 5 3 3 3 5 4 3 5 ...
## $ Q16 : num [1:157] 4 5 3 4 3 5 3 4 5 3 ...
## $ Q18 : num [1:157] 4 5 4 3 2 4 4 3 4 4 ...
## $ Q19 : num [1:157] 3 3 4 3 3 3 3 3 3 3 ...
## $ Q20 : num [1:157] 4 4 4 3 2 5 4 3 3 5 ...
## $ Q21 : num [1:157] 4 3 4 2 3 4 4 4 4 4 ...
## $ Q23 : num [1:157] 3 3 5 2 3 4 5 4 3 3 ...
## $ Q24 : num [1:157] 4 3 3 4 3 3 4 3 4 5 ...
## $ Q25 : num [1:157] 5 4 4 3 4 3 3 3 4 3 ...
## $ Q26 : num [1:157] 5 3 4 3 3 4 4 4 4 3 ...
## $ Q28 : num [1:157] 5 4 5 2 3 4 4 4 4 4 ...
## $ Q29 : num [1:157] 4 4 3 3 4 4 4 3 3 4 ...
## $ Q30 : num [1:157] 4 5 3 4 3 3 4 3 4 4 ...
## $ Skor_Usabilitas : num [1:157] 4.5 3.25 4 3.25 2.75 3.25 4 3.5 4 3.25 ...
## $ Skor_Ketersediaan_Akses : num [1:157] 4.25 3.5 4 3.25 2.75 3.25 3.25 4.25 2.75 3.5 ...
## $ Skor_Keamanan_Berkendara : num [1:157] 4.2 4.2 4.8 3 3.2 4.2 4.6 4.6 3.4 4.6 ...
## $ Skor_Kenyamanan_Sepeda : num [1:157] 3.75 4.25 3.75 3.25 2.5 4.25 3.5 3.25 3.75 3.75 ...
## $ Skor_Kecepatan_Respons : num [1:157] 4 3.25 4 2.75 3.25 3.5 4 3.5 3.75 3.75 ...
## $ Skor_Kepuasan_Keseluruhan : num [1:157] 4.5 4 3.75 3 3.25 3.75 4 3.5 3.75 3.75 ...
## $ Skor_X1_Usabilitas : num [1:157] 4.5 3.25 4 3.25 2.75 3.25 4 3.5 4 3.25 ...
## $ Skor_X2_Ketersediaan_Akses : num [1:157] 4.25 3.5 4 3.25 2.75 3.25 3.25 4.25 2.75 3.5 ...
## $ Skor_X3_Keamanan_Berkendara : num [1:157] 4.2 4.2 4.8 3 3.2 4.2 4.6 4.6 3.4 4.6 ...
## $ Skor_X4_Kenyamanan_Sepeda : num [1:157] 3.75 4.25 3.75 3.25 2.5 4.25 3.5 3.25 3.75 3.75 ...
## $ Skor_X5_Kecepatan_Respons : num [1:157] 4 3.25 4 2.75 3.25 3.5 4 3.5 3.75 3.75 ...
## $ Skor_X6_Kepuasan_Keseluruhan: num [1:157] 4.5 4 3.75 3 3.25 3.75 4 3.5 3.75 3.75 ...
cat("\nEnam baris pertama:\n")
##
## Enam baris pertama:
print(head(data_asli))
## # A tibble: 6 × 37
## Q1 Q2 Q4 Q5 Q6 Q7 Q9 Q10 Q11 Q12 Q13 Q14 Q15
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 4 5 5 4 4 4 4 5 4 4 5 4 4
## 2 3 3 4 3 4 4 2 4 4 4 5 4 4
## 3 4 4 3 5 4 4 5 3 5 5 4 5 5
## 4 3 4 3 3 3 4 4 2 3 2 3 4 3
## 5 3 3 3 2 2 2 4 3 3 3 3 4 3
## 6 3 3 3 4 3 3 4 3 5 4 5 4 3
## # ℹ 24 more variables: Q16 <dbl>, Q18 <dbl>, Q19 <dbl>, Q20 <dbl>, Q21 <dbl>,
## # Q23 <dbl>, Q24 <dbl>, Q25 <dbl>, Q26 <dbl>, Q28 <dbl>, Q29 <dbl>,
## # Q30 <dbl>, Skor_Usabilitas <dbl>, Skor_Ketersediaan_Akses <dbl>,
## # Skor_Keamanan_Berkendara <dbl>, Skor_Kenyamanan_Sepeda <dbl>,
## # Skor_Kecepatan_Respons <dbl>, Skor_Kepuasan_Keseluruhan <dbl>,
## # Skor_X1_Usabilitas <dbl>, Skor_X2_Ketersediaan_Akses <dbl>,
## # Skor_X3_Keamanan_Berkendara <dbl>, Skor_X4_Kenyamanan_Sepeda <dbl>, …
kolom_aspek <- c(
"Skor_Usabilitas",
"Skor_Ketersediaan_Akses",
"Skor_Keamanan_Berkendara",
"Skor_Kenyamanan_Sepeda",
"Skor_Kecepatan_Respons",
"Skor_Kepuasan_Keseluruhan"
)
if (!all(kolom_aspek %in% names(data_asli))) {
stop(
"Nama kolom skor aspek tidak sesuai. Periksa names(data_asli)."
)
}
data_analisis <- data_asli %>%
select(all_of(kolom_aspek)) %>%
mutate(across(everything(), as.numeric))
cat("\n========== PEMERIKSAAN MISSING VALUE ==========\n")
##
## ========== PEMERIKSAAN MISSING VALUE ==========
print(colSums(is.na(data_analisis)))
## Skor_Usabilitas Skor_Ketersediaan_Akses Skor_Keamanan_Berkendara
## 0 0 0
## Skor_Kenyamanan_Sepeda Skor_Kecepatan_Respons Skor_Kepuasan_Keseluruhan
## 0 0 0
baris_lengkap <- complete.cases(data_analisis)
data_bersih <- data_analisis[baris_lengkap, , drop = FALSE]
# Menyimpan data asli yang barisnya sesuai dengan data clustering
data_lengkap_asli <- data_asli[
baris_lengkap, ,
drop = FALSE
]
cat("\nJumlah responden awal:", nrow(data_analisis), "\n")
##
## Jumlah responden awal: 157
cat("Jumlah responden dianalisis:", nrow(data_bersih), "\n")
## Jumlah responden dianalisis: 157
cat("Jumlah baris dikeluarkan:", sum(!baris_lengkap), "\n")
## Jumlah baris dikeluarkan: 0
if (nrow(data_bersih) < 3) {
stop("Jumlah data lengkap tidak mencukupi.")
}
if (any(!is.finite(as.matrix(data_bersih)))) {
stop("Terdapat nilai tidak valid dalam data.")
}
if (any(sapply(data_bersih, sd) == 0)) {
stop("Ada aspek dengan varians nol.")
}
statistik_deskriptif <- data_bersih %>%
summarise(
across(
everything(),
list(
N = ~ sum(!is.na(.x)),
Mean = ~ mean(.x),
SD = ~ sd(.x),
Minimum = ~ min(.x),
Median = ~ median(.x),
Maksimum = ~ max(.x)
),
.names = "{.col}_{.fn}"
)
) %>%
pivot_longer(
cols = everything(),
names_to = c("Aspek", ".value"),
names_pattern =
"(.+)_(N|Mean|SD|Minimum|Median|Maksimum)"
)
cat("\n========== STATISTIK DESKRIPTIF ==========\n")
##
## ========== STATISTIK DESKRIPTIF ==========
print(statistik_deskriptif)
## # A tibble: 6 × 7
## Aspek N Mean SD Minimum Median Maksimum
## <chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Skor_Usabilitas 157 3.35 0.850 1 3.25 5
## 2 Skor_Ketersediaan_Akses 157 3.33 0.745 1.25 3.25 5
## 3 Skor_Keamanan_Berkendara 157 3.54 0.848 1.2 3.8 5
## 4 Skor_Kenyamanan_Sepeda 157 3.43 0.808 1 3.75 5
## 5 Skor_Kecepatan_Respons 157 3.31 0.792 1.25 3.25 5
## 6 Skor_Kepuasan_Keseluruhan 157 3.43 0.792 1 3.5 5
rata_rata_aspek <- data_bersih %>%
summarise(across(everything(), mean)) %>%
pivot_longer(
cols = everything(),
names_to = "Aspek",
values_to = "Rata_rata"
)
cat("\n========== RATA-RATA ASPEK ==========\n")
##
## ========== RATA-RATA ASPEK ==========
print(rata_rata_aspek)
## # A tibble: 6 × 2
## Aspek Rata_rata
## <chr> <dbl>
## 1 Skor_Usabilitas 3.35
## 2 Skor_Ketersediaan_Akses 3.33
## 3 Skor_Keamanan_Berkendara 3.54
## 4 Skor_Kenyamanan_Sepeda 3.43
## 5 Skor_Kecepatan_Respons 3.31
## 6 Skor_Kepuasan_Keseluruhan 3.43
grafik_deskriptif <- ggplot(
rata_rata_aspek,
aes(
x = reorder(Aspek, Rata_rata),
y = Rata_rata
)
) +
geom_col(fill = "#2878B5", width = 0.7) +
geom_text(
aes(label = round(Rata_rata, 3)),
hjust = -0.15,
size = 3.5
) +
coord_flip() +
labs(
title = "Rata-rata Penilaian Enam Aspek WESGO",
x = "Aspek Penilaian",
y = "Rata-rata"
) +
expand_limits(
y = max(rata_rata_aspek$Rata_rata) * 1.15
) +
theme_minimal(base_size = 12)
print(grafik_deskriptif)
# ============================================================ # 4.
STANDARDISASI DATA #
============================================================
data_scaled <- scale(data_bersih)
cat("\n========== PEMERIKSAAN STANDARDISASI ==========\n")
##
## ========== PEMERIKSAAN STANDARDISASI ==========
print(head(round(data_scaled, 3)))
## Skor_Usabilitas Skor_Ketersediaan_Akses Skor_Keamanan_Berkendara
## [1,] 1.349 1.237 0.782
## [2,] -0.122 0.231 0.782
## [3,] 0.760 0.902 1.489
## [4,] -0.122 -0.105 -0.634
## [5,] -0.710 -0.776 -0.398
## [6,] -0.122 -0.105 0.782
## Skor_Kenyamanan_Sepeda Skor_Kecepatan_Respons Skor_Kepuasan_Keseluruhan
## [1,] 0.398 0.876 1.355
## [2,] 1.017 -0.070 0.724
## [3,] 0.398 0.876 0.408
## [4,] -0.221 -0.701 -0.539
## [5,] -1.149 -0.070 -0.223
## [6,] 1.017 0.245 0.408
cat("\nRata-rata setelah standardisasi:\n")
##
## Rata-rata setelah standardisasi:
print(round(colMeans(data_scaled), 4))
## Skor_Usabilitas Skor_Ketersediaan_Akses Skor_Keamanan_Berkendara
## 0 0 0
## Skor_Kenyamanan_Sepeda Skor_Kecepatan_Respons Skor_Kepuasan_Keseluruhan
## 0 0 0
cat("\nStandar deviasi setelah standardisasi:\n")
##
## Standar deviasi setelah standardisasi:
print(round(apply(data_scaled, 2, sd), 4))
## Skor_Usabilitas Skor_Ketersediaan_Akses Skor_Keamanan_Berkendara
## 1 1 1
## Skor_Kenyamanan_Sepeda Skor_Kecepatan_Respons Skor_Kepuasan_Keseluruhan
## 1 1 1
maks_k <- min(8, nrow(data_scaled) - 1)
nilai_k <- 2:maks_k
hasil_elbow <- data.frame(
K = nilai_k,
WSS = sapply(nilai_k, function(k) {
kmeans(
data_scaled,
centers = k,
nstart = 100,
iter.max = 200
)$tot.withinss
})
)
cat("\n========== HASIL ELBOW METHOD ==========\n")
##
## ========== HASIL ELBOW METHOD ==========
print(hasil_elbow)
## K WSS
## 1 2 423.4824
## 2 3 321.0110
## 3 4 271.5573
## 4 5 229.6379
## 5 6 194.9078
## 6 7 174.6631
## 7 8 162.6832
grafik_elbow <- ggplot(
hasil_elbow,
aes(x = K, y = WSS)
) +
geom_line(color = "#2878B5", linewidth = 1) +
geom_point(color = "#D9534F", size = 3) +
scale_x_continuous(breaks = nilai_k) +
labs(
title = "Elbow Method untuk Menentukan Jumlah Cluster",
x = "Jumlah Cluster (K)",
y = "Within-Cluster Sum of Squares (WSS)"
) +
theme_minimal(base_size = 12)
print(grafik_elbow)
jarak_data <- dist(data_scaled)
hasil_silhouette <- sapply(nilai_k, function(k) {
model <- kmeans(
data_scaled,
centers = k,
nstart = 100,
iter.max = 200
)
sil <- silhouette(model$cluster, jarak_data)
mean(sil[, "sil_width"])
})
tabel_silhouette <- data.frame(
K = nilai_k,
Silhouette = hasil_silhouette
)
cat("\n========== HASIL SILHOUETTE ==========\n")
##
## ========== HASIL SILHOUETTE ==========
print(tabel_silhouette)
## K Silhouette
## 1 2 0.4638061
## 2 3 0.3458680
## 3 4 0.3247253
## 4 5 0.2922781
## 5 6 0.3134016
## 6 7 0.3077925
## 7 8 0.3074307
grafik_silhouette <- ggplot(
tabel_silhouette,
aes(x = K, y = Silhouette)
) +
geom_line(color = "#2E8B57", linewidth = 1) +
geom_point(color = "#D9534F", size = 3) +
scale_x_continuous(breaks = nilai_k) +
labs(
title = "Perbandingan Silhouette Coefficient",
x = "Jumlah Cluster (K)",
y = "Rata-rata Silhouette"
) +
theme_minimal(base_size = 12)
print(grafik_silhouette)
k_terbaik <- tabel_silhouette$K[
which.max(tabel_silhouette$Silhouette)
]
cat("\nK dengan Silhouette tertinggi:", k_terbaik, "\n")
##
## K dengan Silhouette tertinggi: 2
K_final <- k_terbaik
set.seed(123)
model_kmeans <- kmeans(
data_scaled,
centers = K_final,
nstart = 100,
iter.max = 200
)
cat("\n========== HASIL K-MEANS FINAL ==========\n")
##
## ========== HASIL K-MEANS FINAL ==========
print(model_kmeans)
## K-means clustering with 2 clusters of sizes 104, 53
##
## Cluster means:
## Skor_Usabilitas Skor_Ketersediaan_Akses Skor_Keamanan_Berkendara
## 1 0.5200947 0.4534167 0.5410415
## 2 -1.0205633 -0.8897234 -1.0616664
## Skor_Kenyamanan_Sepeda Skor_Kecepatan_Respons Skor_Kepuasan_Keseluruhan
## 1 0.5526983 0.5121284 0.5718814
## 2 -1.0845401 -1.0049312 -1.1221824
##
## Clustering vector:
## [1] 1 1 1 2 2 1 1 1 1 1 1 2 2 1 1 1 1 2 1 2 2 1 1 2 2 2 1 1 1 1 2 1 1 1 2 1 2
## [38] 2 2 1 1 1 1 1 1 2 2 1 1 1 1 2 2 2 1 2 1 1 2 2 1 1 1 1 1 1 1 2 1 2 2 2 1 1
## [75] 1 1 1 2 1 1 2 1 2 1 1 1 2 1 1 1 1 1 1 1 2 1 1 1 2 2 2 1 2 2 1 1 1 1 2 1 1
## [112] 1 1 1 1 1 2 1 1 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 2 1 2 2 2 1 1 1 1 2 2 2 1 2
## [149] 2 2 1 1 1 1 2 1 2
##
## Within cluster sum of squares by cluster:
## [1] 268.8701 154.6124
## (between_SS / total_SS = 54.8 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss" "tot.withinss"
## [6] "betweenss" "size" "iter" "ifault"
cat("\nJumlah cluster:", K_final, "\n")
##
## Jumlah cluster: 2
cat("Total WSS:", model_kmeans$tot.withinss, "\n")
## Total WSS: 423.4824
cat("Between-cluster SS:", model_kmeans$betweenss, "\n")
## Between-cluster SS: 512.5176
cat("Proporsi variasi antarcluster:",
round(model_kmeans$betweenss /
model_kmeans$totss, 4), "\n")
## Proporsi variasi antarcluster: 0.5476
cat("\nPusat cluster terstandardisasi:\n")
##
## Pusat cluster terstandardisasi:
print(round(model_kmeans$centers, 3))
## Skor_Usabilitas Skor_Ketersediaan_Akses Skor_Keamanan_Berkendara
## 1 0.520 0.453 0.541
## 2 -1.021 -0.890 -1.062
## Skor_Kenyamanan_Sepeda Skor_Kecepatan_Respons Skor_Kepuasan_Keseluruhan
## 1 0.553 0.512 0.572
## 2 -1.085 -1.005 -1.122
hasil_cluster <- data_bersih %>%
mutate(
Cluster = factor(
model_kmeans$cluster,
levels = seq_len(K_final),
labels = paste("Cluster", seq_len(K_final))
)
)
# Menambahkan cluster ke data asli yang barisnya lengkap
data_lengkap_dengan_cluster <- data_lengkap_asli %>%
mutate(Cluster = hasil_cluster$Cluster)
distribusi_cluster <- hasil_cluster %>%
count(Cluster, name = "Jumlah") %>%
mutate(
Persentase = round(100 * Jumlah / sum(Jumlah), 2)
)
cat("\n========== DISTRIBUSI CLUSTER ==========\n")
##
## ========== DISTRIBUSI CLUSTER ==========
print(distribusi_cluster)
## # A tibble: 2 × 3
## Cluster Jumlah Persentase
## <fct> <int> <dbl>
## 1 Cluster 1 104 66.2
## 2 Cluster 2 53 33.8
grafik_distribusi <- ggplot(
distribusi_cluster,
aes(x = Cluster, y = Jumlah, fill = Cluster)
) +
geom_col(width = 0.65, show.legend = FALSE) +
geom_text(
aes(label = paste0(Jumlah, " (", Persentase, "%)")),
vjust = -0.4
) +
labs(
title = "Distribusi Anggota Cluster WESGO",
x = "Cluster",
y = "Jumlah responden"
) +
expand_limits(y = max(distribusi_cluster$Jumlah) * 1.15) +
theme_minimal(base_size = 12)
print(grafik_distribusi)
final_cluster_centers <- hasil_cluster %>%
group_by(Cluster) %>%
summarise(
across(all_of(kolom_aspek), mean),
.groups = "drop"
)
cat("\n========== FINAL CLUSTER CENTERS ==========\n")
##
## ========== FINAL CLUSTER CENTERS ==========
print(final_cluster_centers)
## # A tibble: 2 × 7
## Cluster Skor_Usabilitas Skor_Ketersediaan_Akses Skor_Keamanan_Berkendara
## <fct> <dbl> <dbl> <dbl>
## 1 Cluster 1 3.80 3.67 4.00
## 2 Cluster 2 2.49 2.67 2.64
## # ℹ 3 more variables: Skor_Kenyamanan_Sepeda <dbl>,
## # Skor_Kecepatan_Respons <dbl>, Skor_Kepuasan_Keseluruhan <dbl>
# Pusat cluster dalam skala standardisasi
centers_scaled <- as.data.frame(model_kmeans$centers)
centers_scaled$Cluster <- paste("Cluster", seq_len(K_final))
centers_scaled <- centers_scaled %>%
select(Cluster, everything())
cat("\nPusat cluster pada skala standardisasi:\n")
##
## Pusat cluster pada skala standardisasi:
print(centers_scaled)
## Cluster Skor_Usabilitas Skor_Ketersediaan_Akses Skor_Keamanan_Berkendara
## 1 Cluster 1 0.5200947 0.4534167 0.5410415
## 2 Cluster 2 -1.0205633 -0.8897234 -1.0616664
## Skor_Kenyamanan_Sepeda Skor_Kecepatan_Respons Skor_Kepuasan_Keseluruhan
## 1 0.5526983 0.5121284 0.5718814
## 2 -1.0845401 -1.0049312 -1.1221824
jarak_centroid <- as.matrix(
dist(model_kmeans$centers)
)
rownames(jarak_centroid) <- paste("Cluster", seq_len(K_final))
colnames(jarak_centroid) <- paste("Cluster", seq_len(K_final))
cat("\n========== JARAK ANTARPUSAT CLUSTER ==========\n")
##
## ========== JARAK ANTARPUSAT CLUSTER ==========
print(round(jarak_centroid, 4))
## Cluster 1 Cluster 2
## Cluster 1 0.0000 3.8208
## Cluster 2 3.8208 0.0000
profil_long <- final_cluster_centers %>%
pivot_longer(
cols = all_of(kolom_aspek),
names_to = "Aspek",
values_to = "Rata_rata"
)
grafik_profil <- ggplot(
profil_long,
aes(
x = Aspek,
y = Rata_rata,
color = Cluster,
group = Cluster
)
) +
geom_line(linewidth = 1) +
geom_point(size = 3) +
labs(
title = "Profil Rata-rata Enam Aspek WESGO",
x = "Aspek",
y = "Rata-rata skor",
color = "Cluster"
) +
theme_minimal(base_size = 11) +
theme(
axis.text.x = element_text(angle = 35, hjust = 1)
)
print(grafik_profil)
# Diagram Final Cluster Centers dalam bentuk batang
grafik_centers <- ggplot(
profil_long,
aes(x = Cluster, y = Rata_rata, fill = Aspek)
) +
geom_col(position = position_dodge(width = 0.8), width = 0.7) +
labs(
title = "Diagram Final Cluster Centers WESGO",
x = "Cluster",
y = "Rata-rata skor",
fill = "Aspek"
) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
print(grafik_centers)
# Visualisasi dua dimensi hasil K-Means
grafik_cluster <- fviz_cluster(
model_kmeans,
data = data_scaled,
geom = "point",
ellipse.type = "norm",
main = paste("K-Means Clustering WESGO, K =", K_final)
)
print(grafik_cluster)
sil_final <- silhouette(
model_kmeans$cluster,
jarak_data
)
nilai_sil_final <- mean(sil_final[, "sil_width"])
cat("\n========== EVALUASI MODEL FINAL ==========\n")
##
## ========== EVALUASI MODEL FINAL ==========
cat("Rata-rata Silhouette:", round(nilai_sil_final, 4), "\n")
## Rata-rata Silhouette: 0.4638
grafik_sil_final <- fviz_silhouette(sil_final) +
labs(title = "Silhouette Plot Model K-Means Final") +
theme_minimal()
## cluster size ave.sil.width
## 1 1 104 0.48
## 2 2 53 0.44
print(grafik_sil_final)
hasil_anova <- lapply(kolom_aspek, function(aspek) {
model_anova <- aov(
hasil_cluster[[aspek]] ~ hasil_cluster$Cluster
)
tabel <- summary(model_anova)[[1]]
data.frame(
Aspek = aspek,
F_hitung = unname(tabel[1, "F value"]),
P_value = unname(tabel[1, "Pr(>F)"])
)
})
hasil_anova <- bind_rows(hasil_anova) %>%
mutate(
Keputusan = ifelse(
P_value < 0.05,
"Signifikan",
"Tidak signifikan"
)
)
cat("\n========== HASIL ANOVA ==========\n")
##
## ========== HASIL ANOVA ==========
print(hasil_anova)
## Aspek F_hitung P_value Keputusan
## 1 Skor_Usabilitas 177.7552 1.682201e-27 Signifikan
## 2 Skor_Ketersediaan_Akses 105.9434 2.925627e-19 Signifikan
## 3 Skor_Keamanan_Berkendara 212.3749 7.547496e-31 Signifikan
## 4 Skor_Kenyamanan_Sepeda 235.6899 6.276687e-33 Signifikan
## 5 Skor_Kecepatan_Respons 166.5453 2.431225e-26 Signifikan
## 6 Skor_Kepuasan_Keseluruhan 282.6912 9.113736e-37 Signifikan
case_summary <- data.frame(
Keterangan = c(
"Jumlah data awal",
"Data lengkap dan dianalisis",
"Data dikeluarkan karena missing value"
),
Jumlah = c(
nrow(data_analisis),
nrow(data_bersih),
sum(!baris_lengkap)
)
) %>%
mutate(
Persentase = round(
100 * Jumlah / nrow(data_analisis),
2
)
)
cat("\n========== CASE PROCESSING SUMMARY ==========\n")
##
## ========== CASE PROCESSING SUMMARY ==========
print(case_summary)
## Keterangan Jumlah Persentase
## 1 Jumlah data awal 157 100
## 2 Data lengkap dan dianalisis 157 100
## 3 Data dikeluarkan karena missing value 0 0
variabel_kategorik <- c("FITUR", "DRIVER", "LAYANAN")
hasil_crosstab <- list()
hasil_chisq_list <- list()
if (all(variabel_kategorik %in% names(data_lengkap_dengan_cluster))) {
for (v in variabel_kategorik) {
cat("\n========================================\n")
cat("CROSSTAB CLUSTER x", v, "\n")
cat("========================================\n")
data_uji <- data_lengkap_dengan_cluster %>%
filter(!is.na(.data[[v]]))
tab <- table(
Cluster = data_uji$Cluster,
Penilaian = data_uji[[v]]
)
print(tab)
hasil_crosstab[[v]] <- as.data.frame.matrix(tab)
if (nrow(tab) >= 2 && ncol(tab) >= 2) {
uji_chisq <- suppressWarnings(
chisq.test(tab, correct = FALSE)
)
cat("\nHasil uji Chi-Square:\n")
print(uji_chisq)
cat("\nFrekuensi harapan:\n")
print(round(uji_chisq$expected, 3))
cat(
"\nSel dengan frekuensi harapan < 5:",
sum(uji_chisq$expected < 5),
"dari", length(uji_chisq$expected), "sel\n"
)
hasil_chisq_list[[v]] <- data.frame(
Variabel = v,
Chi_square = unname(uji_chisq$statistic),
df = unname(uji_chisq$parameter),
P_value = uji_chisq$p.value,
Sel_expected_di_bawah_5 =
sum(uji_chisq$expected < 5)
)
data_grafik <- as.data.frame(tab)
grafik_crosstab <- ggplot(
data_grafik,
aes(
x = Penilaian,
y = Freq,
fill = Cluster
)
) +
geom_col(position = "dodge") +
labs(
title = paste("Distribusi", v, "menurut Cluster"),
x = "Kategori penilaian",
y = "Jumlah responden",
fill = "Cluster"
) +
theme_minimal(base_size = 12) +
theme(
axis.text.x = element_text(
angle = 30,
hjust = 1
)
)
print(grafik_crosstab)
} else {
cat("Chi-Square tidak dijalankan: tabel kurang dari 2 baris atau kolom.\n")
}
}
} else {
cat(
"\nCrosstab dan Chi-Square belum dijalankan.\n",
"Kolom FITUR, DRIVER, dan LAYANAN tidak seluruhnya tersedia.\n",
"Periksa nama variabel kategorik pada data WESGO sebelum melanjutkan.\n",
sep = ""
)
}
##
## Crosstab dan Chi-Square belum dijalankan.
## Kolom FITUR, DRIVER, dan LAYANAN tidak seluruhnya tersedia.
## Periksa nama variabel kategorik pada data WESGO sebelum melanjutkan.
if (length(hasil_chisq_list) > 0) {
ringkasan_chisq <- bind_rows(hasil_chisq_list)
} else {
ringkasan_chisq <- data.frame(
Keterangan = "Tidak ada hasil Chi-Square yang dihitung."
)
}
ringkasan_model <- data.frame(
Jumlah_Responden = nrow(data_bersih),
Jumlah_Aspek = ncol(data_bersih),
K_Final = K_final,
WSS_Final = model_kmeans$tot.withinss,
Between_SS = model_kmeans$betweenss,
Silhouette_Final = nilai_sil_final
)
cat("\n========== RINGKASAN MODEL ==========\n")
##
## ========== RINGKASAN MODEL ==========
print(ringkasan_model)
## Jumlah_Responden Jumlah_Aspek K_Final WSS_Final Between_SS Silhouette_Final
## 1 157 6 2 423.4824 512.5176 0.4638061
cat("\nAspek dengan rata-rata tertinggi:\n")
##
## Aspek dengan rata-rata tertinggi:
print(
rata_rata_aspek[
which.max(rata_rata_aspek$Rata_rata),
]
)
## # A tibble: 1 × 2
## Aspek Rata_rata
## <chr> <dbl>
## 1 Skor_Keamanan_Berkendara 3.54
cat("\nAspek dengan rata-rata terendah:\n")
##
## Aspek dengan rata-rata terendah:
print(
rata_rata_aspek[
which.min(rata_rata_aspek$Rata_rata),
]
)
## # A tibble: 1 × 2
## Aspek Rata_rata
## <chr> <dbl>
## 1 Skor_Kecepatan_Respons 3.31
cat("\n========================================\n")
##
## ========================================
cat("SELURUH ANALISIS SELESAI\n")
## SELURUH ANALISIS SELESAI
cat("========================================\n")
## ========================================