PENERAPAN METODE K-MEANS DALAM PENGELOMPOKAN PUSKESMAS DI KABUPATEN KENDAL BERDASARKAN INDIKATOR STATUS GIZI BALITA DAN KETERSEDIAAN LAYANAN KEBIDANAN

Latar Belakang

Pembangunan kesehatan merupakan prioritas nasional yang berdampak langsung pada kualitas sumber daya manusia dan produktivitas ekonomi. Namun, permasalahan gizi balita seperti stunting, wasting, dan underweight masih menjadi tantangan besar yang memerlukan penanganan strategis melalui Puskesmas sebagai fasilitas kesehatan tingkat pertama. Di Kabupaten Kendal, keragaman karakteristik wilayah memicu variasi kondisi gizi balita dan ketersediaan layanan kesehatan, sehingga diperlukan pemetaan yang akurat. Penggunaan metode K-Means clustering dalam penelitian ini bertujuan untuk mengelompokkan Puskesmas berdasarkan kemiripan karakteristik tersebut guna mendukung pengambilan kebijakan dan penentuan prioritas intervensi yang lebih tepat sasaran.

Input Data

Status Gizi Balita

Status gizi balita merupakan indikator penting kesehatan masyarakat yang memengaruhi perkembangan fisik, kognitif, dan daya tahan tubuh anak, sehingga pemantauannya dilakukan secara komprehensif melalui tiga indikator antropometri utama menurut WHO, yaitu stunting, wasting, dan underweight.

  • Stunting : kondisi gagal tumbuh pada balita yang ditandai dengan panjang atau tinggi badan menurut umur berada di bawah standar yang ditetapkan.

  • Wasting : kondisi balita dengan berat badan menurut tinggi badan yang rendah, yang menunjukkan adanya kekurangan gizi akut.

  • Underweight : kondisi berat badan menurut umur yang berada di bawah standar. Indikator ini mencerminkan kombinasi antara kekurangan gizi kronis dan akut.

Ketersediaan Tenaga Kebidanan

Tenaga kebidanan merupakan bagian penting dalam pelayanan kesehatan ibu dan anak yang memiliki kompetensi memberikan pelayanan sejak masa kehamilan, persalinan, nifas, hingga pemantauan tumbuh kembang anak. Ketersediaan dan pemerataan tenaga kebidanan berperan dalam meningkatkan kualitas pelayanan kesehatan, menurunkan angka kematian ibu dan bayi, serta mendukung pencegahan dan penanganan masalah gizi balita melalui edukasi gizi, pemantauan pertumbuhan, dan deteksi dini masalah gizi.

library(readxl) 
## Warning: package 'readxl' was built under R version 4.3.3
data <- read_excel("D:/DATA STATUS GIZI DAN LAYANAN KEBIDANAN.xlsx")
data
## # A tibble: 30 × 5
##    Puskesmas    Stunting Wasting Underweight Tenaga
##    <chr>           <dbl>   <dbl>       <dbl>  <dbl>
##  1 Plantungan       8.47    4.11         7.8     19
##  2 Sukorejo 01     18.5     5.61        11.6     22
##  3 Sukorejo 02      9.39    4.02         6.6     17
##  4 Pageruyung       6.56    3.94         7.8     20
##  5 Patean          12.5     7.04        12.7     24
##  6 Singorojo 01    12.4     8.08        12.8     22
##  7 Singorojo 02     7.34    7.98         9.6     17
##  8 Limbangan       13.2     9.37        10.9     24
##  9 Boja 01          4.69    6.01         5.3     29
## 10 Boja 02         12.4     9.03        11.6     20
## # ℹ 20 more rows

Cek Statistik Deskriptif

summary(data) 
##   Puskesmas            Stunting         Wasting        Underweight   
##  Length:30          Min.   : 4.690   Min.   : 3.320   Min.   : 3.40  
##  Class :character   1st Qu.: 8.283   1st Qu.: 7.275   1st Qu.:10.93  
##  Mode  :character   Median :11.215   Median :10.395   Median :11.85  
##                     Mean   :11.546   Mean   : 9.086   Mean   :11.44  
##                     3rd Qu.:13.540   3rd Qu.:11.068   3rd Qu.:13.40  
##                     Max.   :18.810   Max.   :13.050   Max.   :15.30  
##      Tenaga     
##  Min.   :10.00  
##  1st Qu.:17.00  
##  Median :19.50  
##  Mean   :20.27  
##  3rd Qu.:23.75  
##  Max.   :34.00

