Analisis ini menggunakan metode K-Medoids Clustering dengan tujuan mengelompokkan kabupaten/kota di Provinsi Jawa Tengah berdasarkan kesamaan karakteristik kesejahteraan sosial. Dengan metode ini, diharapkan pola kesejahteraan sosial antarwilayah dapat diidentifikasi secara lebih jelas sehingga pemerintah daerah dapat merumuskan kebijakan dan strategi pembangunan yang lebih tepat sasaran sesuai dengan kondisi masing-masing daerah.
Rendahnya capaian IPM, tingginya tingkat pengangguran dan kemiskinan, serta keterbatasan akses sanitasi layak di beberapa kabupaten/kota di Provinsi Jawa Tengah menunjukkan adanya permasalahan kesejahteraan sosial dan ketimpangan antarwilayah. Meskipun pemerintah daerah telah melaksanakan berbagai program pembangunan, kesenjangan kesejahteraan sosial masih menjadi tantangan. Sehingga kebijakan yang bersifat seragam belum tentu efektif dan memerlukan pemahaman yang lebih mendalam terhadap karakteristik masing-masing daerah agar kebijakan yang diterapkan dapat lebih tepat sasaran.
Variabel yang digunakan yaitu Indeks Pembangunan Manusia (IPM) sebagai X1. Tingkat Pengangguran Terbuka (TPT) sebagai X2. Persentase penduduk miskin sebagai X3. Persentase rumah tangga yang memiliki akses terhadap sanitasi layak sebagai X4.
Tahapan pada analisis ini meliputi: 1.) Mendeskripsikan data Indeks
Pembangunan Manusia (IPM), Tingkat Pengangguran Terbuka (TPT),
persentase penduduk miskin, dan persentase rumah tangga yang memiliki
akses terhadap sanitasi layak di Provinsi Jawa Tengah menggunakan
statistik deskriptif dan visualisasi Box-Plot. 2.) Melakukan Normalisasi
Min-Max.
3.) Melakukan uji asumsi sampel mewakili populasi (sample
representative) dengan uji Kaiser Mayer Olkin (KMO) pada variabel Indeks
Pembangunan Manusia (IPM), Tingkat Pengangguran Terbuka (TPT),
persentase pendudukmiskin, dan persentase rumah tangga yang memiliki
akses terhadap sanitasi layak. 4.) Melakukan uji asumsi
non-multikolinearitas untuk mengetahui ada atau tidaknya hubungan
antarvariabel yang digunakan. 5.) Menentukan jumlah cluster yang optimal
menggunakan metode Silhouette. 6.) Melakukan analisis clustering dengan
metode K-Medoids Clustering. 7.) Menginterpretasikan hasil analisis
cluster. 8.) Melakukan profilling cluster. 9.) Visualisasi persebaran
cluster. 10.) Peta Cluster
Outlier adalah observasi yang memiliki nilai sangat berbeda dari sebagian besar data lainnya. Keberadaannya dapat memberikan informasi penting atau menunjukkan kesalahan data, namun juga berpotensi mengganggu analisis dan menghasilkan kesimpulan yang tidak akurat. Deteksi outlier dapat dilakukan secara visual menggunakan boxplot dengan metode IQR. Data yang berada di luar batas whisker pada boxplot dikategorikan sebagai outlier.
Normalisasi data bertujuan menyamakan skala variabel agar perbedaan rentang nilai tidak memengaruhi hasil analisis. Salah satu metode yang digunakan adalah Min-Max Normalization, yaitu transformasi linear menggunakan nilai minimum dan maksimum untuk mengubah data ke rentang [0,1], dengan rumus sebagai berikut: \[ \hat{x}_{ij} = \frac{x_{ij} - \min_j}{\max_j - \min_j}, \quad i = 1,2,\ldots,n \quad \text{dan} \quad j = 1,2,\ldots,p \]
Sampel representatif adalah sampel yang mampu menggambarkan karakteristik populasi. Keterwakilan sampel diuji menggunakan Kaiser-Meyer-Olkin (KMO) untuk menilai kecukupan sampel dan kelayakan analisis faktor. Nilai KMO digunakan untuk menentukan apakah sampel telah mewakili populasi. Berikut rumus KMO:
\[ KMO = \frac{ \sum_{k=1}^{p}\sum_{l=1,\, l \neq k}^{p} r_{kl}^2 }{ \sum_{k=1}^{p}\sum_{l=1,\, l \neq k}^{p} r_{kl}^2 + \sum_{k=1}^{p}\sum_{l=1,\, l \neq k}^{p} p_{kl}^2 } \]
Multikolinearitas adalah adanya hubungan linear antarvariabel yang dapat menyebabkan distorsi atau penyimpangan dalam perhitungan jarak pada analisis cluster, sehingga hasil pengelompokan menjadi kurang akurat dan sulit diinterpretasikan. Oleh karena itu, diperlukan uji untuk mendeteksi ada tidaknya multikolinearitas dalam data. Berikut rumus VIF:
\[ VIF_i = \frac{1}{1 - R_i^2} \]
K-Medoids Clustering adalah metode clustering unsupervised yang membagi data ke dalam k kelompok berdasarkan kemiripan. Perbedaannya dengan K-Means terletak pada penentuan pusat cluster. K-Means menggunakan nilai rata-rata (mean), sedangkan K-Medoids menggunakan medoid, yaitu salah satu objek data yang memiliki ketidakmiripan rata-rata paling kecil. Penggunaan medoid membuat K-Medoids lebih robust terhadap noise dan outlier, sehingga hasil pengelompokan lebih stabil dan representatif.
Silhouette Coefficient merupakan metode validasi internal untuk menilai kualitas dan kekuatan cluster berdasarkan ketepatan penempatan objek dalam cluster. Nilainya berada pada rentang −1 hingga 1, di mana semakin mendekati 1 menunjukkan kualitas pengelompokan yang semakin baik, sedangkan nilai mendekati −1 menunjukkan kualitas pengelompokan yang buruk. Rata-rata nilai Silhouette Coefficient digunakan sebagai ukuran tingkat kemiripan data dalam cluster yang sama. Terdapat beberapa tahapan dalam perhitungan Silhouette Coefficient, yaitu:
\[ b(i) = \min_{C \ne A} d(i,C) \] dengan:
Dengan rata-rata Silhouette Coefficient:
\[ SC = \frac{1}{n} \sum_{i=1}^{n} s(i) \]
## Warning: package 'readxl' was built under R version 4.3.3
## # A tibble: 6 × 5
## `Kabupaten/Kota` IPM TPT Persentase Penduduk Misk…¹ Persentase Rumah Tan…²
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Cilacap 72.4 7.83 10.7 83.2
## 2 Banyumas 74.5 6.18 12.0 83.2
## 3 Purbalingga 70.7 4.96 14.2 82.0
## 4 Banjarnegara 69.6 5.57 14.7 52.4
## 5 Kebumen 71.9 5.07 15.7 93.4
## 6 Purworejo 75.1 3.89 10.9 84.6
## # ℹ abbreviated names: ¹​`Persentase Penduduk Miskin`,
## # ²​`Persentase Rumah Tangga dengan Akses Sanitasi Layak`
Interpretasi
Berdasarkan output head(data), dapat dilihat bahwa data yang digunakan memuat beberapa variabel yang akan dianalisis. Tampilan enam observasi pertama menunjukkan struktur data serta tipe variabel yang tersedia dalam analisis ini.
## # A tibble: 6 × 4
## IPM TPT `Persentase Penduduk Miskin` Persentase Rumah Tangga dengan Akse…¹
## <dbl> <dbl> <dbl> <dbl>
## 1 72.4 7.83 10.7 83.2
## 2 74.5 6.18 12.0 83.2
## 3 70.7 4.96 14.2 82.0
## 4 69.6 5.57 14.7 52.4
## 5 71.9 5.07 15.7 93.4
## 6 75.1 3.89 10.9 84.6
## # ℹ abbreviated name: ¹​`Persentase Rumah Tangga dengan Akses Sanitasi Layak`
Interpretasi
Pada tahap ini dipilih variabel numerik X1, X2, X3, dan X4 untuk dianalisis. Enam observasi pertama ditampilkan guna memastikan kesesuaian dan kesiapan data untuk analisis selanjutnya.
## IPM TPT Persentase Penduduk Miskin
## Min. :68.46 Min. :2.35 Min. : 4.030
## 1st Qu.:71.86 1st Qu.:3.50 1st Qu.: 7.555
## Median :74.32 Median :3.97 Median : 9.630
## Mean :74.75 Mean :4.52 Mean :10.129
## 3rd Qu.:77.22 3rd Qu.:5.32 3rd Qu.:11.995
## Max. :85.72 Max. :8.35 Max. :15.710
## Persentase Rumah Tangga dengan Akses Sanitasi Layak
## Min. :52.40
## 1st Qu.:83.25
## Median :88.26
## Mean :86.57
## 3rd Qu.:95.42
## Max. :98.54
Interpretasi
Berdasarkan hasil statistik deskriptif, diperoleh informasi mengenai nilai minimum, maksimum, mean, dan kuartil dari masing-masing variabel. Hasil ini memberikan gambaran umum mengenai karakteristik dan sebaran data sebelum dilakukan analisis lebih lanjut.
boxplot(data_kp$`Persentase Penduduk Miskin`,
main = "Boxplot Persentase Penduduk Miskin",
ylab = "Persentase Penduduk Miskin")boxplot(data_kp$`Persentase Rumah Tangga dengan Akses Sanitasi Layak`,
main = "Boxplot Persentase Rumah Tangga dengan Akses Sanitasi Layak",
ylab = "Persentase Rumah Tangga dengan Akses Sanitasi Layak")Interpretasi
Berdasarkan output menggunakan box-plot untuk melakukan pengecekan outlier dapat diketahui bahwa terdapat outlier pada variabel X1 (Indeks Pembangunan Manusia/IPM), X2 (Tingkat Pengangguran Terbuka/TPT), dan X4 (persentase rumah tangga dengan akses sanitasi layak). Sementara itu, pada variabel X3 (persentase penduduk miskin) tidak ditemukan adanya outlier.
# Membuat fungsi Min-Max
minmax <- function(x){
(x - min(x)) / (max(x) - min(x))
}
# Melakukan normalisasi pada seluruh variabel numerik
data_norm <- as.data.frame(lapply(data_kp, minmax))
# Menampilkan hasil normalisasi
head (data_norm)## IPM TPT Persentase.Penduduk.Miskin
## 1 0.22711472 0.9133333 0.5693493
## 2 0.35110081 0.6383333 0.6780822
## 3 0.12920046 0.4350000 0.8690068
## 4 0.06604867 0.5366667 0.9143836
## 5 0.20104287 0.4533333 1.0000000
## 6 0.38528389 0.2566667 0.5856164
## Persentase.Rumah.Tangga.dengan.Akses.Sanitasi.Layak
## 1 0.6686173
## 2 0.6686173
## 3 0.6417425
## 4 0.0000000
## 5 0.8892501
## 6 0.6987430
Interpretasi
Sebelum proses pengelompokan dilakukan, data dinormalisasi karena setiap variabel memiliki perbedaan satuan dan skala, untuk menghindari bias akibat perbedaan rentang nilai. Metode yang digunakan adalah Normalisasi Min-Max, yaitu mentransformasikan data ke dalam rentang 0 sampai 1, berdasarkan nilai minimum dan maksimum masing-masing variabel.
# Load package
library(psych)
# Membentuk matriks korelasi dari variabel numerik
cor_matrix <- cor(data[, c("IPM",
"TPT",
"Persentase Penduduk Miskin",
"Persentase Rumah Tangga dengan Akses Sanitasi Layak")])
# Uji KMO
kmo_result <- KMO(cor_matrix)
# Menampilkan hasil
kmo_result## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = cor_matrix)
## Overall MSA = 0.54
## MSA for each item =
## IPM
## 0.52
## TPT
## 0.84
## Persentase Penduduk Miskin
## 0.52
## Persentase Rumah Tangga dengan Akses Sanitasi Layak
## 0.55
Interpretasi
Berdasarkan output uji KMO dapat diketahui bahwa nilai KMO pada seluruh variabel ≥ 0.5, dapat disimpulkan bahwa sampel yang digunakan mewakili populasi atau sampel representatif, sehingga sudah cukup layak untuk dianalisis lebih lanjut.
# Load package yang diperlukan
library(car)
# Membuat fungsi VIF untuk semua variabel
vif_all <- function(data_z) {
variables <- colnames(data_z)
vif_values <- c()
for (var in variables) {
independent_vars <- setdiff(variables, var)
# Memberi tanda backtick pada nama variabel yang mengandung spasi
quoted_independent_vars <- sapply(independent_vars,
function(x) paste0("`", x, "`"))
formula <- as.formula(
paste(paste0("`", var, "`"), "~",
paste(quoted_independent_vars, collapse = " + "))
)
model <- lm(formula, data = data_z)
vif_values[var] <- max(vif(model))
}
return(vif_values)
}
# Menjalankan fungsi
vif_result <- vif_all(data_kp)
# Menampilkan hasil
vif_result## IPM
## 1.069189
## TPT
## 2.443153
## Persentase Penduduk Miskin
## 1.296620
## Persentase Rumah Tangga dengan Akses Sanitasi Layak
## 1.970508
Interpretasi
Berdasarkan output uji VIF diketahui nilai VIF pada seluruh variabel berada di bawah 10, sehingga dapat disimpulkan bahwa tidak ada hubungan linear antar variabel (data tidak terjadi multikolinearitas) atau asumsi non-multikolinearitas terpenuhi.
# Load package
library(cluster)
library(factoextra)
# Reproducibility
set.seed(123)
# Visualisasi jumlah klaster optimal
silhouette <- fviz_nbclust(data_norm, pam, method = "silhouette") +
labs(title = "Penentuan Jumlah Klaster Optimal (Silhouette)")
# Menampilkan plot
silhouette## clusters y
## 1 1 0.0000000
## 2 2 0.2571149
## 3 3 0.2580905
## 4 4 0.2855666
## 5 5 0.2348732
## 6 6 0.2089284
## 7 7 0.2192599
## 8 8 0.1953518
## 9 9 0.2270769
## 10 10 0.2285633
Interpretasi
Berdasarkan visualisasi grafik metode Silhouette, jumlah cluster optimal yang diperoleh adalah sebanyak 4 cluster, karena nilai koefisien Silhouette tertinggi terdapat pada pembentukan 4 cluster, yaitu sebesar 0.2855666.
# Load package
library(cluster)
# Reproducibility
set.seed(123)
# Proses clustering PAM dengan 4 klaster
pam_res <- pam(data_norm, k = 4)
# Menampilkan ringkasan hasil clustering
pam_res## Medoids:
## ID IPM TPT Persentase.Penduduk.Miskin
## [1,] 1 0.2271147 0.9133333 0.5693493
## [2,] 3 0.1292005 0.4350000 0.8690068
## [3,] 9 0.4345307 0.1350000 0.4794521
## [4,] 30 0.7931634 0.3416667 0.1635274
## Persentase.Rumah.Tangga.dengan.Akses.Sanitasi.Layak
## [1,] 0.6686173
## [2,] 0.6417425
## [3,] 0.7771998
## [4,] 0.7834850
## Clustering vector:
## [1] 1 1 2 2 2 3 2 3 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 1 3 2 1 1 4 4 4 4 4 4
## Objective function:
## build swap
## 0.3164493 0.3106064
##
## Available components:
## [1] "medoids" "id.med" "clustering" "objective" "isolation"
## [6] "clusinfo" "silinfo" "diss" "call" "data"
# Mengambil hasil klaster
final_cluster <- pam_res$clustering
# Melihat jumlah anggota tiap klaster
table(final_cluster)## final_cluster
## 1 2 3 4
## 5 5 18 7
# Menambahkan variabel klaster ke data awal
data$Cluster <- as.factor(final_cluster)
# Menampilkan kolom Cluster
data$Cluster## [1] 1 1 2 2 2 3 2 3 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 1 3 2 1 1 4 4 4 4 4 4
## Levels: 1 2 3 4
# Load package
library(dplyr)
# Menghitung rata-rata tiap variabel pada setiap klaster
cluster_summary <- data %>%
group_by(Cluster) %>%
summarise(
rata_X1 = mean(IPM),
rata_X2 = mean(TPT),
rata_X3 = mean(`Persentase Penduduk Miskin`),
rata_X4 = mean(`Persentase Rumah Tangga dengan Akses Sanitasi Layak`)
)
# Menampilkan hasil ringkasan
cluster_summary## # A tibble: 4 × 5
## Cluster rata_X1 rata_X2 rata_X3 rata_X4
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 1 71.4 7.11 10.8 81.1
## 2 2 70.1 5.25 15.0 75.2
## 3 3 74.3 3.51 10.1 89.1
## 4 4 81.6 4.73 6.38 92.1
# Membentuk matriks jarak gabungan (data + medoid)
dist_matrix <- as.matrix(
dist(rbind(data_norm, pam_res$medoids))
)
# Menentukan jumlah data dan jumlah medoid
num_data_points <- nrow(data_norm)
num_medoids <- nrow(pam_res$medoids)
# Mengambil jarak data ke masing-masing medoid
dist_to_medoid <- dist_matrix[
1:num_data_points,
(num_data_points + 1):(num_data_points + num_medoids)
]
# Membuat tabel hasil jarak
hasil_jarak_ke_medoid <- data.frame(
'Kabupaten/Kota' = data$'Kabupaten/Kota',
Medoid1 = dist_to_medoid[,1],
Medoid2 = dist_to_medoid[,2],
Medoid3 = dist_to_medoid[,3],
Medoid4 = dist_to_medoid[,4],
Cluster = data$Cluster
)
# Menampilkan hasil
head (hasil_jarak_ke_medoid)## Kabupaten.Kota Medoid1 Medoid2 Medoid3 Medoid4 Cluster
## 1 Cilacap 0.0000000 0.5735040 0.8177383 0.9083501 1
## 2 Banyumas 0.3206562 0.3574335 0.5581658 0.7492608 1
## 3 Purbalingga 0.5735040 0.0000000 0.5944141 0.9835396 2
## 4 Banjarnegara 0.8566900 0.6543827 1.0441839 1.3207402 2
## 5 Kebumen 0.6681457 0.2896837 0.6628560 1.0363150 2
## 6 Purworejo 0.6763141 0.4253712 0.1861569 0.5991086 3
Interpretasi
Pengelompokan dilakukan berdasarkan medoid sebagai pusat cluster, sedangkan nilai rata-rata digunakan untuk menggambarkan karakteristik umum tiap cluster.
Cluster 1 (5 kab/kota) IPM menengah (71,374) dengan TPT relatif tinggi (7,112%) dan kemiskinan 10,754%. Akses sanitasi cukup baik (81,072%). Menunjukkan pembangunan manusia menengah, namun masih menghadapi masalah pengangguran dan kemiskinan.
Cluster 2 (5 kab/kota) Memiliki kemiskinan tertinggi (14,960%) dan sanitasi terendah (75,194%), dengan IPM relatif rendah (70,118) dan TPT 5,250%. Permasalahan utama terletak pada kemiskinan dan kualitas hidup, bukan pengangguran.
Cluster 3 (18 kab/kota) IPM cukup tinggi (74,293), TPT terendah (3,513%), kemiskinan 10,070%, dan sanitasi baik (89,102%). Menggambarkan kondisi kesejahteraan sosial yang relatif baik.
Cluster 4 (7 kab/kota) Memiliki IPM tertinggi (81,638), kemiskinan terendah (6,381%), TPT 4,733%, dan sanitasi tertinggi (92,096%). Merupakan cluster dengan tingkat kesejahteraan sosial terbaik.
library(dplyr)
# ===============================
# 1. Persiapan Data
# ===============================
# Ambil nama variabel dari data normalisasi
feature_cols <- colnames(data_norm)
# Gabungkan data normalisasi + cluster
df_prof <- data_norm %>%
mutate(Cluster = data$Cluster)
# ===============================
# 2. Rata-rata per Klaster & Overall
# ===============================
mean_cluster <- df_prof %>%
group_by(Cluster) %>%
summarise(across(all_of(feature_cols), mean, na.rm = TRUE),
.groups = "drop")
mean_overall <- df_prof %>%
summarise(across(all_of(feature_cols), mean, na.rm = TRUE))
# ===============================
# 3. Fungsi Label Tinggi/Rendah
# ===============================
label_level <- function(x, tol = 0.05){
ifelse(x > tol, "tinggi",
ifelse(x < -tol, "rendah", "sedang"))
}
# ===============================
# 4. Hitung Selisih & Label
# ===============================
profil_norm <- mean_cluster
for(v in feature_cols){
profil_norm[[paste0(v, "_diff")]] <-
profil_norm[[v]] - mean_overall[[v]]
profil_norm[[paste0(v, "_level")]] <-
label_level(profil_norm[[paste0(v, "_diff")]])
}
profil_norm## # A tibble: 4 × 13
## Cluster IPM TPT Persentase.Penduduk.Mis…¹ Persentase.Rumah.Tan…² IPM_diff
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 0.169 0.794 0.576 0.621 -0.196
## 2 2 0.0961 0.483 0.936 0.494 -0.268
## 3 3 0.338 0.194 0.517 0.795 -0.0264
## 4 4 0.764 0.397 0.201 0.860 0.399
## # ℹ abbreviated names: ¹​Persentase.Penduduk.Miskin,
## # ²​Persentase.Rumah.Tangga.dengan.Akses.Sanitasi.Layak
## # ℹ 7 more variables: IPM_level <chr>, TPT_diff <dbl>, TPT_level <chr>,
## # Persentase.Penduduk.Miskin_diff <dbl>,
## # Persentase.Penduduk.Miskin_level <chr>,
## # Persentase.Rumah.Tangga.dengan.Akses.Sanitasi.Layak_diff <dbl>,
## # Persentase.Rumah.Tangga.dengan.Akses.Sanitasi.Layak_level <chr>
# ===============================
# 5. Profilisasi Klaster
# ===============================
# Level cluster yang sebenarnya (lebih aman dari 1:k)
cluster_levels <- unique(data$Cluster)
# Daftar kabupaten/kota per klaster
kabkota_cluster <- data %>%
group_by(Cluster) %>%
summarise(
n = n(),
KabKota = paste(`Kabupaten/Kota`, collapse = ", "),
.groups = "drop"
)
# Narasi profil klaster
narasi <- sapply(cluster_levels, function(cl){
row <- profil_norm %>% filter(Cluster == cl)
info <- kabkota_cluster %>% filter(Cluster == cl)
parts <- sapply(feature_cols, function(v){
lvl <- row[[paste0(v, "_level")]]
paste0(gsub("\\.", " ", v), " ", lvl)
})
paste0(
"Klaster ", cl, " (", info$n, " kabupaten/kota: ",
info$KabKota, ") dicirikan oleh ",
paste(parts, collapse = ", "),
"."
)
})
cat(paste(narasi, collapse = "\n\n")) ## Klaster 1 (5 kabupaten/kota: Cilacap, Banyumas, Batang, Tegal, Brebes) dicirikan oleh IPM rendah, TPT tinggi, Persentase Penduduk Miskin tinggi, Persentase Rumah Tangga dengan Akses Sanitasi Layak rendah.
##
## Klaster 2 (5 kabupaten/kota: Purbalingga, Banjarnegara, Kebumen, Wonosobo, Pemalang) dicirikan oleh IPM rendah, TPT tinggi, Persentase Penduduk Miskin tinggi, Persentase Rumah Tangga dengan Akses Sanitasi Layak rendah.
##
## Klaster 3 (18 kabupaten/kota: Purworejo, Magelang, Boyolali, Klaten, Wonogiri, Karanganyar, Sragen, Grobogan, Blora, Rembang, Pati, Kudus, Jepara, Demak, Semarang, Temanggung, Kendal, Pekalongan) dicirikan oleh IPM sedang, TPT rendah, Persentase Penduduk Miskin sedang, Persentase Rumah Tangga dengan Akses Sanitasi Layak tinggi.
##
## Klaster 4 (7 kabupaten/kota: Sukoharjo, Kota Magelang, Kota Surakarta, Kota Salatiga, Kota Semarang, Kota Pekalongan, Kota Tegal) dicirikan oleh IPM tinggi, TPT sedang, Persentase Penduduk Miskin rendah, Persentase Rumah Tangga dengan Akses Sanitasi Layak tinggi.
Interpretasi
Cluster 1 (5 kabupaten): Kabupaten Cilacap, Banyumas, Batang, Tegal, dan Brebes. Memiliki IPM tingkat menengah, tingkat pengangguran relatif tinggi, serta persentase penduduk miskin cukup besar. Akses sanitasi sudah cukup baik, namun masih menghadapi tantangan pada aspek ketenagakerjaan dan kemiskinan.
Cluster 2 (5 kabupaten): Kabupaten Purbalingga, Banjarnegara, Kebumen, Wonosobo, dan Pemalang. Ditandai IPM relatif rendah, tingkat kemiskinan tinggi, dan akses sanitasi yang masih rendah. Permasalahan utama terletak pada kemiskinan dan kualitas hidup masyarakat.
Cluster 3 (18 kabupaten): Mayoritas kabupaten di Jawa Tengah bagian tengah–timur. Memiliki IPM cukup tinggi, tingkat pengangguran rendah, kemiskinan lebih kecil, dan akses sanitasi tinggi. Termasuk wilayah dengan kondisi kesejahteraan sosial yang relatif baik.
Cluster 4 (7 kabupaten/kota): Kabupaten Sukoharjo serta Kota Magelang, Surakarta, Salatiga, Semarang, Pekalongan, dan Tegal. Memiliki IPM tertinggi, kemiskinan terendah, dan akses sanitasi sangat baik. Menjadi cluster dengan tingkat kesejahteraan sosial terbaik dibandingkan cluster lainnya.
# Load package
library(factoextra)
# Visualisasi klaster
fviz_cluster(pam_res,
data = data_norm,
ellipse.type = "convex", # Garis convex hull tiap klaster
repel = TRUE, # Menghindari overlap label
ggtheme = theme_minimal(),
main = "Visualisasi K-Medoid Clustering")Interpretasi
Wilayah yang ditandai dengan warna merah merepresentasikan Cluster 1, yang terdiri dari 5 kabupaten, yaitu Kabupaten Cilacap, Kabupaten Banyumas, Kabupaten Batang, Kabupaten Tegal, dan Kabupaten Brebes. Selanjutnya, wilayah berwarna hijau menunjukkan Cluster 2 yang terdiri dari 5 kabupaten, yaitu Kabupaten Purbalingga, Kabupaten Banjarnegara, Kabupaten Kebumen, Kabupaten Wonosobo, dan Kabupaten Pemalang. Wilayah yang ditandai dengan warna biru merupakan Cluster 3, yang mencakup 18 kabupaten, yaitu Kabupaten Purworejo, Kabupaten Magelang, Kabupaten Boyolali, Kabupaten Klaten, Kabupaten Wonogiri, Kabupaten Karanganyar, Kabupaten Sragen, Kabupaten Grobogan, Kabupaten Blora, Kabupaten Rembang, Kabupaten Pati, Kabupaten Kudus, Kabupaten Jepara, Kabupaten Demak, Kabupaten Semarang, Kabupaten Temanggung, Kabupaten Kendal, dan Kabupaten Pekalongan. Sementara itu, wilayah yang ditampilkan dengan warna ungu merupakan Cluster 4, yang terdiri dari 7 kabupaten/kota, yaitu Kabupaten Sukoharjo, Kota Magelang, Kota Surakarta, Kota Salatiga, Kota Semarang, Kota Pekalongan, dan Kota Tegal.
library(sf)
library(geodata)
library(ggplot2)
library(dplyr)
options(timeout = 600)
# Ambil peta Indonesia
indo <- gadm("IDN", level = 2, path = tempdir())
# Cek apakah berhasil
if (is.null(indo)) {
stop("Data peta gagal diunduh dari GADM. Coba jalankan ulang atau cek koneksi internet.")
}
# Filter Jawa Tengah
jateng_map <- indo[indo$NAME_1 == "Jawa Tengah", ]
# Konversi ke sf
jateng_map_sf <- st_as_sf(jateng_map)
# Tambahan penting: Filter hanya Kabupaten & Kota
jateng_map_sf <- jateng_map_sf %>%
filter(ENGTYPE_2 %in% c("Regency", "City"))
# Tambahkan hanya untuk 2 wilayah ini saja
jateng_map_sf <- jateng_map_sf %>%
mutate(NAME_2 = case_when(
NAME_2 == "Salatiga" ~ "Kota Salatiga",
NAME_2 == "Surakarta" ~ "Kota Surakarta",
TRUE ~ NAME_2
))
# ===============================
# 2. Gabungkan Data Klaster
# ===============================
data_clustered <- data %>%
select(`Kabupaten/Kota`, Cluster)
jateng_map_clustered <- jateng_map_sf %>%
left_join(data_clustered,
by = c("NAME_2" = "Kabupaten/Kota"))
# ===============================
# 3. Titik Label
# ===============================
jateng_centroid <- st_point_on_surface(jateng_map_clustered)
# ===============================
# 4. Visualisasi
# ===============================
ggplot(data = jateng_map_clustered) +
geom_sf(aes(fill = as.factor(Cluster)),
color = "white", size = 0.3) +
geom_sf_text(
data = jateng_centroid,
aes(label = NAME_2),
size = 3,
color = "black"
) +
scale_fill_brewer(palette = "Set2", name = "Klaster") +
labs(
title = "Peta Hasil Klaster Kabupaten/Kota Provinsi Jawa Tengah",
subtitle = "Hasil K-Medoid (PAM) Clustering",
caption = "Sumber: GADM dan Data Penelitian (diolah)"
) +
theme_minimal()Berdasarkan hasil analisis K-Medoids Clustering terhadap indikator kesejahteraan sosial kabupaten/kota di Provinsi Jawa Tengah tahun 2024, diperoleh empat kelompok wilayah dengan karakteristik yang berbeda. Cluster 1 menunjukkan tingkat kesejahteraan relatif rendah dengan tingkat pengangguran dan kemiskinan yang cukup tinggi. Cluster 2 memiliki kondisi kesejahteraan yang belum optimal dengan IPM lebih rendah serta tingkat kemiskinan yang tinggi. Cluster 3 menggambarkan wilayah dengan kondisi kesejahteraan yang relatif baik, ditandai oleh IPM yang lebih tinggi serta tingkat kemiskinan dan pengangguran yang lebih rendah. Sementara itu, Cluster 4 merupakan kelompok wilayah dengan tingkat kesejahteraan sosial paling tinggi yang didominasi oleh wilayah perkotaan, dengan IPM tertinggi, tingkat kemiskinan paling rendah, serta akses sanitasi layak yang sangat baik. Pemerintah daerah diharapkan dapat memanfaatkan hasil pengelompokan wilayah ini sebagai bahan pertimbangan dalam merumuskan kebijakan dan program pembangunan yang lebih tepat sasaran guna meningkatkan kesejahteraan sosial masyarakat di setiap wilayah.