K-Means Clustering merupakan salah satu metode analisis dalam teknik data mining dan machine learning yang digunakan untuk mengelompokkan data ke dalam beberapa kelompok (cluster) berdasarkan tingkat kemiripan karakteristik data. Metode ini termasuk dalam kategori unsupervised learning, yaitu teknik pembelajaran yang tidak menggunakan label atau kategori sebelumnya dalam proses pengelompokan data.K-Means Clustering adalah metode pengelompokan data yang membagi sekumpulan objek ke dalam sejumlah K kelompok dengan cara meminimalkan variasi atau jarak antar data dalam kelompok yang sama melalui penentuan titik pusat cluster (centroid) (MacQueen, 1967).
Data yang digunakan pada penelitian in merupakan data sekunder yang diambil dari website resmi BPS Kota Yogyakarta (https://jogjakota.bps.go.id/id)
X1 Jumlah Pasar
X2 Jumlah Swalayan
X3 Jumlah Restoran
X4 Jumlah Akomodasi
X5 Jumlah Perbankan
Berikut adalah daftar package yang akan digunakan pada analisis ini. Apabila belum memasang package dibawah silahkan pasang menggunakan fungsi install.packages()
##
## 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
## Welcome to factoextra!
## Want to learn more? See two factoextra-related books at https://www.datanovia.com/en/product/practical-guide-to-principal-component-methods-in-r/
##
## Attaching package: 'psych'
## The following objects are masked from 'package:ggplot2':
##
## %+%, alpha
## Linking to GEOS 3.13.1, GDAL 3.11.4, PROJ 9.7.0; sf_use_s2() is TRUE
## Loading required package: terra
## terra 1.8.93
##
## Attaching package: 'terra'
## The following objects are masked from 'package:psych':
##
## describe, distance, rescale
## The following object is masked from 'package:tidyr':
##
## extract
##
## Attaching package: 'scales'
## The following object is masked from 'package:terra':
##
## rescale
## The following objects are masked from 'package:psych':
##
## alpha, rescale
##
## Attaching package: 'knitr'
## The following object is masked from 'package:terra':
##
## spin
##
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
##
## group_rows
Untuk melakukan analisis, panggil data daai file lokal dan bersihkan data serta definisikan variabel.
set.seed(42)
path <- "D:/SEMESTER 6/1. KP/INFRASTRUKTUR EKONOMI.xlsx"
id_col <- "KECAMATAN"
k_min <- 2
k_max <- 5
df_raw <- read_excel(path)
df <- df_raw %>%
rename_with(toupper) %>%
rename(
X1 = PASAR,
X2 = SWALAYAN,
X3 = RESTORAN,
X4 = AKOMODASI,
X5 = PERBANKAN
)
if (!id_col %in% names(df)) {
stop(paste("Kolom", id_col, "tidak ditemukan! Periksa header Excel Anda."))
}
num_cols <- c("X1", "X2", "X3", "X4", "X5")
df <- df %>%
mutate(across(all_of(num_cols), ~ replace_na(., median(., na.rm = TRUE))))
X <- df %>% select(all_of(num_cols)) %>% as.data.frame()Variabel infrastruktur ekonomi memiliki skala yang berbeda . Oleh karena itu, dilakukan Z-score Standardization agar semua variabel memiliki kontribusi yang setara dalam perhitungan jarak antar klaster.
## X1 X2 X3 X4 X5
## [1,] 1.7702905 -0.27090233 0.95324111 1.20262529 -0.2934276
## [2,] -0.2950484 -1.13286431 -1.10240354 -1.03916166 -1.0759012
## [3,] 0.3933979 -0.09850994 1.08375823 0.96910582 0.2282215
## [4,] 1.0818442 1.79780640 1.24690463 0.66553050 1.2063135
## [5,] -0.2950484 -0.01231374 -1.00451570 -1.06251361 -0.1630153
## [6,] 0.3933979 2.48737598 2.03000736 0.08173182 2.7712606
## [7,] -0.9834947 -0.44329473 -0.35193009 -0.33860324 -0.4238399
## [8,] -0.9834947 -1.04666811 -0.74348145 -0.71223440 -0.9454889
## [9,] 1.7702905 -0.61568712 -0.84136930 -0.85234608 0.3586337
## [10,] -0.9834947 -0.44329473 -1.03714498 -0.82899413 -0.4890460
## [11,] 0.3933979 -0.18470614 0.20276767 -0.36195519 -0.1630153
## [12,] -0.9834947 0.33247105 -0.09089585 2.34687072 -0.6194583
## [13,] -0.2950484 -0.44329473 -0.64559361 -0.40865908 0.3586337
## [14,] -0.9834947 0.07388245 0.30065551 0.33860324 -0.7498705
## attr(,"scaled:center")
## X1 X2 X3 X4 X5
## 2.428571 15.142857 35.785714 61.500000 17.500000
## attr(,"scaled:scale")
## X1 X2 X3 X4 X5
## 1.452546 11.601440 30.647320 42.822981 15.335981
Outlier dapat menarik pusat klaster (centroid) secara ekstrem, sehingga hasil clustering menjadi tidak akurat. Menggunakan Jarak Mahalanobis yang mempertimbangkan korelasi antar variabel untuk mendeteksi kecamatan dengan karakteristik infrastruktur yang sangat tidak biasa dibandingkan wilayah lainnya.
center <- colMeans(X_scaled)
cov_matrix <- cov(X_scaled)
md <- mahalanobis(X_scaled, center = center, cov = cov_matrix)
alpha <- 0.05
cutoff <- qchisq(1 - alpha, df = ncol(X_scaled))
df$Mahalanobis_Distance <- md
df$Outlier <- ifelse(md > cutoff, "Outlier", "Tidak")
cat("=== HASIL DETEKSI OUTLIER ===\n")## === HASIL DETEKSI OUTLIER ===
## # A tibble: 14 × 3
## KECAMATAN Mahalanobis_Distance Outlier
## <chr> <dbl> <chr>
## 1 MANTRIJERON 6.40 Tidak
## 2 KRATON 2.26 Tidak
## 3 MERGANGSAN 4.82 Tidak
## 4 UMBULHARJO 5.77 Tidak
## 5 KOTAGEDE 3.49 Tidak
## 6 GONDOKUSUMAN 9.05 Tidak
## 7 DANUREJAN 1.44 Tidak
## 8 PAKUALAMAN 2.36 Tidak
## 9 GONDOMANAN 7.14 Tidak
## 10 NGAMPILAN 1.80 Tidak
## 11 WIROBRAJAN 1.38 Tidak
## 12 GEDONG TENGEN 10.6 Tidak
## 13 JETIS 4.68 Tidak
## 14 TEGALREJO 3.86 Tidak
##
## Jumlah Outlier: 0
Sebelum melakukan clustering, kami melakukan uji KMO (Kaiser-Meyer-Olkin) untuk memastikan kecukupan sampel dan uji VIF (Variance Inflation Factor) untuk mendeteksi multikolinearitas.
## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = X_scaled)
## Overall MSA = 0.58
## MSA for each item =
## X1 X2 X3 X4 X5
## 0.45 0.59 0.76 0.41 0.54
#UJI MULTIKOLINEARITAS
vif_values <- sapply(num_cols, function(var){
y <- df[[var]]
x_vars <- num_cols[num_cols != var]
formula <- as.formula(
paste(var, "~", paste(x_vars, collapse = "+"))
)
model <- lm(formula, data = df)
r2 <- summary(model)$r.squared
vif <- 1 / (1 - r2)
return(vif)
})
vif_result <- data.frame(
Variabel = num_cols,
VIF = vif_values
)
cat("=== HASIL UJI MULTIKOLINEARITAS (VIF) ===\n")## === HASIL UJI MULTIKOLINEARITAS (VIF) ===
## Variabel VIF
## X2 X2 7.787928
## X5 X5 7.572016
## X3 X3 4.766118
## X4 X4 2.488202
## X1 X1 1.739133
Menggunakan metode Silhouette Coefficient untuk menentukan jumlah kelompok (k) terbaik. Metode ini mengukur seberapa dekat sebuah data dengan kelompoknya sendiri dibandingkan dengan kelompok lain.
fviz_nbclust(
X_scaled,
kmeans,
method = "silhouette",
k.max = k_max
) +
geom_point(size = 3) +
theme_minimal()sil_results <- data.frame()
for(k in k_min:k_max){
km <- kmeans(X_scaled, centers = k, nstart = 25)
ss <- silhouette(km$cluster, dist(X_scaled))
avg_sil <- mean(ss[, 3])
sil_results <- rbind(
sil_results,
data.frame(
k = k,
avg_silhouette = avg_sil
)
)
}
sil_ranking <- sil_results %>%
arrange(desc(avg_silhouette))
cat("=== RANKING NILAI SILHOUETTE ===\n")## === RANKING NILAI SILHOUETTE ===
## k avg_silhouette
## 1 2 0.3789327
## 2 3 0.3528985
## 3 4 0.3190462
## 4 5 0.3059025
k_terpilih <- sil_ranking$k[1]
cat("\nJumlah Klaster Optimal (Berdasarkan Silhouette Tertinggi):",
k_terpilih, "\n")##
## Jumlah Klaster Optimal (Berdasarkan Silhouette Tertinggi): 2
profil_mean <- df %>%
group_by(cluster) %>%
summarise(across(all_of(num_cols), mean), .groups = "drop")
profil_long <- profil_mean %>%
pivot_longer(cols = all_of(num_cols),
names_to = "Variabel",
values_to = "Rata_Rata")
variable_labels <- c(X1 = "Pasar", X2 = "Swalayan", X3 = "Restoran",
X4 = "Akomodasi", X5 = "Perbankan")
ggplot(profil_long, aes(x = Variabel, y = Rata_Rata, fill = cluster)) +
geom_bar(stat = "identity", position = "dodge", color = "white") +
scale_x_discrete(labels = variable_labels) +
scale_fill_manual(values = cluster_colors) +
theme_minimal() +
labs(
title = "Perbandingan Infrastruktur Ekonomi antar Klaster",
x = "Jenis Infrastruktur",
y = "Rata-rata Jumlah (Unit)",
fill = "Klaster"
) +
geom_text(aes(label = round(Rata_Rata, 1)),
position = position_dodge(width = 0.9),
vjust = -0.5, size = 3)df <- df %>%
mutate(Nama_Klaster = case_when(
cluster == 1 ~ "Ekonomi Lokal",
cluster == 2 ~ "Pusat Ekonomi & Wisata"
))
anggota_klaster <- df %>%
group_by(cluster) %>%
summarise(
Jumlah_Kecamatan = n(),
Daftar_Kecamatan = paste(KECAMATAN, collapse = ", "),
.groups = "drop"
)
profil_mean <- df %>%
group_by(cluster) %>%
summarise(across(all_of(num_cols), mean), .groups = "drop")
anggota <- df %>%
group_by(cluster) %>%
summarise(
Jumlah = n(),
Daftar_Kecamatan = paste(KECAMATAN, collapse = ", "),
.groups = "drop"
)
tabel_final <- profil_mean %>%
left_join(anggota, by = "cluster") %>%
rename(
Klaster = cluster,
`X1` = X1,
`X2` = X2,
`X3` = X3,
`X4` = X4,
`X5` = X5
)
tabel_final %>%
kable(
caption = "Profil Infrastruktur Ekonomi dan Keanggotaan Klaster",
digits = 2,
align = "c"
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = F,
position = "center"
) %>%
column_spec(1, bold = T, border_right = T) %>%
column_spec(8, width = "30em", italic = T) | Klaster | X1 | X2 | X3 | X4 | X5 | Jumlah | Daftar_Kecamatan |
|---|---|---|---|---|---|---|---|
| 1 | 2.0 | 9.67 | 18.0 | 36.44 | 11.89 | 9 | KRATON, KOTAGEDE, DANUREJAN, PAKUALAMAN, GONDOMANAN, NGAMPILAN, WIROBRAJAN, JETIS, TEGALREJO |
| 2 | 3.2 | 25.00 | 67.8 | 106.60 | 27.60 | 5 | MANTRIJERON, MERGANGSAN, UMBULHARJO, GONDOKUSUMAN, GEDONG TENGEN |
Cluster 1 memiliki karakteristik sebagai wilayah infrastruktur ekonomi relatif rendah. Wilayah ini cenderung memiliki intensitas aktivitas perdagangan dan jasa yang lebih rendah, sehingga dapat menjadi prioritas dalam upaya pemerataan pembangunan dan penguatan infrastruktur ekonomi guna mengurangi kesenjangan antar kecamatan di Kota Yogyakarta.
Cluster 2 memiliki karakteristik sebagai wilayah infrastruktur ekonomi yang tinggi. Tingginya konsentrasi fasilitas perdagangan, jasa, serta layanan keuangan tersebut menunjukkan bahwa kecamatan dalam cluster ini merupakan wilayah dengan tingkat aktivitas ekonomi yang relatif lebih intensif dan terpusat. Ketersediaan infrastruktur yang lebih lengkap mencerminkan peran wilayah ini sebagai pusat distribusi barang dan jasa, sekaligus sebagai simpul utama dalam dinamika perekonomian kota.
Berikut merupakan visualisasi cluster yang dapat digunakan untuk melihat lebih jelas tentang hasil cluster kecamatan di Kota Yogyakarta berdasarkan infrastruktur ekonomi pada tahun 2025 dengan 2 cluster.
pca <- prcomp(X_scaled, center = TRUE, scale. = FALSE)
var_pct <- (pca$sdev^2) / sum(pca$sdev^2) * 100
plot_df <- data.frame(
Dim1 = pca$x[, 1],
Dim2 = pca$x[, 2],
cluster = factor(final_model$cluster),
Kecamatan = df[[id_col]]
)
hulls <- plot_df %>%
group_by(cluster) %>%
slice(chull(Dim1, Dim2))
cluster_colors <- scales::hue_pal()(k_terpilih)
ggplot(plot_df, aes(Dim1, Dim2, color = cluster)) +
geom_polygon(
data = hulls,
aes(fill = cluster),
alpha = 0.2,
color = NA
) +
geom_point(size = 3) +
geom_text(aes(label = Kecamatan), vjust = -0.6, size = 3) +
scale_color_manual(values = cluster_colors)+
scale_fill_manual(values = cluster_colors)+
theme_minimal() +
labs(
title = "Visualisasi Klaster K-Means",
x = paste0("Dimensi 1 (", round(var_pct[1], 1), "%)"),
y = paste0("Dimensi 2 (", round(var_pct[2], 1), "%)")
) +
guides(fill = "none")Berikut merupakan visualisasi peta Kota yogyakrta yang dapat digunakan untuk melihat lebih jelas tentang hasil cluster kecamatan di Kota Yogyakarta berdasarkan infrastruktur ekonomi pada tahun 2025.
path_rds <- "D:/SEMESTER 6/1. KP/yogyakarta_map.rds"
if (file.exists(path_rds)) {
cat("Memuat data peta dari penyimpanan lokal...\n")
kota_yk <- readRDS(path_rds)
} else {
cat("Mengunduh data peta baru dari GADM...\n")
tryCatch({
indo <- geodata::gadm(country = "IDN", level = 3, path = tempdir(), version = "latest")
indo_sf <- sf::st_as_sf(indo)
kota_yk <- indo_sf %>%
dplyr::filter(NAME_1 == "Yogyakarta",
NAME_2 == "Kota Yogyakarta") %>%
dplyr::rename(Kecamatan = NAME_3)
saveRDS(kota_yk, path_rds)
cat("Data peta berhasil disimpan ke lokal.\n")
}, error = function(e) {
stop("Gagal mendapatkan data peta. Periksa koneksi internet.")
})
}## Memuat data peta dari penyimpanan lokal...
df$Kecamatan <- toupper(trimws(df[[id_col]]))
kota_yk$Kecamatan <- toupper(trimws(kota_yk$Kecamatan))
map_data <- kota_yk %>%
left_join(df, by = "Kecamatan")
centroids <- st_centroid(map_data)## Warning: st_centroid assumes attributes are constant over geometries
coords <- centroids %>%
mutate(
X = st_coordinates(.)[,1],
Y = st_coordinates(.)[,2]
) %>%
st_drop_geometry()
ggplot(data = map_data) +
geom_sf(aes(fill = cluster), color = "white", size = 0.3) +
geom_text_repel(
data = coords,
aes(x = X, y = Y, label = Kecamatan),
size = 2.8, # Ukuran teks
fontface = "bold", # Tebal
box.padding = 0.5, # Jarak antar teks
max.overlaps = Inf # Tampilkan semua nama kecamatan
) +
scale_fill_manual(values = cluster_colors, na.value = "grey80") +
theme_minimal() +
labs(
title = "Peta Distribusi Klaster Infrastruktur Ekonomi",
subtitle = "Kota Yogyakarta - Tahun 2025",
fill = "Klaster"
) +
theme(
axis.text = element_blank(),
axis.title = element_blank(),
panel.grid = element_blank(),
legend.position = "right"
)
Secara keseluruhan, hasil pengelompokan ini menunjukkan bahwa setiap
cluster memiliki karakteristik dan peran yang berbeda dalam pembangunan
infrastruktur ekonomi Kota Yogyakarta. Informasi ini dapat menjadi dasar
dalam perumusan kebijakan pembangunan infrastruktur ekonomi yang lebih
terarah dan berbasis karakteristik wilayah.