Berdasarkan statistik deskriptif, rata-rata persentase stunting sebesar 11,55%, wasting 9,08%, dan underweight 11,44% dengan variasi yang berbeda antar puskesmas. Nilai minimum dan maksimum masing-masing variabel menunjukkan adanya perbedaan kondisi gizi balita di setiap wilayah. Sementara itu, jumlah tenaga kebidanan memiliki rata-rata 20,27 orang dengan rentang 10–34 orang, yang menunjukkan adanya perbedaan ketersediaan tenaga kebidanan antar puskesmas.

Pengecekan Outlier

# Membuat Boxplot untuk variabel numerik (kolom 2 sampai 5)
boxplot(data[, 2:5], 
        main = "Deteksi Outlier Menggunakan Boxplot",
        col = "orange",
        border = "brown")

Berdasarkan boxplot, variabel stunting, wasting, dan tenaga kebidanan tidak menunjukkan pencilan yang signifikan. Namun, pada variabel underweight terdapat beberapa data di bawah lower whisker yang menunjukkan adanya puskesmas dengan persentase underweight jauh lebih rendah dibandingkan wilayah lainnya di Kabupaten Kendal.

# Pilih hanya kolom numerik (Stunting s/d Tenaga)
kolom_numerik <- data[, 2:5]

# Loop untuk mengecek setiap variabel satu per satu
for (col in names(kolom_numerik)) {
  
  # Hitung batas outlier
  nilai <- data[[col]]
  outlier_values <- boxplot.stats(nilai)$out
  
  # Jika ditemukan outlier, tampilkan datanya
  if (length(outlier_values) > 0) {
    cat("\n--------------------------------------\n")
    cat("Outlier ditemukan pada variabel:", col, "\n")
    cat("Nilai Outlier:", paste(outlier_values, collapse = ", "), "\n")
    
    # Menampilkan baris data yang mengandung outlier tersebut
    print(data[data[[col]] %in% outlier_values, c("Puskesmas", col)])
  }
}
## 
## --------------------------------------
## Outlier ditemukan pada variabel: Underweight 
## Nilai Outlier: 6.6, 5.3, 3.4 
## # A tibble: 3 × 2
##   Puskesmas   Underweight
##   <chr>             <dbl>
## 1 Sukorejo 02         6.6
## 2 Boja 01             5.3
## 3 Kaliwungu           3.4

Meskipun secara statistik tergolong pencilan, data tersebut tetap dipertahankan karena merupakan data riil dan bukan kesalahan pencatatan. Nilai underweight yang rendah mencerminkan keberhasilan penanganan gizi di wilayah tersebut, sehingga tetap digunakan agar hasil K-Means clustering dapat menggambarkan variasi kondisi kesehatan secara lebih akurat.

Asumsi Analisis Cluster

Asumsi Sampel yang Mewakili Populasi

Uji Kaiser–Meyer–Olkin (KMO) digunakan untuk menilai apakah sampel yang digunakan sudah mewakili populasi. Namun, apabila data yang dianalisis mencakup seluruh populasi, maka pengujian ini tidak diperlukan karena tidak ada proses generalisasi dari sampel ke populasi.

\[ KMO = \frac{\sum_{i=1}^{p} \sum_{j=1}^{p} r_{ij}^{2}} {\sum_{i=1}^{p} \sum_{j=1}^{p} r_{ij}^{2} + \sum_{i=1}^{p} \sum_{j=1}^{p} a_{ij}^{2}} \]

Dengan:

\(p\) : banyaknya variabel

\(r_{ij}\) : koefisien korelasi terobservasi antara variabel ke-\(i\) dan ke-\(j\)

\(a_{ij}\) : koefisien korelasi parsial antara variabel ke-\(i\) dan ke-\(j\)

Dikarenakan data yang digunakan adalah data seluruh puskesmas di Kabupaten Kendal, maka data tersebut berupa populasi sehingga tidak perlu diuji KMO.

Uji Multikolinearitas

Menurut Gujarati (1978), multikolinearitas merupakan kondisi adanya hubungan linear yang kuat atau sempurna di antara dua atau lebih variabel independen. Kondisi ini dapat dideteksi menggunakan nilai Variance Inflation Factor (VIF), di mana multikolinearitas dianggap terjadi apabila nilai VIF lebih dari 10.

\[ VIF_j = \frac{1}{1 - R_j^2} \]

Keterangan:

\(VIF_j\) : nilai Variance Inflation Factor pada variabel ke-\(j\)

\(R_j^2\) : koefisien determinasi dari regresi variabel ke-\(j\) terhadap variabel bebas lainnya

Puskesmas <- data$Puskesmas
X1 <- data$Stunting
X2 <- data$Wasting
X3 <- data$Underweight
X4 <- data$Tenaga

predictors <- c("X1", "X2", "X3", "X4")
df_data <- data.frame(X1, X2, X3, X4)
vif_results <- data.frame(
  Variable = character(),
  R_Squared = numeric(),
  VIF_Value = numeric(),
  stringsAsFactors = FALSE
)

for (i in seq_along(predictors)) {
  y_var <- predictors[i]
  x_vars <- predictors[-i]
  formula_reg <- as.formula(paste(y_var, "~", paste(x_vars, collapse = " + ")))
  model <- lm(formula_reg, data = df_data)
  r_sq <- summary(model)$r.squared
  vif_val <- 1 / (1 - r_sq)
  vif_results[i, ] <- c(y_var, r_sq, vif_val)
}
vif_results$R_Squared <- as.numeric(vif_results$R_Squared)
vif_results$VIF_Value <- as.numeric(vif_results$VIF_Value)
print(vif_results)
##   Variable R_Squared VIF_Value
## 1       X1 0.4161803  1.712858
## 2       X2 0.6570037  2.915483
## 3       X3 0.7508973  4.014408
## 4       X4 0.1129287  1.127305

Berdasarkan hasil perhitungan VIF, seluruh variabel memiliki nilai kurang dari 10 sehingga tidak terdeteksi multikolinearitas. Dengan demikian, semua variabel dinyatakan valid dan dapat digunakan dalam analisis selanjutnya.

Standardisasi Data (Scaling)

Data yang digunakan dalam penelitian ini memiliki satuan yang berbeda setiap variabelnya. Sehingga, perlu dilakukan standarisasi agar skala variabel sama, menambah akurasi dalam perhitungan jarak, serta mencegah klasterisasi yang tidak akurat

Standardisasi Data (Z-Score)

Standarisasi data dengan metode Z-score dilakukan untuk mengubah data agar memiliki rata-rata 0 dan standar deviasi 1. Proses ini bertujuan menyamakan skala antar variabel sehingga perbedaan satuan tidak memengaruhi hasil analisis.

\[ Z_{ij} = \frac{X_{ij} - \bar{X}_j}{s_j} \]

Keterangan:

\(Z_{ij}\) : nilai hasil standardisasi pada observasi ke-\(i\) dan variabel ke-\(j\)

\(X_{ij}\) : nilai asli data pada observasi ke-\(i\) dan variabel ke-\(j\)

\(\bar{X}_j\) : nilai rata-rata dari variabel ke-\(j\)

\(s_j\) : simpangan baku dari variabel ke-\(j\)

data_select <- data[, 2:5]
data_scaled <- scale(data_select)
row.names(data_scaled) <- data$Puskesmas
print(data_scaled)
##                       Stunting     Wasting Underweight      Tenaga
## Plantungan        -0.765294692 -1.75720572 -1.28113622 -0.20972291
## Sukorejo 01        1.729852916 -1.22746593  0.05509003  0.28698924
## Sukorejo 02       -0.536427713 -1.78899010 -1.70310240 -0.54086435
## Pageruyung        -1.240442442 -1.81724289 -1.28113622 -0.04415219
## Patean             0.247192922 -0.72244734  0.44189236  0.61813068
## Singorojo 01       0.224803761 -0.35516109  0.47705621  0.28698924
## Singorojo 02      -1.046403046 -0.39047708 -0.64818694 -0.54086435
## Limbangan          0.406404733  0.10041512 -0.19105691  0.61813068
## Boja 01           -1.705639453 -1.08620199 -2.16023244  1.44598427
## Boja 02            0.212365338 -0.01965923  0.05509003 -0.04415219
## Kaliwungu         -1.364826669 -2.03620200 -2.82834556  1.77712571
## Kaliwungu Selatan -0.068743017  0.68666048 -0.36687615 -0.04415219
## Brangsong 01       1.020862818  0.85264561  0.33640082 -1.36871794
## Brangsong 02      -0.969284825  1.07866792  0.30123697 -0.37529363
## Pegandon           0.199926915  0.54892813  0.75836700  2.27383786
## Ngampel           -0.969284825  0.70078687  0.23090927  1.11484284
## Gemuh 01          -0.242880935  0.45710657  0.44189236 -0.37529363
## Gemuh 02           1.070616509  0.51714375  0.82869470 -0.54086435
## Ringinarum        -0.096107547  1.40004338  1.35615243  0.45255996
## Weleri 01         -0.404580431  0.78907683 -0.05040152 -1.03757650
## Weleri 02         -0.827486806 -0.18917596 -0.15589306 -0.54086435
## Rowosari 01       -0.553841505  1.10338911  1.14516934 -0.37529363
## Rowosari 02        1.806971137 -0.92728006 -0.05040152 -0.70643506
## Kangkung 01        1.782094292 -0.14679678  1.00451394 -0.70643506
## Kangkung 02        1.744779024  0.79614003  1.07484164 -1.69985937
## Cepiring          -0.332437579  1.24818465  0.30123697  1.94269643
## Patebon 01         0.008375205  0.69725527  0.05509003 -1.36871794
## Patebon 02         1.117882516  0.46770137  0.89902240  0.12141853
## Kendal 01          0.525813592  0.52420694 -0.12072921  0.78370140
## Kendal 02         -0.974260194  0.49595416  1.07484164 -1.20314722
## attr(,"scaled:center")
##    Stunting     Wasting Underweight      Tenaga 
##   11.546333    9.085667   11.443333   20.266667 
## attr(,"scaled:scale")
##    Stunting     Wasting Underweight      Tenaga 
##    4.019802    2.831579    2.843830    6.039715

Menentukan Jumlah Cluster Optimal

Metode Davies-Bouldin Index

Davies–Bouldin Index (DBI) merupakan metode evaluasi internal pada analisis cluster yang digunakan untuk menilai kualitas hasil pengelompokan berdasarkan kedekatan data dalam cluster dan pemisahan antar cluster.

Langkah-langkah Davies-Bouldin Index (DBI)

  1. Menghitung jarak Rata-rata dalam cluster

    \[ S_k = \frac{1}{n_k}\sum_{i=1}^{n_k} d(x_i,\mu_k) \]

    Keterangan:

    \(S_k\) : jarak rata-rata dalam cluster ke-\(k\)

    \(n_k\) : jumlah data dalam cluster ke-\(k\)

    \(x_i\) : data ke-\(i\) dalam cluster ke-\(k\)

    \(\mu_k\) : pusat centroid cluster ke-\(k\)

    \(d(x_i,\mu_k)\) : jarak euclidean antara data ke-\(i\) dan centroid

  2. Jarak antar centroid cluster

    \[ M_{kj} = d(\mu_k,\mu_j) \]

    Keterangan:

    \(M_{kj}\) : jarak antar centroid cluster ke-\(k\) dan ke-\(j\)

    \(\mu_k\) : vektor pusat (centroid) cluster ke-\(k\)

    \(\mu_j\) : vektor pusat (centroid) cluster ke-\(j\)

  3. Rasio antar cluster

    \[ R_{kj} = \frac{S_k + S_j}{M_{kj}} \]

    Keterangan:

    \(R_{kj}\) : rasio cluster ke-\(k\) dan cluster ke-\(j\)

    \(S_k\) : rata-rata jarak di dalam cluster ke-\(k\)

    \(S_j\) : rata-rata jarak di dalam cluster ke-\(j\)

    \(M_{kj}\) : jarak antara centroid cluster ke-\(k\) (\(\mu_k\)) dan centroid cluster ke-\(j\) (\(\mu_j\))

  4. Nilai maksimum rasio tiap cluster\[ D_k = \max_{j \ne k} (R_{kj}) \]

    Keterangan:

    \(D_k\) : nilai rasio maksimal dari cluster ke-\(k\) dengan cluster lain (\(j\))

    \(R_{kj}\) : rasio cluster ke-\(k\) dan cluster ke-\(j\)

  5. Nilai Davies-Bouldin Index

    \[ DBI = \frac{1}{K} \sum_{k=1}^{K} D_k \]

    Keterangan:

    \(D_k\) : nilai rasio maksimal dari cluster ke-\(k\) dengan cluster lain (\(j\))

    \(K\) : jumlah cluster yang terbentuk

# Fungsi untuk menghitung Davies-Bouldin Index sesuai langkah di gambar
hitung_DBI_manual <- function(data, hasil_kmeans) {
  
  # Persiapan Data
  k <- nrow(hasil_kmeans$centers)
  centroids <- hasil_kmeans$centers
  cluster_labels <- hasil_kmeans$cluster
  
  # --- LANGKAH 1: Hitung Intra-Cluster Distance (Si) ---
  # Mengukur kepadatan dalam satu klaster (Average distance to centroid)
  #
  S <- numeric(k)
  for (i in 1:k) {
    # Ambil data milik klaster i
    data_i <- data[cluster_labels == i, , drop = FALSE]
    if(nrow(data_i) > 0) {
      # Hitung jarak setiap titik ke centroid-nya
      distances <- sqrt(rowSums((t(t(data_i) - centroids[i, ]))^2))
      # Hitung rata-ratanya (1/ni * Sigma)
      S[i] <- mean(distances)
    } else {
      S[i] <- 0
    }
  }
  
  # --- LANGKAH 2: Hitung Inter-Cluster Distance (Mij) ---
  # Mengukur jarak antar pusat klaster (Centroid Distance)
  #
  M <- as.matrix(dist(centroids))
  
  # --- LANGKAH 3: Hitung Rasio Kemiripan (Rij) ---
  # Rumus: (Si + Sj) / Mij
  #
  R <- matrix(0, nrow = k, ncol = k)
  for (i in 1:k) {
    for (j in 1:k) {
      if (i != j) {
        R[i, j] <- (S[i] + S[j]) / M[i, j]
      }
    }
  }
  
  # --- LANGKAH 4: Ambil Nilai Maksimum Rasio Tiap Klaster (Ri) ---
  # Cari "musuh" terdekat atau rasio terburuk untuk setiap klaster
  #
  R_max <- apply(R, 1, max)
  
  # --- LANGKAH 5: Hitung Rata-Rata Keseluruhan (DBI) ---
  # Rumus: 1/k * Sigma(Ri)
  #
  DBI <- mean(R_max)
  
  return(DBI)
}
# Kita akan coba uji dari 2 klaster sampai 5 klaster
k_range <- 2:5
nilai_dbi <- c()

# Looping pengujian
for (k in k_range) {
  set.seed(123) # Kunci agar hasil konsisten
  
  # 1. Lakukan K-Means
  km_model <- kmeans(data_scaled, centers = k, nstart = 25)
  
  # 2. Hitung DBI pakai rumus manual tadi
  dbi_score <- hitung_DBI_manual(data_scaled, km_model)
  
  # 3. Simpan hasil
  nilai_dbi <- c(nilai_dbi, dbi_score)
}

# Gabungkan hasil dalam tabel
hasil_dbi <- data.frame(Jumlah_Klaster = k_range, Nilai_DBI = nilai_dbi)

print("=== HASIL AKHIR DAVIES-BOULDIN INDEX ===")
## [1] "=== HASIL AKHIR DAVIES-BOULDIN INDEX ==="
print(hasil_dbi)
##   Jumlah_Klaster Nilai_DBI
## 1              2 0.8736294
## 2              3 1.0693266
## 3              4 1.0308101
## 4              5 0.9293725

Berdasarkan hasil perhitungan DBI, nilai terkecil diperoleh pada k = 2. Karena nilai DBI yang lebih kecil menunjukkan kualitas pengelompokan yang lebih baik, maka jumlah cluster optimal adalah 2.

Visualisasi Kmeans Clustering

library(factoextra)
## Warning: package 'factoextra' was built under R version 4.3.3
## Loading required package: ggplot2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
kmeans_data = kmeans(data_scaled, centers = 2) 
fviz_cluster(kmeans_data, data = data_scaled)

Penetapan Profil (Profiling)

Adapun kriteria yang digunakan dalam menginterpretasikan profil Cluster adalah sebagai berikut:

  • Cluster dengan rata-rata variabel rendah maka dikategorikan sebagai kelompok puskesmas dengan status gizi balita dan ketersediaan layanan kebidanan yang sedikit.

  • Cluster dengan rata-rata variabel tinggi maka dikategorikan sebagai kelompok puskesmas dengan status gizi balita dan ketersediaan layanan kebidanan yang banyak.

Cek Hasil Clustering

# Menggabungkan hasil cluster
hasil_kmeans = data.frame(data$Puskesmas, data_scaled, kmeans_data$cluster) 
hasil_kmeans[order(hasil_kmeans$kmeans_data.cluster),] 
##                      data.Puskesmas     Stunting     Wasting Underweight
## Plantungan               Plantungan -0.765294692 -1.75720572 -1.28113622
## Sukorejo 02             Sukorejo 02 -0.536427713 -1.78899010 -1.70310240
## Pageruyung               Pageruyung -1.240442442 -1.81724289 -1.28113622
## Singorojo 02           Singorojo 02 -1.046403046 -0.39047708 -0.64818694
## Boja 01                     Boja 01 -1.705639453 -1.08620199 -2.16023244
## Kaliwungu                 Kaliwungu -1.364826669 -2.03620200 -2.82834556
## Sukorejo 01             Sukorejo 01  1.729852916 -1.22746593  0.05509003
## Patean                       Patean  0.247192922 -0.72244734  0.44189236
## Singorojo 01           Singorojo 01  0.224803761 -0.35516109  0.47705621
## Limbangan                 Limbangan  0.406404733  0.10041512 -0.19105691
## Boja 02                     Boja 02  0.212365338 -0.01965923  0.05509003
## Kaliwungu Selatan Kaliwungu Selatan -0.068743017  0.68666048 -0.36687615
## Brangsong 01           Brangsong 01  1.020862818  0.85264561  0.33640082
## Brangsong 02           Brangsong 02 -0.969284825  1.07866792  0.30123697
## Pegandon                   Pegandon  0.199926915  0.54892813  0.75836700
## Ngampel                     Ngampel -0.969284825  0.70078687  0.23090927
## Gemuh 01                   Gemuh 01 -0.242880935  0.45710657  0.44189236
## Gemuh 02                   Gemuh 02  1.070616509  0.51714375  0.82869470
## Ringinarum               Ringinarum -0.096107547  1.40004338  1.35615243
## Weleri 01                 Weleri 01 -0.404580431  0.78907683 -0.05040152
## Weleri 02                 Weleri 02 -0.827486806 -0.18917596 -0.15589306
## Rowosari 01             Rowosari 01 -0.553841505  1.10338911  1.14516934
## Rowosari 02             Rowosari 02  1.806971137 -0.92728006 -0.05040152
## Kangkung 01             Kangkung 01  1.782094292 -0.14679678  1.00451394
## Kangkung 02             Kangkung 02  1.744779024  0.79614003  1.07484164
## Cepiring                   Cepiring -0.332437579  1.24818465  0.30123697
## Patebon 01               Patebon 01  0.008375205  0.69725527  0.05509003
## Patebon 02               Patebon 02  1.117882516  0.46770137  0.89902240
## Kendal 01                 Kendal 01  0.525813592  0.52420694 -0.12072921
## Kendal 02                 Kendal 02 -0.974260194  0.49595416  1.07484164
##                        Tenaga kmeans_data.cluster
## Plantungan        -0.20972291                   1
## Sukorejo 02       -0.54086435                   1
## Pageruyung        -0.04415219                   1
## Singorojo 02      -0.54086435                   1
## Boja 01            1.44598427                   1
## Kaliwungu          1.77712571                   1
## Sukorejo 01        0.28698924                   2
## Patean             0.61813068                   2
## Singorojo 01       0.28698924                   2
## Limbangan          0.61813068                   2
## Boja 02           -0.04415219                   2
## Kaliwungu Selatan -0.04415219                   2
## Brangsong 01      -1.36871794                   2
## Brangsong 02      -0.37529363                   2
## Pegandon           2.27383786                   2
## Ngampel            1.11484284                   2
## Gemuh 01          -0.37529363                   2
## Gemuh 02          -0.54086435                   2
## Ringinarum         0.45255996                   2
## Weleri 01         -1.03757650                   2
## Weleri 02         -0.54086435                   2
## Rowosari 01       -0.37529363                   2
## Rowosari 02       -0.70643506                   2
## Kangkung 01       -0.70643506                   2
## Kangkung 02       -1.69985937                   2
## Cepiring           1.94269643                   2
## Patebon 01        -1.36871794                   2
## Patebon 02         0.12141853                   2
## Kendal 01          0.78370140                   2
## Kendal 02         -1.20314722                   2

Hitung Jarak Setiap Data Terhadap Centroid

\[ d(x_i,\mu_k) = \sqrt{\sum_{j=1}^{p} (x_{ij} - \mu_{k(j)})^2} \]

dimana:

\(d(x_i,\mu_k)\) : jarak antara \(x_i\) dan \(\mu_k\)

\(x_{ij}\) : data pada objek ke-\(i\) pada variabel ke-\(j\)

\(\mu_{k(j)}\) : pusat cluster ke-\(k\) pada variabel ke-\(j\)

\(p\) : banyaknya variabel yang diukur

data_final <- data_scaled

cluster_assignments <- kmeans_data$cluster 

centroids <- kmeans_data$centers

# Rumus hitung jarak per baris (Sesuai syntax Anda)
jarak_ke_centroid <- sapply(1:nrow(data_final), function(i) { 
  sqrt(sum((data_final[i, ] - centroids[cluster_assignments[i], ])^2)) 
}) 

# Masukkan ke tabel hasil
hasil_kmeans$Jarak_Centroid <- jarak_ke_centroid 
hasil_kmeans[order(hasil_kmeans$kmeans_data.cluster),]
##                      data.Puskesmas     Stunting     Wasting Underweight
## Plantungan               Plantungan -0.765294692 -1.75720572 -1.28113622
## Sukorejo 02             Sukorejo 02 -0.536427713 -1.78899010 -1.70310240
## Pageruyung               Pageruyung -1.240442442 -1.81724289 -1.28113622
## Singorojo 02           Singorojo 02 -1.046403046 -0.39047708 -0.64818694
## Boja 01                     Boja 01 -1.705639453 -1.08620199 -2.16023244
## Kaliwungu                 Kaliwungu -1.364826669 -2.03620200 -2.82834556
## Sukorejo 01             Sukorejo 01  1.729852916 -1.22746593  0.05509003
## Patean                       Patean  0.247192922 -0.72244734  0.44189236
## Singorojo 01           Singorojo 01  0.224803761 -0.35516109  0.47705621
## Limbangan                 Limbangan  0.406404733  0.10041512 -0.19105691
## Boja 02                     Boja 02  0.212365338 -0.01965923  0.05509003
## Kaliwungu Selatan Kaliwungu Selatan -0.068743017  0.68666048 -0.36687615
## Brangsong 01           Brangsong 01  1.020862818  0.85264561  0.33640082
## Brangsong 02           Brangsong 02 -0.969284825  1.07866792  0.30123697
## Pegandon                   Pegandon  0.199926915  0.54892813  0.75836700
## Ngampel                     Ngampel -0.969284825  0.70078687  0.23090927
## Gemuh 01                   Gemuh 01 -0.242880935  0.45710657  0.44189236
## Gemuh 02                   Gemuh 02  1.070616509  0.51714375  0.82869470
## Ringinarum               Ringinarum -0.096107547  1.40004338  1.35615243
## Weleri 01                 Weleri 01 -0.404580431  0.78907683 -0.05040152
## Weleri 02                 Weleri 02 -0.827486806 -0.18917596 -0.15589306
## Rowosari 01             Rowosari 01 -0.553841505  1.10338911  1.14516934
## Rowosari 02             Rowosari 02  1.806971137 -0.92728006 -0.05040152
## Kangkung 01             Kangkung 01  1.782094292 -0.14679678  1.00451394
## Kangkung 02             Kangkung 02  1.744779024  0.79614003  1.07484164
## Cepiring                   Cepiring -0.332437579  1.24818465  0.30123697
## Patebon 01               Patebon 01  0.008375205  0.69725527  0.05509003
## Patebon 02               Patebon 02  1.117882516  0.46770137  0.89902240
## Kendal 01                 Kendal 01  0.525813592  0.52420694 -0.12072921
## Kendal 02                 Kendal 02 -0.974260194  0.49595416  1.07484164
##                        Tenaga kmeans_data.cluster Jarak_Centroid
## Plantungan        -0.20972291                   1      0.7791765
## Sukorejo 02       -0.54086435                   1      1.0766752
## Pageruyung        -0.04415219                   1      0.6294599
## Singorojo 02      -0.54086435                   1      1.7105218
## Boja 01            1.44598427                   1      1.4316464
## Kaliwungu          1.77712571                   1      1.9752841
## Sukorejo 01        0.28698924                   2      2.2186366
## Patean             0.61813068                   2      1.2962943
## Singorojo 01       0.28698924                   2      0.8162439
## Limbangan          0.61813068                   2      0.9690751
## Boja 02           -0.04415219                   2      0.5338048
## Kaliwungu Selatan -0.04415219                   2      0.9104852
## Brangsong 01      -1.36871794                   2      1.5671098
## Brangsong 02      -0.37529363                   2      1.4687405
## Pegandon           2.27383786                   2      2.3857545
## Ngampel            1.11484284                   2      1.7667249
## Gemuh 01          -0.37529363                   2      0.6059927
## Gemuh 02          -0.54086435                   2      1.0186185
## Ringinarum         0.45255996                   2      1.5405679
## Weleri 01         -1.03757650                   2      1.3322315
## Weleri 02         -0.54086435                   2      1.4388297
## Rowosari 01       -0.37529363                   2      1.3615505
## Rowosari 02       -0.70643506                   2      2.1518416
## Kangkung 01       -0.70643506                   2      1.8097899
## Kangkung 02       -1.69985937                   2      2.3241477
## Cepiring           1.94269643                   2      2.2894710
## Patebon 01        -1.36871794                   2      1.4041702
## Patebon 02         0.12141853                   2      0.9962576
## Kendal 01          0.78370140                   2      1.0552622
## Kendal 02         -1.20314722                   2      1.8126740

Jarak Antar Centroid Cluster

\[ \mu_{k(j)} = \frac{1}{N_k}\sum_{i=1}^{N_k} x_{ij}, \quad j = 1,2,\ldots,p \]

Keterangan:

\(\mu_{k(j)}\) : pusat cluster ke-\(k\) pada variabel ke-\(j\)

\(N_k\) : jumlah data dalam cluster ke-\(k\)

\(x_{ij}\) : nilai data pada objek ke-\(i\) pada variabel ke-\(j\)

# Mengambil centroid hasil K-Means
centroids <- kmeans_data$centers

# Menghitung jarak antar centroid
jarak_centroid <- dist(centroids)

# Menampilkan hasil
jarak_centroid
##          1
## 2 3.123241

Berdasarkan hasil perhitungan, jarak centroid antara Cluster 1 dan Cluster 2 sebesar 3,123241. Nilai ini menunjukkan adanya perbedaan karakteristik yang cukup jelas antar cluster, sehingga hasil pengelompokan K-Means mampu memisahkan data dengan baik.

Profiling Hasil Cluster

Profiling cluster merupakan tahap untuk menggambarkan karakteristik dari setiap cluster yang terbentuk. Proses ini dilakukan dengan menganalisis statistik deskriptif pada masing-masing variabel dalam setiap cluster, seperti nilai rata-rata. Hasil perbandingan antar cluster digunakan untuk mengidentifikasi variabel yang paling membedakan karakteristik setiap cluster sehingga memudahkan interpretasi terhadap pola yang terbentuk.

\[ \bar{x}_{kj} = \frac{1}{n_k}\sum_{i=1}^{n_k} x_{ij} \]

dimana:

\(\bar{x}_{kj}\) : nilai rata-rata variabel ke-\(j\) pada cluster ke-\(k\)

\(n_k\) : jumlah objek atau anggota pada cluster ke-\(k\)

\(x_{ij}\) : nilai variabel ke-\(j\) pada objek ke-\(i\) dalam cluster ke-\(k\)

data <- data[complete.cases(data), ]
k2 <- kmeans(data_scaled, centers = 2, nstart = 25)

library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.3
## 
## 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
# Menghitung rata-rata karakteristik tiap klaster
mean.klaster <- data %>%
  mutate(Klaster = k2$cluster) %>%
  group_by(Klaster) %>%
  summarise(
    Mean_Stunting    = mean(Stunting),
    Mean_Wasting     = mean(Wasting),
    Mean_Underweight = mean(Underweight),
    Mean_Tenaga      = mean(Tenaga)
  ) %>%
  mutate(
    Total_Mean = Mean_Stunting + Mean_Wasting + Mean_Underweight + Mean_Tenaga
  ) %>%
  arrange(Klaster)

# Tampilkan hasil
mean.klaster
## # A tibble: 2 × 6
##   Klaster Mean_Stunting Mean_Wasting Mean_Underweight Mean_Tenaga Total_Mean
##     <int>         <dbl>        <dbl>            <dbl>       <dbl>      <dbl>
## 1       1          7.08         4.90             6.75        22.2       40.9
## 2       2         12.7         10.1             12.6         19.8       55.2

Profiling Cluster

  • Cluster 1 terdiri dari 6 puskesmas, yaitu Plantungan, Sukorejo 02, Pageruyung, Singorojo 02, Boja 01, dan Kaliwungu. Cluster ini memiliki prevalensi masalah gizi yang relatif rendah dengan rata-rata stunting 7,085%, wasting 4,897%, dan underweight 6,750%. Selain itu, cluster ini didukung oleh ketersediaan tenaga kebidanan yang cukup tinggi dengan rata-rata 22 orang per puskesmas, sehingga mencerminkan wilayah dengan kondisi kesehatan masyarakat yang baik.
  • Cluster 2 terdiri dari 24 puskesmas atau sekitar 80% dari total observasi di Kabupaten Kendal. Cluster ini memiliki prevalensi masalah gizi yang lebih tinggi dengan rata-rata stunting 12,66%, wasting 10,13%, dan underweight 12,61%. Jumlah tenaga kebidanan rata-rata sekitar 20 orang per puskesmas lebih sedikit daripada cluster 1, sehingga cluster ini dapat dikategorikan sebagai wilayah prioritas intervensi dalam penanganan masalah gizi.