11/3/2024
Analisis klaster adalah teknik statistik yang berguna untuk mengelompokkan objek ke dalam beberapa kelompok tertentu dimana setiap objek yang terbentuk memiliki sifat dan karakteristik yang berdekatan.
Tujuan dari analisis klaster adalah mengelompokkan objek berdasarkan kesamaan karakteristik di antara objek-objek tersebut. Dengan demikian, ciri-ciri suatu klaster yang baik yaitu memiliki:
Homogenitas internal (within cluster) yaitu kesamaan antar anggota dalam satu klaster
Heterogenitas eksternal (between cluster) yaitu perbedaan antara klaster yang satu dengan klaster yang lain
Pada analisis klaster, data mentah diubah ke dalam matriks similarity, selanjutnya dirumuskan formasi kelompok dengan prinsip variasi dalam kelompok lebih kecil daripada variasi antar kelompok.
Metode Hirarki (Hierarchical Cluster Analysis)
Pengelompokan dimulai dengan dua atau lebih obyek yang mempunyai kesamaan paling dekat. Metode hirarki ini terdiri dari dua cara, yaitu:
Penggabungan (Agglomerative)
Cara ini digunakan jika masing-masing objek dianggap satu kelompok kemudian antar objek yang jaraknya berdekatan bergabung menjadi satu kelompok. Pada metode ini, dapat digunakan tiga pendekatan yaitu single linkage, average linkage, dan complete linkage.
Pemecahan (Divisive)
Cara ini digunakan jika pada awalnya semua objek berada dalam satu kelompok. Setelah itu, objek dengan sifat paling beda dipisahkan dan membentuk satu kelompok yang lain. Proses tersebut berlanjut sampai semua objek tersebut masing masing membentuk satu kelompok. Metode ini juga disebut sebagai metode splinter average distance karena pemisahan tersebut didasarkan pada rata-rata jarak dengan kelompok lain dan dengan kelompok sendiri.
Metode Non-Hirarki (K-Means Clustering)
Metode Non-Hirarki dilakukan dengan pendekatan K-Means. K-means cluster sangat efektif dan efisien jika digunakan untuk mengelompokkan objek yang berjumlah besar. Metode ini didasarkan optimasi kriteria formal dan telah didefinisikan dengan jumlah obyek yang besar. Pada metode K-Means sudah diasumsikan terlebih dahulu jumlah kelompok yang akan terbentuk. Penentuan kelompok pada metode ini tidak final, jika tidak tepat (tingkat errornya tinggi) maka hasil pengelompokkan dapat diubah dengan memindahkan objek ke klaster lainnya. Adapun tahapan dalam metode K-Means sebagai berikut:
Tentukan kelompok awal berdasarkan perkiraan (hiportesis)
Membuat tabel karakteristik setiap kelompok, berdasarkan rata-rata setiap variabel pada setiap kelompok
Hitung jarak antara invididu dengan kelompok dimana invidu tersebut berada,
Hitung kesalahan pengelompokkan
Menguji penurunan nilai kesalahan dengan adanya pemindahan invidu ke kelompok lain.
Contoh kasus:
Provinsi Jawa Barat yang merupakan provinsi dengan jumlah penduduk
terbesar di Indonesia. Setiap daerah memiliki kewajiban untuk
menyediakan pelayanan pendidikan dan kesehatan. Pembangunan bidang
kesehatan dan pendidikan bertujuan agar semua lapisan masyarakat dapat
meperoleh pelayanan kesehatan dan pendidikan secara mudah dan merata.
Selain fasilitas kesehatan skala kecamatan dan kota/kabupaten,
diperlukan juga pengembangan sarana dan prasarana maupun program di
sektor kesehatan dan pendidikan yang melayani beberapa kota/kabupaten.
Oleh karena itu, Pemprov Jawa Barat ingin merancang kebijakan terkait
pelayanan kesehatan dan pendidikan. Untuk efektivitas dan efisiensi
kebijakan tersebut tidak dimungkinkan membuat kebijakan khusus untuk
setiap kota/kabupaten sehingga perlu adanya pengelompokkan
kota/kabupaten menjadi 5 kelompok berdasarkan
karakteristik yang dimilikinya menggunakan data yang tertera pada data
di bawah ini.
Data ini juga dapat diunduh pada link ini: Data
Berikut adalah tabel data sarana kesehatan dan pendidikan di kota/kabupaten Jawa Barat (Sumber: Provinsi Jawa Barat dalam Angka, 2021)
data <- read.csv("data02.csv")
head(data)
## KabKota JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## 1 Bogor 639 1788 348 25 101 4804 153
## 2 Sukabumi 311 1205 147 7 58 3451 54
## 3 Cianjur 268 1254 164 3 45 2896 6
## 4 Bandung 302 1431 130 7 62 4198 131
## 5 Garut 339 1583 159 6 65 3963 96
## 6 Tasikmalaya 240 1090 116 1 40 2278 29
Masalah yang akan diteliti adalah sebegai berikut:
Berapa klaster yang terbentuk?
Bagaimana karakteristik setiap klaster berdasarkan variabel penentunya?
Bagaimana interpretasi pembentukan klaster tersebut dalam konteks perencanaan wilayah dan kota?
Sebelum melakukan analisis klaster, ada beberapa step yang harus dilakukan (hal ini biasanya berlaku di banyak jenis analisis), yaitu missing value imputation dan scaling.
Missing Value Imputation
Penting juga untuk menangani nilai yang hilang/null/inf dalam kumpulan data Anda sebelumnya. Ada banyak cara untuk menangani nilai-nilai tersebut, salah satunya adalah dengan menghapusnya atau mengimputasinya dengan mean, median, modus, atau menggunakan beberapa teknik regresi tingkat lanjut. R memiliki banyak paket dan fungsi untuk menangani imputasi nilai yang hilang seperti impute(), Amelia, Mice, Hmisc, dll. Dalam kasus praktikum ini tidak terdapat missing value.
# check missing values in data
missing_values <- colSums(is.na(data))
# menampilkan missing values
print("Missing values:")
## [1] "Missing values:"
print(missing_values)
## KabKota JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas
## 0 0 0 0 0 0
## JmlPosyandu JmlKlinik
## 0 0
Tidak ada missing values.
Scaling
Sama seperti praktikum sebelumnya, scaling melalui `scale()` dilakukan untuk menyamakan range pada setiap kolom. Hal ini karena nilai fitur dari setiap pengamatan direpresentasikan sebagai koordinat dalam ruang n-dimensi (n adalah jumlah fitur) dan kemudian jarak antara koordinat ini dihitung. Jika koordinat ini tidak dinormalisasi, maka hal ini dapat menyebabkan hasil yang salah.
# semua data adalah numerical kecuali nama kab/kota
# simpan kolom kab/kota
kabKota <- data$KabKota
# hapus kabkota
num_data <- data[, -1]
# melakukan scaling
scaled_data <- as.data.frame(scale(num_data))
# penggabungan dengan kolom kab/kota
normalized_data <- cbind(KabKota=kabKota, scaled_data)
head(normalized_data)
## KabKota JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu
## 1 Bogor 3.4887296 2.2838748 3.5808450 1.1585236 2.97449528 2.4035309
## 2 Sukabumi 0.9942851 1.0493119 0.6734174 -0.4186262 0.91522932 1.2935569
## 3 Cianjur 0.6672695 1.1530744 0.9193193 -0.7691039 0.29266054 0.8382460
## 4 Bandung 0.9258400 1.5278903 0.4275156 -0.4186262 1.10678894 1.9063807
## 5 Garut 1.2072255 1.8497661 0.8469952 -0.5062456 1.25045866 1.7135914
## 6 Tasikmalaya 0.4543291 0.8057874 0.2250082 -0.9443428 0.05321101 0.3312512
## JmlKlinik
## 1 1.4486412
## 2 -0.2125420
## 3 -1.0179641
## 4 1.0794894
## 5 0.4922024
## 6 -0.6320327
Jangan lupa untuk melakukan instalasi dan load library untuk analisis klaster
# install.packages("cluster")
# install.packages("stats")
library(cluster)
library(stats)
Sebelum melakukan analisis klaster (hirarki) berdasarkan jenis-jenisnya, perhitungan distance matrix menjadi hal yang umum untuk dilakukan. Hal ini untuk melihat overview “jarak” antar data secara keseluruhan.
Hasil matriks ini juga yang menjadi dasar melakukan analsis cluster.
Jarak yang digunakan adalah euclidean distance. Ada yang tahu apa itu euclidean distance?
Distance Matrix
# untuk mempermudah interpretasi, kolom kabKota dijadikan index dataframe
new_normalized_data <- normalized_data
rownames(new_normalized_data) <- new_normalized_data[, "KabKota"]
# menghapus kolom kabKota sebelumnya
new_normalized_data <- new_normalized_data[, -which(names(new_normalized_data) == "KabKota")]
dist_mat <- dist(new_normalized_data, method = 'euclidean') # scaled_data digunakan karena matriks ini dihitung hanya untuk kolom numerik (tidak termasuk KabKota)
dist_mat
## Bogor Sukabumi Cianjur Bandung Garut
## Sukabumi 5.1883604
## Cianjur 5.9804105 1.2428246
## Bandung 4.8417519 1.5413575 2.6028982
## Garut 4.4723816 1.2285558 2.1944172 0.8770045
## Tasikmalaya 6.6508244 1.6350491 1.0686680 2.7534541 2.6160490
## Ciamis 7.8742544 2.9144206 2.6049130 3.6860491 3.8450714
## Kuningan 8.2356850 3.2748639 2.8823666 4.1777603 4.2891056
## Cirebon 6.4655520 1.5712265 1.6102891 2.6420212 2.6182829
## Majalengka 8.2106516 3.2055412 2.7574948 4.0775139 4.1964772
## Sumedang 7.8553348 3.0470071 2.8268966 3.6594547 3.9085002
## Indramayu 6.6710163 1.6850179 1.3365366 2.8795362 2.7948141
## Subang 6.9748183 2.2561819 2.1745212 2.9122469 3.0901192
## Purwakarta 8.1917398 3.6466118 3.4481228 4.3121113 4.5598825
## Karawang 6.4585462 3.1501656 3.7644888 2.8241324 3.3784094
## Bekasi 5.7762627 4.7243516 5.3999719 4.3330640 4.7049309
## Bandung Barat 7.3235078 2.4511711 2.2464650 3.1851467 3.3891680
## Pangandaran 9.5730218 4.6614530 4.1171707 5.5136253 5.6675970
## Kota Bogor 8.0390859 3.8685132 3.7617652 4.4914641 4.7624541
## Kota Sukabumi 9.5725620 4.7988629 4.3356767 5.6333160 5.8236835
## Kota Bandung 5.7661506 3.1908127 3.8493595 3.4588212 3.6569982
## Kota Cirebon 9.3586316 4.6915596 4.3218278 5.4986183 5.7029475
## Kota Bekasi 7.1952804 3.8886765 3.7627540 4.8693534 4.8330948
## Kota Depok 7.2094286 3.5231466 3.5986228 4.1050977 4.3366096
## Kota Cimahi 9.6500536 4.9037025 4.4778947 5.6836991 5.9035770
## Kota Tasikmalaya 8.9002577 4.2533659 3.8985496 5.0687391 5.2737383
## Kota Banjar 10.0260130 5.2034816 4.7024093 6.0160357 6.2103887
## Tasikmalaya Ciamis Kuningan Cirebon Majalengka
## Sukabumi
## Cianjur
## Bandung
## Garut
## Tasikmalaya
## Ciamis 1.6632120
## Kuningan 2.0361567 0.6958917
## Cirebon 1.3035350 1.6950518 1.8905142
## Majalengka 1.8370829 0.4861467 0.4969874 1.9696245
## Sumedang 1.8915075 0.7486932 1.3187631 2.0511812 0.9929975
## Indramayu 0.8395222 1.4649031 1.7017712 0.6211703 1.6652772
## Subang 1.3610396 1.0407546 1.6093979 1.3956948 1.4457408
## Purwakarta 2.5453957 1.4891950 1.6130577 2.6647333 1.4932276
## Karawang 3.2873196 2.9758054 3.4300348 2.8570893 3.4103846
## Bekasi 5.2848346 5.3817946 5.7055025 4.9303223 5.7234635
## Bandung Barat 1.4081310 0.9192546 1.4031373 1.5622840 1.1643638
## Pangandaran 3.2193283 1.9055209 1.6378053 3.4321336 1.5186659
## Kota Bogor 3.0288135 2.0576158 2.1625435 2.8829935 2.1316996
## Kota Sukabumi 3.4672395 2.1012088 1.8138336 3.5356914 1.7769246
## Kota Bandung 3.6932195 3.6353686 3.7870377 2.8083647 3.9706136
## Kota Cirebon 3.4630031 2.0272644 1.7028874 3.3661745 1.7868932
## Kota Bekasi 3.6531976 3.5740519 3.3723025 3.1926608 3.5855673
## Kota Depok 3.0186382 2.5275032 2.7297293 2.8367536 2.7024288
## Kota Cimahi 3.5910324 2.1877780 1.9336679 3.6521913 1.8972002
## Kota Tasikmalaya 3.0847582 1.7603877 1.4928766 2.9862906 1.5518208
## Kota Banjar 3.8104556 2.4457159 2.1677909 3.9559420 2.1008364
## Sumedang Indramayu Subang Purwakarta Karawang
## Sukabumi
## Cianjur
## Bandung
## Garut
## Tasikmalaya
## Ciamis
## Kuningan
## Cirebon
## Majalengka
## Sumedang
## Indramayu 1.7911099
## Subang 0.9766328 1.2262644
## Purwakarta 1.3047047 2.4412752 1.6898192
## Karawang 2.7186449 3.0934144 2.2105288 2.9168782
## Bekasi 5.1445367 5.1455330 4.5333427 4.8403523 2.8899686
## Bandung Barat 0.7904309 1.2986353 0.7148718 1.4512676 2.5999337
## Pangandaran 1.9924096 3.1027072 2.7581333 1.8165915 4.4298844
## Kota Bogor 1.7484906 2.7397883 1.9668002 1.0440715 2.6895948
## Kota Sukabumi 2.0984319 3.2538914 2.8384285 1.6697068 4.3009988
## Kota Bandung 3.6657544 3.1855775 2.9911986 3.5999728 2.2179349
## Kota Cirebon 2.0776240 3.1623683 2.7019025 1.5194302 3.9924399
## Kota Bekasi 3.7544106 3.2234800 3.3496841 3.1330356 3.9431884
## Kota Depok 2.2270178 2.7456923 2.0506759 1.6811949 2.3589570
## Kota Cimahi 2.1484741 3.3901003 2.8963854 1.6365632 4.2507973
## Kota Tasikmalaya 1.7740935 2.7790849 2.3158784 1.1419668 3.6339403
## Kota Banjar 2.4416097 3.6566020 3.2332855 2.0537269 4.6971416
## Bekasi Bandung Barat Pangandaran Kota Bogor Kota Sukabumi
## Sukabumi
## Cianjur
## Bandung
## Garut
## Tasikmalaya
## Ciamis
## Kuningan
## Cirebon
## Majalengka
## Sumedang
## Indramayu
## Subang
## Purwakarta
## Karawang
## Bekasi
## Bandung Barat 4.8100394
## Pangandaran 6.5820487 2.4093177
## Kota Bogor 4.3668607 1.8546041 2.3877272
## Kota Sukabumi 6.3190965 2.4931432 0.6392547 2.0225595
## Kota Bandung 3.0022931 3.3575158 5.0198869 3.1731555 4.7937609
## Kota Cirebon 5.9750283 2.4487410 1.0674296 1.7461402 0.5852155
## Kota Bekasi 4.3146560 3.2863393 4.1685049 2.8086175 3.8870125
## Kota Depok 3.6479125 2.1328409 3.2428727 1.0146594 2.9308194
## Kota Cimahi 6.2514059 2.5618919 0.7794930 1.9823840 0.2596385
## Kota Tasikmalaya 5.5384124 1.9989082 1.2638496 1.3355339 0.8641087
## Kota Banjar 6.7450073 2.8867320 0.6570437 2.4690788 0.5130001
## Kota Bandung Kota Cirebon Kota Bekasi Kota Depok Kota Cimahi
## Sukabumi
## Cianjur
## Bandung
## Garut
## Tasikmalaya
## Ciamis
## Kuningan
## Cirebon
## Majalengka
## Sumedang
## Indramayu
## Subang
## Purwakarta
## Karawang
## Bekasi
## Bandung Barat
## Pangandaran
## Kota Bogor
## Kota Sukabumi
## Kota Bandung
## Kota Cirebon 4.3680198
## Kota Bekasi 2.9148146 3.5727992
## Kota Depok 2.5332035 2.6423059 2.5606821
## Kota Cimahi 4.8095451 0.5707801 3.9426300 2.9176361
## Kota Tasikmalaya 4.0139733 0.6126700 3.1286783 2.2403784 0.8815505
## Kota Banjar 5.2749245 0.9825656 4.3475305 3.3827332 0.5170647
## Kota Tasikmalaya
## Sukabumi
## Cianjur
## Bandung
## Garut
## Tasikmalaya
## Ciamis
## Kuningan
## Cirebon
## Majalengka
## Sumedang
## Indramayu
## Subang
## Purwakarta
## Karawang
## Bekasi
## Bandung Barat
## Pangandaran
## Kota Bogor
## Kota Sukabumi
## Kota Bandung
## Kota Cirebon
## Kota Bekasi
## Kota Depok
## Kota Cimahi
## Kota Tasikmalaya
## Kota Banjar 1.3509546
Data diatas menjadi gambaran jarak antar kab/kota untuk aspek kesehatan dan pendidikan ini. Namun untuk mendalami lebih lanjut dalam mengetahui kelompok-kelompoknya, mari kita lakukan analisis klaster.
Single Linkage: menghitung jarak minimum antara klaster sebelum penggabungan. Hubungan ini dapat digunakan untuk mendeteksi nilai tinggi dalam dataset Anda yang mungkin merupakan outlier karena akan digabungkan di bagian akhir.
hclust_single <- hclust(dist_mat, method = 'single')
plot(hclust_single)
Bagaimana cara membaca dendogram?
Dalam pengelompokan hierarki, Anda mengkategorikan objek ke dalam hierarki yang mirip dengan diagram seperti pohon yang disebut dendogram. Jarak pemisahan atau penggabungan (disebut tinggi) ditunjukkan pada sumbu y pada dendogram di bawah ini.
Pada gambar di atas, pertama-tama 4 dan 6 digabungkan ke dalam satu cluster, katakanlah cluster 1, karena jaraknya paling dekat, diikuti oleh titik 1 dan 2, katakanlah cluster 2. Setelah itu 5 digabungkan dalam cluster 1 yang sama diikuti oleh 3 yang menghasilkan dua cluster. Akhirnya kedua cluster tersebut digabungkan menjadi satu cluster dan di sinilah proses pengelompokan berhenti.
Satu pertanyaan yang mungkin membuat Anda penasaran adalah bagaimana Anda memutuskan kapan harus berhenti menggabungkan cluster? Hal ini tergantung pada domain knowledge yang Anda miliki tentang data. Misalnya, jika Anda mengelompokkan pemain sepak bola di lapangan berdasarkan posisi mereka di lapangan yang akan mewakili koordinat mereka untuk penghitungan jarak, Anda sudah tahu bahwa Anda harus mengakhiri dengan hanya 2 cluster karena hanya ada dua tim yang memainkan pertandingan sepak bola.
Namun terkadang Anda juga tidak memiliki informasi tersebut. Pada kasus seperti itu, Anda dapat memanfaatkan hasil dari dendogram untuk memperkirakan jumlah cluster. Anda memotong pohon dendogram dengan garis horizontal pada ketinggian di mana garis tersebut dapat melintasi jarak maksimum ke atas dan ke bawah tanpa memotong titik penggabungan. Pada kasus di atas, ketinggiannya adalah antara 1,5 dan 2,5 seperti yang ditunjukkan:
Jika Anda melakukan pemotongan seperti yang ditunjukkan, Anda hanya akan mendapatkan dua klaster.
Perhatikan bahwa Anda tidak perlu melakukan pemotongan hanya pada tempat tersebut, Anda dapat memilih titik mana pun sebagai titik potong tergantung pada berapa banyak cluster yang Anda inginkan. Sebagai contoh, pemotongan di bawah 1,5 dan di atas 1 akan memberikan Anda 3 cluster.
Perhatikan bahwa ini bukanlah aturan yang baku untuk menentukan jumlah cluster. Anda juga dapat mempertimbangkan plot seperti plot Silhouette, plot siku, atau beberapa ukuran numerik seperti indeks Dunn, gamma Hubert, dll. yang menunjukkan variasi kesalahan dengan jumlah cluster (k), dan Anda memilih nilai k di mana kesalahannya terkecil.
Mari kita coba untuk memilih jumlah kluster sebanyak 5 pada single linkage ini.
plot(hclust_single)
rect.hclust(hclust_single , k = 5, border = 2:6)
abline(h = 5, col = 'red')
Bisa terlihat ke-5 kluster yang terbentuk pada dendrogram di atas.
Kalian juga bisa melakukannya dengan visualisasi yang lebih jelas,
yaitu dengan dendextend
.
library(dendextend)
##
## ---------------------
## Welcome to dendextend version 1.17.1
## Type citation('dendextend') for how to cite the package.
##
## Type browseVignettes(package = 'dendextend') for the package vignette.
## The github page is: https://github.com/talgalili/dendextend/
##
## Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
## You may ask questions at stackoverflow, use the r and dendextend tags:
## https://stackoverflow.com/questions/tagged/dendextend
##
## To suppress this message use: suppressPackageStartupMessages(library(dendextend))
## ---------------------
##
## Attaching package: 'dendextend'
## The following object is masked from 'package:stats':
##
## cutree
sing_dend_obj <- as.dendrogram(hclust_single)
sing_col_dend <- color_branches(sing_dend_obj, k = 5)
plot(sing_col_dend)
Visuaslisasi diatas bisa dilihat lebih mudah terkait pembentukan klasternya melalui warna branches yang dihasilkan. Mari kita melihat bagaimana karakteristik klaster yang terbentuk.
Melakukan cutree klaster terlebih dahulu.
# Menentukan klaster dengan cutree
num_clusters <- 5
clusters_single <- cutree(hclust_single, k = num_clusters)
Menambahkan kolom klaster pada setiap data. Untuk step ini kita kembali menggunakan data awal (bukan dalam bentuk scaled). Namun sebelumnya kita ubah terlebih dahulu KabKota menjadi index dataframenya.
# untuk mempermudah interpretasi, kolom kabKota dijadikan index dataframe
new_index_data <- data
rownames(new_index_data) <- new_index_data[, "KabKota"]
# menghapus kolom kabKota sebelumnya
new_index_data <- new_index_data[, -which(names(new_index_data) == "KabKota")]
new_index_data
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## Bogor 639 1788 348 25 101 4804 153
## Sukabumi 311 1205 147 7 58 3451 54
## Cianjur 268 1254 164 3 45 2896 6
## Bandung 302 1431 130 7 62 4198 131
## Garut 339 1583 159 6 65 3963 96
## Tasikmalaya 240 1090 116 1 40 2278 29
## Ciamis 106 751 57 4 37 1586 45
## Kuningan 94 650 41 7 37 1417 13
## Cirebon 183 923 103 10 57 2591 28
## Majalengka 103 668 52 3 32 1461 24
## Sumedang 101 612 76 2 32 1644 78
## Indramayu 193 892 116 6 49 2311 20
## Subang 151 872 102 7 40 1836 80
## Purwakarta 165 429 55 11 20 1010 77
## Karawang 145 890 97 20 50 2271 187
## Bekasi 304 917 178 44 39 2457 240
## Bandung Barat 151 704 91 6 31 2209 64
## Pangandaran 47 295 24 1 15 520 11
## Kota Bogor 120 223 98 17 24 965 94
## Kota Sukabumi 41 104 32 6 15 447 22
## Kota Bandung 234 634 132 33 73 1973 118
## Kota Cirebon 43 134 29 11 22 330 31
## Kota Bekasi 254 441 143 38 31 1546 0
## Kota Depok 206 275 134 20 32 1003 113
## Kota Cimahi 36 101 24 7 13 398 33
## Kota Tasikmalaya 69 208 50 13 20 840 35
## Kota Banjar 22 82 14 3 10 199 18
# Menambahkan kolom klaster ke data frame
data_with_clusters_single <- cbind(data.frame(new_index_data), Cluster = clusters_single)
data_with_clusters_single
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## Bogor 639 1788 348 25 101 4804 153
## Sukabumi 311 1205 147 7 58 3451 54
## Cianjur 268 1254 164 3 45 2896 6
## Bandung 302 1431 130 7 62 4198 131
## Garut 339 1583 159 6 65 3963 96
## Tasikmalaya 240 1090 116 1 40 2278 29
## Ciamis 106 751 57 4 37 1586 45
## Kuningan 94 650 41 7 37 1417 13
## Cirebon 183 923 103 10 57 2591 28
## Majalengka 103 668 52 3 32 1461 24
## Sumedang 101 612 76 2 32 1644 78
## Indramayu 193 892 116 6 49 2311 20
## Subang 151 872 102 7 40 1836 80
## Purwakarta 165 429 55 11 20 1010 77
## Karawang 145 890 97 20 50 2271 187
## Bekasi 304 917 178 44 39 2457 240
## Bandung Barat 151 704 91 6 31 2209 64
## Pangandaran 47 295 24 1 15 520 11
## Kota Bogor 120 223 98 17 24 965 94
## Kota Sukabumi 41 104 32 6 15 447 22
## Kota Bandung 234 634 132 33 73 1973 118
## Kota Cirebon 43 134 29 11 22 330 31
## Kota Bekasi 254 441 143 38 31 1546 0
## Kota Depok 206 275 134 20 32 1003 113
## Kota Cimahi 36 101 24 7 13 398 33
## Kota Tasikmalaya 69 208 50 13 20 840 35
## Kota Banjar 22 82 14 3 10 199 18
## Cluster
## Bogor 1
## Sukabumi 2
## Cianjur 2
## Bandung 2
## Garut 2
## Tasikmalaya 2
## Ciamis 2
## Kuningan 2
## Cirebon 2
## Majalengka 2
## Sumedang 2
## Indramayu 2
## Subang 2
## Purwakarta 2
## Karawang 2
## Bekasi 3
## Bandung Barat 2
## Pangandaran 2
## Kota Bogor 2
## Kota Sukabumi 2
## Kota Bandung 4
## Kota Cirebon 2
## Kota Bekasi 5
## Kota Depok 2
## Kota Cimahi 2
## Kota Tasikmalaya 2
## Kota Banjar 2
Melihat keanggotaan setiap klasternya
# Jika nama kabkota adalah row names, Anda bisa mendapatkannya seperti ini:
kabkota_names <- rownames(data_with_clusters_single)
# Kemudian, Anda bisa melihat keanggotaan klaster dengan nama kabkota:
for(k in unique(data_with_clusters_single$Cluster)) {
cat(paste("Klaster", k, ": \n"))
cat(paste(kabkota_names[data_with_clusters_single$Cluster == k], collapse = ", "), "\n\n")
}
## Klaster 1 :
## Bogor
##
## Klaster 2 :
## Sukabumi, Cianjur, Bandung, Garut, Tasikmalaya, Ciamis, Kuningan, Cirebon, Majalengka, Sumedang, Indramayu, Subang, Purwakarta, Karawang, Bandung Barat, Pangandaran, Kota Bogor, Kota Sukabumi, Kota Cirebon, Kota Depok, Kota Cimahi, Kota Tasikmalaya, Kota Banjar
##
## Klaster 3 :
## Bekasi
##
## Klaster 4 :
## Kota Bandung
##
## Klaster 5 :
## Kota Bekasi
Melihat karaktersitik setiap klaster menggunakan dplyr
# Melihat karakteristik setiap klaster
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
cluster_summary_single <- data_with_clusters_single %>%
group_by(Cluster) %>%
summarize_all(list(mean = mean, sd = sd, median = median))
cluster_summary_single
## # A tibble: 5 × 22
## Cluster JmlSMP_mean JmlSD_mean JmlSMA_mean JmlRS_mean JmlPuskesmas_mean
## <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 639 1788 348 25 101
## 2 2 149. 669. 83.1 7.74 35.0
## 3 3 304 917 178 44 39
## 4 4 234 634 132 33 73
## 5 5 254 441 143 38 31
## # ℹ 16 more variables: JmlPosyandu_mean <dbl>, JmlKlinik_mean <dbl>,
## # JmlSMP_sd <dbl>, JmlSD_sd <dbl>, JmlSMA_sd <dbl>, JmlRS_sd <dbl>,
## # JmlPuskesmas_sd <dbl>, JmlPosyandu_sd <dbl>, JmlKlinik_sd <dbl>,
## # JmlSMP_median <int>, JmlSD_median <int>, JmlSMA_median <int>,
## # JmlRS_median <int>, JmlPuskesmas_median <int>, JmlPosyandu_median <int>,
## # JmlKlinik_median <int>
Interpretasi
Klaster 1
Klaster 2
Klaster 3
Klaster 4
Klaster 5
Notes: Kolom yang memiliki nilai NaN
untuk standar deviasi (sd) menunjukkan bahwa hanya ada satu elemen dalam
klaster tersebut, sehingga tidak mungkin menghitung deviasi standar.
Dari hasil tersebut, bisa terlihat pengelompokkan mengumpul pada klaster 2 yang memiliki banyak anggota. Sedangkan pada klaster lain hanya memiliki 1 anggota masing-masing. Lalu, bagaimana kita bisa mendapatkan jumlah klaster yang tepat? Hal ini sangat bergantung pada tujuan penelitian dan domain knowledge. Apabila penelitian memang dituntut secara tegas untuk menentukan 5 klaster, maka klaster tersebut harus diikuti. Namun, jika ingin menemukan angka klaster optimum berdasarkan data yang dimiliki, maka kita bisa menggunakan analisis stopping rules untuk analisis klaster.
Library yang dibutuhkan
# install.packages('fpc') -> untuk cluster.stats Calinski-Harabasz
library(fpc)
# install.packages('clValid') -> untuk dunn
library(clValid)
Calinski-Harabasz
Pada perhitungan Calinski-Harabasz Index, pendekatan looping digunakan untuk melakukan iterasi pehitungan index mulai dari jumlah klaster paling kecil hingga ke terbesar. Pada praktik umum, batas klaster yang digunakan biasanya adalah 10 klaster. Hal ini dinilai sebagai batas jumlah klaster yang masih bisa menyediakan insight signifikan, apalagi dengan data yang hanya ada 27 data.
# Inisialisasi vektor untuk menyimpan skor Calinski-Harabasz
ch_scores_single <- numeric(9)
# menghitung index dengan iterasi 2-10 klaster
for (k in 2:10) {
clusters <- cutree(hclust_single, k)
ch_score <- cluster.stats(dist_mat, clusters)$ch
ch_scores_single[k-1] <- ch_score
cat("k =", k, ": Calinski-Harabasz Index =", ch_score, "\n")
}
## k = 2 : Calinski-Harabasz Index = 9.504155
## k = 3 : Calinski-Harabasz Index = 7.732228
## k = 4 : Calinski-Harabasz Index = 6.025049
## k = 5 : Calinski-Harabasz Index = 5.369267
## k = 6 : Calinski-Harabasz Index = 4.811465
## k = 7 : Calinski-Harabasz Index = 10.80516
## k = 8 : Calinski-Harabasz Index = 16.98808
## k = 9 : Calinski-Harabasz Index = 14.87939
## k = 10 : Calinski-Harabasz Index = 18.20564
Perhatikan juga hasil pada saat k bernilai 5: 5.369267
Dunn Index
# Inisialisasi vektor untuk menyimpan skor Dunn
dunn_scores_single <- numeric(9) # Misalkan kita ingin mengevaluasi dari 2 sampai 10 klaster
for (k in 2:10) {
# Memotong pohon klaster untuk mendapatkan vektor klaster
clusters <- cutree(hclust_single, k)
# Menghitung indeks Dunn menggunakan matriks jarak dan klaster yang dihasilkan
dunn_scores_single[k-1] <- dunn(dist_mat, clusters)
# Mencetak skor Dunn untuk jumlah klaster k
cat("Jumlah klaster:", k, "- Skor Dunn:", dunn_scores_single[k-1], "\n")
}
## Jumlah klaster: 2 - Skor Dunn: 0.6630655
## Jumlah klaster: 3 - Skor Dunn: 0.4653442
## Jumlah klaster: 4 - Skor Dunn: 0.4123224
## Jumlah klaster: 5 - Skor Dunn: 0.357133
## Jumlah klaster: 6 - Skor Dunn: 0.3559405
## Jumlah klaster: 7 - Skor Dunn: 0.3041904
## Jumlah klaster: 8 - Skor Dunn: 0.3674025
## Jumlah klaster: 9 - Skor Dunn: 0.3631844
## Jumlah klaster: 10 - Skor Dunn: 0.362507
Perhatikan hasil pada saat k bernilai 5: 0.357133
Visualisasi hasil keduanya
# Rentang jumlah klaster yang dievaluasi
k_range <- 2:10
# Plot untuk Indeks Calinski-Harabasz
plot(k_range, ch_scores_single, type = 'o', pch = 19, col = 'blue', xlab = 'Jumlah Klaster', ylab = 'Indeks Calinski-Harabasz',
main = 'Indeks Calinski-Harabasz vs. Jumlah Klaster (Single Linkage)')
abline(v = which.max(ch_scores_single) + 1, col = "red", lwd = 2, lty = 2)
# Plot untuk Indeks Dunn
plot(k_range, dunn_scores_single, type = 'o', pch = 19, col = 'red', xlab = 'Jumlah Klaster', ylab = 'Skor Dunn',
main = 'Skor Dunn vs. Jumlah Klaster (Single Linkage)')
abline(v = which.max(dunn_scores_single) + 1, col = "blue", lwd = 2, lty = 2)
Berdasarkan Indeks Calinski-Harabasz, klaster optimum (dalam iterasi hingga 10 klaster) adalah 10 klaster. Sedangkan Skor Dunn optimum pada 2 klaster. Mengapa berbeda?
Perbedaan dalam hasil yang kalian lihat antara indeks Calinski-Harabasz dan indeks Dunn bisa disebabkan oleh karakteristik metrik yang berbeda:
single
yang digunakan dalam hclust
cenderung menciptakan rantai klaster panjang, yang mungkin tidak ideal
untuk menangkap struktur klaster yang alami. Ini bisa memengaruhi skor
kedua metrik secara berbeda, tergantung pada bagaimana klaster yang
dihasilkan cocok dengan asumsi masing-masing indeks.Pada akhirnya, pengambilan keputusan tentang jumlah klaster tidak harus bergantung pada satu indeks saja, melainkan kombinasi dari berbagai indeks, visualisasi, dan, yang paling penting, pengetahuan domain yang digunakan. Maka dari itu,iterasi 1 jenis klaster ini (single linkage) tidak lah cukup.
Complete Linkage: menghitung jarak maksimum antar klaster sebelum penggabungan.
hclust_complete <- hclust(dist_mat, method = 'complete')
plot(hclust_complete)
Selanjutnya, kita mengelompokkan dendrogram ke dalam 5 kelompok seperti tujuan awal modul ini.
plot(hclust_complete)
rect.hclust(hclust_complete , k = 5, border = 2:6)
abline(h = 5, col = 'red')
Melakukan bentuk visualisasi lainnya.
comp_dend_obj <- as.dendrogram(hclust_complete)
comp_col_dend <- color_branches(comp_dend_obj, k = 5)
plot(comp_col_dend)
Setelah itu, mari kita lihat karakteristik setiap klaster untuk melakukan interpretasi secara lengkap.
# Menentukan klaster dengan cutree
num_clusters <- 5
clusters_comp <- cutree(hclust_complete, k = num_clusters)
Lalu, kita gabungkan dengan data kita sebelumnya
# Menambahkan kolom klaster ke data frame
data_with_clusters_comp <- cbind(data.frame(new_index_data), Cluster = clusters_comp)
data_with_clusters_comp
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## Bogor 639 1788 348 25 101 4804 153
## Sukabumi 311 1205 147 7 58 3451 54
## Cianjur 268 1254 164 3 45 2896 6
## Bandung 302 1431 130 7 62 4198 131
## Garut 339 1583 159 6 65 3963 96
## Tasikmalaya 240 1090 116 1 40 2278 29
## Ciamis 106 751 57 4 37 1586 45
## Kuningan 94 650 41 7 37 1417 13
## Cirebon 183 923 103 10 57 2591 28
## Majalengka 103 668 52 3 32 1461 24
## Sumedang 101 612 76 2 32 1644 78
## Indramayu 193 892 116 6 49 2311 20
## Subang 151 872 102 7 40 1836 80
## Purwakarta 165 429 55 11 20 1010 77
## Karawang 145 890 97 20 50 2271 187
## Bekasi 304 917 178 44 39 2457 240
## Bandung Barat 151 704 91 6 31 2209 64
## Pangandaran 47 295 24 1 15 520 11
## Kota Bogor 120 223 98 17 24 965 94
## Kota Sukabumi 41 104 32 6 15 447 22
## Kota Bandung 234 634 132 33 73 1973 118
## Kota Cirebon 43 134 29 11 22 330 31
## Kota Bekasi 254 441 143 38 31 1546 0
## Kota Depok 206 275 134 20 32 1003 113
## Kota Cimahi 36 101 24 7 13 398 33
## Kota Tasikmalaya 69 208 50 13 20 840 35
## Kota Banjar 22 82 14 3 10 199 18
## Cluster
## Bogor 1
## Sukabumi 2
## Cianjur 2
## Bandung 2
## Garut 2
## Tasikmalaya 2
## Ciamis 3
## Kuningan 3
## Cirebon 2
## Majalengka 3
## Sumedang 3
## Indramayu 2
## Subang 3
## Purwakarta 3
## Karawang 4
## Bekasi 4
## Bandung Barat 3
## Pangandaran 3
## Kota Bogor 3
## Kota Sukabumi 3
## Kota Bandung 4
## Kota Cirebon 3
## Kota Bekasi 5
## Kota Depok 3
## Kota Cimahi 3
## Kota Tasikmalaya 3
## Kota Banjar 3
Melihat keanggotaan setiap klaster
# Jika nama kabkota adalah row names, Anda bisa mendapatkannya seperti ini:
kabkota_names <- rownames(data_with_clusters_comp)
# Kemudian, Anda bisa melihat keanggotaan klaster dengan nama kabkota:
for(k in unique(data_with_clusters_comp$Cluster)) {
cat(paste("Klaster", k, ": \n"))
cat(paste(kabkota_names[data_with_clusters_comp$Cluster == k], collapse = ", "), "\n\n")
}
## Klaster 1 :
## Bogor
##
## Klaster 2 :
## Sukabumi, Cianjur, Bandung, Garut, Tasikmalaya, Cirebon, Indramayu
##
## Klaster 3 :
## Ciamis, Kuningan, Majalengka, Sumedang, Subang, Purwakarta, Bandung Barat, Pangandaran, Kota Bogor, Kota Sukabumi, Kota Cirebon, Kota Depok, Kota Cimahi, Kota Tasikmalaya, Kota Banjar
##
## Klaster 4 :
## Karawang, Bekasi, Kota Bandung
##
## Klaster 5 :
## Kota Bekasi
Melihat karakteristik setiap klaster melalui summary statistics.
cluster_summary_comp <- data_with_clusters_comp %>%
group_by(Cluster) %>%
summarize_all(list(mean = mean, sd = sd, median = median))
cluster_summary_comp
## # A tibble: 5 × 22
## Cluster JmlSMP_mean JmlSD_mean JmlSMA_mean JmlRS_mean JmlPuskesmas_mean
## <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 639 1788 348 25 101
## 2 2 262. 1197. 134. 5.71 53.7
## 3 3 97 407. 58.6 7.87 25.3
## 4 4 228. 814. 136. 32.3 54
## 5 5 254 441 143 38 31
## # ℹ 16 more variables: JmlPosyandu_mean <dbl>, JmlKlinik_mean <dbl>,
## # JmlSMP_sd <dbl>, JmlSD_sd <dbl>, JmlSMA_sd <dbl>, JmlRS_sd <dbl>,
## # JmlPuskesmas_sd <dbl>, JmlPosyandu_sd <dbl>, JmlKlinik_sd <dbl>,
## # JmlSMP_median <int>, JmlSD_median <int>, JmlSMA_median <int>,
## # JmlRS_median <int>, JmlPuskesmas_median <int>, JmlPosyandu_median <int>,
## # JmlKlinik_median <int>
Interpretasi
Klaster 1
Klaster 2
Klaster 3
Klaster 4
Klaster 5
Calinski-Harabasz
# Inisialisasi vektor untuk menyimpan skor Calinski-Harabasz
ch_scores_comp <- numeric(9) # menghitung index dengan iterasi 2-10 klaster
for (k in 2:10) {
clusters <- cutree(hclust_complete, k)
ch_score <- cluster.stats(dist_mat, clusters)$ch
ch_scores_comp[k-1] <- ch_score
cat("k =", k, ": Calinski-Harabasz Index =", ch_score, "\n")
}
## k = 2 : Calinski-Harabasz Index = 9.504155
## k = 3 : Calinski-Harabasz Index = 16.22964
## k = 4 : Calinski-Harabasz Index = 19.06925
## k = 5 : Calinski-Harabasz Index = 17.57447
## k = 6 : Calinski-Harabasz Index = 20.67776
## k = 7 : Calinski-Harabasz Index = 20.21964
## k = 8 : Calinski-Harabasz Index = 24.45806
## k = 9 : Calinski-Harabasz Index = 31.48063
## k = 10 : Calinski-Harabasz Index = 33.62283
Perhatikan hasil pada saat k bernilai 5: 17.57447
Dunn Index
# Inisialisasi vektor untuk menyimpan skor Dunn
dunn_scores_comp <- numeric(9) # Misalkan kita ingin mengevaluasi dari 2 sampai 10 klaster
for (k in 2:10) {
# Memotong pohon klaster untuk mendapatkan vektor klaster
clusters <- cutree(hclust_complete, k)
# Menghitung indeks Dunn menggunakan matriks jarak dan klaster yang dihasilkan
dunn_scores_comp[k-1] <- dunn(dist_mat, clusters)
# Mencetak skor Dunn untuk jumlah klaster k
cat("Jumlah klaster:", k, "- Skor Dunn:", dunn_scores_comp[k-1], "\n")
}
## Jumlah klaster: 2 - Skor Dunn: 0.6630655
## Jumlah klaster: 3 - Skor Dunn: 0.2270872
## Jumlah klaster: 4 - Skor Dunn: 0.2842091
## Jumlah klaster: 5 - Skor Dunn: 0.362507
## Jumlah klaster: 6 - Skor Dunn: 0.3803649
## Jumlah klaster: 7 - Skor Dunn: 0.3965801
## Jumlah klaster: 8 - Skor Dunn: 0.4183443
## Jumlah klaster: 9 - Skor Dunn: 0.5148784
## Jumlah klaster: 10 - Skor Dunn: 0.679259
Perhatikan hasil pada saat k bernilai 5: 0.362507
Visualisasi hasil keduanya
# Rentang jumlah klaster yang dievaluasi
k_range <- 2:10
# Plot untuk Indeks Calinski-Harabasz
plot(k_range, ch_scores_comp, type = 'o', pch = 19, col = 'blue', xlab = 'Jumlah Klaster', ylab = 'Indeks Calinski-Harabasz',
main = 'Indeks Calinski-Harabasz vs. Jumlah Klaster (Complete Linkage)')
abline(v = which.max(ch_scores_comp) + 1, col = "red", lwd = 2, lty = 2)
# Plot untuk Indeks Dunn
plot(k_range, dunn_scores_comp, type = 'o', pch = 19, col = 'red', xlab = 'Jumlah Klaster', ylab = 'Skor Dunn',
main = 'Skor Dunn vs. Jumlah Klaster (Complete Linkage)')
abline(v = which.max(dunn_scores_comp) + 1, col = "blue", lwd = 2, lty = 2)
Keduanya memberikan jumlah klaster optimum pada 10 klaster. Hal ini bisa menjadi insight baru untuk mencoba iterasi pembentukan 10 klaster pada data. Pada kasus ini coba lakukan masing-masing secara mandiri.
Average Linkage:menghitung jarak rata-rata antar klaster sebelum penggabungan.
hclust_avg <- hclust(dist_mat, method = 'average')
plot(hclust_avg)
Selanjutnya, kita mengelompokkan dendrogram ke dalam 5 kelompok seperti tujuan awal modul ini.
plot(hclust_avg)
rect.hclust(hclust_avg , k = 5, border = 2:6)
abline(h = 5, col = 'red')
Melakukan bentuk visualisasi lainnya.
avg_dend_obj <- as.dendrogram(hclust_avg)
avg_col_dend <- color_branches(avg_dend_obj, k = 5)
plot(avg_col_dend)
Setelah itu, mari kita lihat karakteristik setiap klaster untuk melakukan interpretasi secara lengkap.
# Menentukan klaster dengan cutree
num_clusters <- 5
clusters_avg <- cutree(hclust_avg, k = num_clusters)
Lalu, kita gabungkan dengan data kita sebelumnya
# Menambahkan kolom klaster ke data frame
data_with_clusters_avg <- cbind(data.frame(new_index_data), Cluster = clusters_avg)
data_with_clusters_avg
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## Bogor 639 1788 348 25 101 4804 153
## Sukabumi 311 1205 147 7 58 3451 54
## Cianjur 268 1254 164 3 45 2896 6
## Bandung 302 1431 130 7 62 4198 131
## Garut 339 1583 159 6 65 3963 96
## Tasikmalaya 240 1090 116 1 40 2278 29
## Ciamis 106 751 57 4 37 1586 45
## Kuningan 94 650 41 7 37 1417 13
## Cirebon 183 923 103 10 57 2591 28
## Majalengka 103 668 52 3 32 1461 24
## Sumedang 101 612 76 2 32 1644 78
## Indramayu 193 892 116 6 49 2311 20
## Subang 151 872 102 7 40 1836 80
## Purwakarta 165 429 55 11 20 1010 77
## Karawang 145 890 97 20 50 2271 187
## Bekasi 304 917 178 44 39 2457 240
## Bandung Barat 151 704 91 6 31 2209 64
## Pangandaran 47 295 24 1 15 520 11
## Kota Bogor 120 223 98 17 24 965 94
## Kota Sukabumi 41 104 32 6 15 447 22
## Kota Bandung 234 634 132 33 73 1973 118
## Kota Cirebon 43 134 29 11 22 330 31
## Kota Bekasi 254 441 143 38 31 1546 0
## Kota Depok 206 275 134 20 32 1003 113
## Kota Cimahi 36 101 24 7 13 398 33
## Kota Tasikmalaya 69 208 50 13 20 840 35
## Kota Banjar 22 82 14 3 10 199 18
## Cluster
## Bogor 1
## Sukabumi 2
## Cianjur 3
## Bandung 2
## Garut 2
## Tasikmalaya 3
## Ciamis 3
## Kuningan 3
## Cirebon 3
## Majalengka 3
## Sumedang 3
## Indramayu 3
## Subang 3
## Purwakarta 3
## Karawang 4
## Bekasi 4
## Bandung Barat 3
## Pangandaran 3
## Kota Bogor 3
## Kota Sukabumi 3
## Kota Bandung 4
## Kota Cirebon 3
## Kota Bekasi 5
## Kota Depok 3
## Kota Cimahi 3
## Kota Tasikmalaya 3
## Kota Banjar 3
Melihat keanggotaan setiap klaster
# Jika nama kabkota adalah row names, Anda bisa mendapatkannya seperti ini:
kabkota_names <- rownames(data_with_clusters_avg)
# Kemudian, Anda bisa melihat keanggotaan klaster dengan nama kabkota:
for(k in unique(data_with_clusters_avg$Cluster)) {
cat(paste("Klaster", k, ": \n"))
cat(paste(kabkota_names[data_with_clusters_avg$Cluster == k], collapse = ", "), "\n\n")
}
## Klaster 1 :
## Bogor
##
## Klaster 2 :
## Sukabumi, Bandung, Garut
##
## Klaster 3 :
## Cianjur, Tasikmalaya, Ciamis, Kuningan, Cirebon, Majalengka, Sumedang, Indramayu, Subang, Purwakarta, Bandung Barat, Pangandaran, Kota Bogor, Kota Sukabumi, Kota Cirebon, Kota Depok, Kota Cimahi, Kota Tasikmalaya, Kota Banjar
##
## Klaster 4 :
## Karawang, Bekasi, Kota Bandung
##
## Klaster 5 :
## Kota Bekasi
Melihat karakteristik setiap klaster
cluster_summary_avg <- data_with_clusters_avg %>%
group_by(Cluster) %>%
summarize_all(list(mean = mean, sd = sd, median = median))
cluster_summary_avg
## # A tibble: 5 × 22
## Cluster JmlSMP_mean JmlSD_mean JmlSMA_mean JmlRS_mean JmlPuskesmas_mean
## <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 639 1788 348 25 101
## 2 2 317. 1406. 145. 6.67 61.7
## 3 3 123. 540. 72.5 7.26 30.1
## 4 4 228. 814. 136. 32.3 54
## 5 5 254 441 143 38 31
## # ℹ 16 more variables: JmlPosyandu_mean <dbl>, JmlKlinik_mean <dbl>,
## # JmlSMP_sd <dbl>, JmlSD_sd <dbl>, JmlSMA_sd <dbl>, JmlRS_sd <dbl>,
## # JmlPuskesmas_sd <dbl>, JmlPosyandu_sd <dbl>, JmlKlinik_sd <dbl>,
## # JmlSMP_median <int>, JmlSD_median <int>, JmlSMA_median <int>,
## # JmlRS_median <int>, JmlPuskesmas_median <int>, JmlPosyandu_median <int>,
## # JmlKlinik_median <int>
Interpretasi
Klaster 1 (Bogor)
Klaster ini menonjol dengan jumlah fasilitas pendidikan dan kesehatan yang sangat tinggi dibandingkan klaster lain, yang dapat menunjukkan karakteristik wilayah urban dengan aksesibilitas dan ketersediaan fasilitas yang luas. Keberadaan banyak sekolah menandakan fokus yang kuat pada pendidikan, sementara keberadaan rumah sakit, puskesmas, posyandu, dan klinik yang banyak mencerminkan sistem kesehatan yang berkembang dengan baik, menawarkan berbagai layanan kesehatan kepada masyarakat. Ini mungkin mengindikasikan penduduk yang besar dan kepadatan yang tinggi, dengan infrastruktur yang mendukung kebutuhan pendidikan dan kesehatan masyarakat secara komprehensif.
Klaster 2 (Sukabumi, Bandung, Garut)
Klaster ini memiliki jumlah fasilitas pendidikan dan kesehatan yang moderat, menunjukkan wilayah dengan perkembangan urban yang baik namun mungkin tidak sepadat Klaster 1. Variabilitas dalam jumlah fasilitas antar wilayah dalam klaster ini bisa mengindikasikan adanya perbedaan tingkat urbanisasi dan kepadatan penduduk. Meskipun demikian, ketersediaan fasilitas yang relatif tinggi ini menandakan akses yang baik ke pendidikan dan layanan kesehatan, mendukung kebutuhan dasar masyarakatnya.
Klaster 3 (Cianjur, Tasikmalaya, Ciamis, dst.)
Dengan jumlah entitas terbanyak dan variasi fasilitas kesehatan serta pendidikan yang signifikan, Klaster 3 mungkin mencakup wilayah dengan tingkat urbanisasi yang beragam, dari semi-urban hingga rural. Variabilitas tinggi dalam distribusi fasilitas menunjukkan perbedaan yang besar dalam aksesibilitas dan ketersediaan layanan antar wilayah. Klaster ini kemungkinan mencakup wilayah dengan tantangan geografis atau demografis yang mempengaruhi distribusi fasilitas, menunjukkan perluasan layanan yang belum merata.
Klaster 4 (Karawang, Bekasi, Kota Bandung)
Dengan jumlah rata-rata fasilitas kesehatan yang tinggi, khususnya rumah sakit dan klinik, Klaster 4 mungkin menunjukkan wilayah yang sangat urban dengan kepadatan penduduk tinggi dan kebutuhan kesehatan yang kompleks. Ketersediaan fasilitas pendidikan yang moderat bersama dengan fasilitas kesehatan yang luas mungkin mencerminkan fokus kuat pada kesejahteraan dan layanan kesehatan masyarakat. Variasi dalam jumlah fasilitas bisa menunjukkan perbedaan dalam prioritas atau kapasitas layanan antar kota dalam klaster.
Klaster 5 (Kota Bekasi)
Klaster ini, dengan jumlah fasilitas yang lebih terfokus, menunjukkan karakteristik wilayah urban dengan fokus yang lebih spesifik pada pendidikan dan kesehatan. Meskipun mungkin tidak memiliki keanekaragaman fasilitas sebanyak klaster lain, keberadaan fasilitas yang cukup tinggi di Kota Bekasi menunjukkan infrastruktur yang mendukung kebutuhan mendasar pendiduknya. Ketiadaan variasi data menunjukkan homogenitas dalam distribusi fasilitas, kemungkinan karena fokus pada pengembangan infrastruktur yang merata di seluruh wilayah.
Calinski-Harabasz
# Inisialisasi vektor untuk menyimpan skor Calinski-Harabasz
ch_scores_avg <- numeric(9) # menghitung index dengan iterasi 2-10 klaster
for (k in 2:10) {
clusters <- cutree(hclust_avg, k)
ch_score <- cluster.stats(dist_mat, clusters)$ch
ch_scores_avg[k-1] <- ch_score
cat("k =", k, ": Calinski-Harabasz Index =", ch_score, "\n")
}
## k = 2 : Calinski-Harabasz Index = 9.504155
## k = 3 : Calinski-Harabasz Index = 14.47158
## k = 4 : Calinski-Harabasz Index = 13.58756
## k = 5 : Calinski-Harabasz Index = 12.29036
## k = 6 : Calinski-Harabasz Index = 10.70125
## k = 7 : Calinski-Harabasz Index = 18.70103
## k = 8 : Calinski-Harabasz Index = 16.98808
## k = 9 : Calinski-Harabasz Index = 22.5999
## k = 10 : Calinski-Harabasz Index = 33.62283
Perhatikan hasil pada saat k bernilai 5: 12.29036
Dunn Index
# Inisialisasi vektor untuk menyimpan skor Dunn
dunn_scores_avg <- numeric(9) # Misalkan kita ingin mengevaluasi dari 2 sampai 10 klaster
for (k in 2:10) {
# Memotong pohon klaster untuk mendapatkan vektor klaster
clusters <- cutree(hclust_avg, k)
# Menghitung indeks Dunn menggunakan matriks jarak dan klaster yang dihasilkan
dunn_scores_avg[k-1] <- dunn(dist_mat, clusters)
# Mencetak skor Dunn untuk jumlah klaster k
cat("Jumlah klaster:", k, "- Skor Dunn:", dunn_scores_avg[k-1], "\n")
}
## Jumlah klaster: 2 - Skor Dunn: 0.6630655
## Jumlah klaster: 3 - Skor Dunn: 0.2630678
## Jumlah klaster: 4 - Skor Dunn: 0.2642953
## Jumlah klaster: 5 - Skor Dunn: 0.2642953
## Jumlah klaster: 6 - Skor Dunn: 0.2642953
## Jumlah klaster: 7 - Skor Dunn: 0.3674025
## Jumlah klaster: 8 - Skor Dunn: 0.3674025
## Jumlah klaster: 9 - Skor Dunn: 0.3961907
## Jumlah klaster: 10 - Skor Dunn: 0.679259
Perhatikan hasil pada saat k bernilai 5: 0.2642953
Visualisasi Keduanya
# Rentang jumlah klaster yang dievaluasi
k_range <- 2:10
# Plot untuk Indeks Calinski-Harabasz
plot(k_range, ch_scores_avg, type = 'o', pch = 19, col = 'blue', xlab = 'Jumlah Klaster', ylab = 'Indeks Calinski-Harabasz',
main = 'Indeks Calinski-Harabasz vs. Jumlah Klaster (Average Linkage)')
abline(v = which.max(ch_scores_avg) + 1, col = "red", lwd = 2, lty = 2)
# Plot untuk Indeks Dunn
plot(k_range, dunn_scores_avg, type = 'o', pch = 19, col = 'red', xlab = 'Jumlah Klaster', ylab = 'Skor Dunn',
main = 'Skor Dunn vs. Jumlah Klaster (Average Linkage)')
abline(v = which.max(dunn_scores_avg) + 1, col = "blue", lwd = 2, lty = 2)
Keduanya optimum pada 10 klaster.
Di sisi kiri diagram di atas, kita dapat melihat 2 kumpulan titik yang berbeda yang tidak diberi label dan diwarnai sebagai titik data yang serupa. Memasukkan model k-means ke data ini (sisi kanan) dapat mengungkapkan 2 kelompok yang berbeda (ditunjukkan dalam lingkaran dan warna yang berbeda).
Dalam dua dimensi, mudah bagi manusia untuk membagi kelompok-kelompok ini, tetapi dengan lebih banyak dimensi, Anda perlu menggunakan model.
Algoritma
Karena k-means memilih secara acak pusat-pusat cluster, algoritma ini perlu dijalankan dalam jumlah tertentu, yang ditetapkan oleh pengguna. Dengan cara ini, solusi terbaik akan tercapai, dengan meminimalkan metrics kualitas model. Metrics ini disebut within-cluster sum of squares (WCSS), yaitu jumlah jarak antara titik data dan pusat data yang sesuai untuk setiap klaster. Memang, semakin kecil pengukuran kualitas model kita, semakin kita akan mencapai model terbaik.
Sekarang, kita coba melakukan k-means clustering dengan 5 klaster.
set.seed(123) # penting!
km.out <- kmeans(new_normalized_data, centers = 5, nstart = 20)
km.out
## K-means clustering with 5 clusters of sizes 9, 8, 5, 4, 1
##
## Cluster means:
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu
## 1 -0.2537821 0.1827414 -0.2410802 -0.5841296 0.0266055 0.04238630
## 2 -0.8546838 -1.0852327 -0.8634690 -0.2762446 -1.0302981 -1.05467817
## 3 0.3676320 -0.1653456 0.5258763 1.6842402 0.2926605 -0.01987143
## 4 0.9486550 1.3950107 0.7168119 -0.5281505 0.8912844 1.43794372
## 5 3.4887296 2.2838748 3.5808450 1.1585236 2.9744953 2.40353090
## JmlKlinik
## 1 -0.40830429
## 2 -0.44535930
## 3 1.08955719
## 4 0.08529644
## 5 1.44864123
##
## Clustering vector:
## Bogor Sukabumi Cianjur Bandung
## 5 4 4 4
## Garut Tasikmalaya Ciamis Kuningan
## 4 1 1 1
## Cirebon Majalengka Sumedang Indramayu
## 1 1 1 1
## Subang Purwakarta Karawang Bekasi
## 1 2 3 3
## Bandung Barat Pangandaran Kota Bogor Kota Sukabumi
## 1 2 2 2
## Kota Bandung Kota Cirebon Kota Bekasi Kota Depok
## 3 2 3 3
## Kota Cimahi Kota Tasikmalaya Kota Banjar
## 2 2 2
##
## Within cluster sum of squares by cluster:
## [1] 7.766899 6.559790 19.358442 4.447357 0.000000
## (between_SS / total_SS = 79.0 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss" "tot.withinss"
## [6] "betweenss" "size" "iter" "ifault"
Catatan penting
set.seed
adalah fungsi di R yang digunakan untuk
menentukan titik awal dari pembangkitan bilangan acak, sehingga hasil
yang diperoleh bisa diulang atau konsisten pada saat kode dijalankan
berulang kali. Dalam konteks penggunaan set.seed
sebelum
melakukan clustering dengan k-means, fungsi ini memastikan bahwa hasil
dari k-means clustering adalah sama setiap kali kode tersebut
dijalankan, asalkan datasetnya tidak berubah.
K-means clustering adalah metode yang sensitif terhadap posisi awal
dari centroid-cluster yang ditentukan secara acak pada awal algoritma.
Oleh karena itu, titik awal yang berbeda bisa menghasilkan kelompok
akhir yang berbeda. Untuk mengatasi hal ini, nstart
digunakan dalam fungsi kmeans
untuk menjalankan algoritma
beberapa kali dengan titik awal yang berbeda, dan hasil terbaik (dengan
total jarak terkecil dari titik ke pusat cluster mereka) dipilih.
Penggunaan set.seed
memastikan bahwa “keacakan” dalam
pemilihan titik awal ini konsisten di setiap eksekusi, memungkinkan
hasil yang dapat diulang.
Argumen nstart=20
memberitahu R untuk menjalankan
algoritma k-means sebanyak 20 kali dengan titik awal yang berbeda.
Tujuannya adalah untuk mengurangi kemungkinan hasil yang buruk karena
pemilihan awal yang buruk untuk pusat cluster (centroid). Fungsi ini
akan memilih hasil terbaik dari ke-20 run tersebut, yaitu yang memiliki
total within-cluster sum of squares terkecil.
Interpretasi
JmlSMP
, JmlSD
, JmlSMA
,
JmlRS
, JmlPuskesmas
, JmlPosyandu
,
dan JmlKlinik
. Nilai-nilai ini menunjukkan karakteristik
pusat dari setiap cluster.cluster
untuk melihat
penugasan cluster, centers
untuk melihat pusat cluster,
withinss
untuk sum of squares dalam setiap cluster, dan
lain-lain. Ini berguna untuk analisis lebih lanjut terhadap hasil
clustering.Bisa berikan interpretasi dari hasil di atas?
Mari kita gabungkan hasil klaster ini ke dalam tabel utama (non-scaled).
data_with_clusters_kmeans <- new_index_data
data_with_clusters_kmeans$Cluster <- km.out$cluster
data_with_clusters_kmeans
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## Bogor 639 1788 348 25 101 4804 153
## Sukabumi 311 1205 147 7 58 3451 54
## Cianjur 268 1254 164 3 45 2896 6
## Bandung 302 1431 130 7 62 4198 131
## Garut 339 1583 159 6 65 3963 96
## Tasikmalaya 240 1090 116 1 40 2278 29
## Ciamis 106 751 57 4 37 1586 45
## Kuningan 94 650 41 7 37 1417 13
## Cirebon 183 923 103 10 57 2591 28
## Majalengka 103 668 52 3 32 1461 24
## Sumedang 101 612 76 2 32 1644 78
## Indramayu 193 892 116 6 49 2311 20
## Subang 151 872 102 7 40 1836 80
## Purwakarta 165 429 55 11 20 1010 77
## Karawang 145 890 97 20 50 2271 187
## Bekasi 304 917 178 44 39 2457 240
## Bandung Barat 151 704 91 6 31 2209 64
## Pangandaran 47 295 24 1 15 520 11
## Kota Bogor 120 223 98 17 24 965 94
## Kota Sukabumi 41 104 32 6 15 447 22
## Kota Bandung 234 634 132 33 73 1973 118
## Kota Cirebon 43 134 29 11 22 330 31
## Kota Bekasi 254 441 143 38 31 1546 0
## Kota Depok 206 275 134 20 32 1003 113
## Kota Cimahi 36 101 24 7 13 398 33
## Kota Tasikmalaya 69 208 50 13 20 840 35
## Kota Banjar 22 82 14 3 10 199 18
## Cluster
## Bogor 5
## Sukabumi 4
## Cianjur 4
## Bandung 4
## Garut 4
## Tasikmalaya 1
## Ciamis 1
## Kuningan 1
## Cirebon 1
## Majalengka 1
## Sumedang 1
## Indramayu 1
## Subang 1
## Purwakarta 2
## Karawang 3
## Bekasi 3
## Bandung Barat 1
## Pangandaran 2
## Kota Bogor 2
## Kota Sukabumi 2
## Kota Bandung 3
## Kota Cirebon 2
## Kota Bekasi 3
## Kota Depok 3
## Kota Cimahi 2
## Kota Tasikmalaya 2
## Kota Banjar 2
Melihat keanggotaan klaster
# Jika nama kabkota adalah row names, Anda bisa mendapatkannya seperti ini:
kabkota_names <- rownames(data_with_clusters_kmeans)
# Kemudian, Anda bisa melihat keanggotaan klaster dengan nama kabkota:
for(k in unique(data_with_clusters_kmeans$Cluster)) {
cat(paste("Klaster", k, ": \n"))
cat(paste(kabkota_names[data_with_clusters_kmeans$Cluster == k], collapse = ", "), "\n\n")
}
## Klaster 5 :
## Bogor
##
## Klaster 4 :
## Sukabumi, Cianjur, Bandung, Garut
##
## Klaster 1 :
## Tasikmalaya, Ciamis, Kuningan, Cirebon, Majalengka, Sumedang, Indramayu, Subang, Bandung Barat
##
## Klaster 2 :
## Purwakarta, Pangandaran, Kota Bogor, Kota Sukabumi, Kota Cirebon, Kota Cimahi, Kota Tasikmalaya, Kota Banjar
##
## Klaster 3 :
## Karawang, Bekasi, Kota Bandung, Kota Bekasi, Kota Depok
Melihat karakteristik setiap klaster
cluster_summary_kmeans <- data_with_clusters_kmeans %>%
group_by(Cluster) %>%
summarize_all(list(mean = mean, sd = sd, median = median))
cluster_summary_kmeans
## # A tibble: 5 × 22
## Cluster JmlSMP_mean JmlSD_mean JmlSMA_mean JmlRS_mean JmlPuskesmas_mean
## <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 147. 796. 83.8 5.11 39.4
## 2 2 67.9 197 40.8 8.62 17.4
## 3 3 229. 631. 137. 31 45
## 4 4 305 1368. 150 5.75 57.5
## 5 5 639 1788 348 25 101
## # ℹ 16 more variables: JmlPosyandu_mean <dbl>, JmlKlinik_mean <dbl>,
## # JmlSMP_sd <dbl>, JmlSD_sd <dbl>, JmlSMA_sd <dbl>, JmlRS_sd <dbl>,
## # JmlPuskesmas_sd <dbl>, JmlPosyandu_sd <dbl>, JmlKlinik_sd <dbl>,
## # JmlSMP_median <dbl>, JmlSD_median <dbl>, JmlSMA_median <dbl>,
## # JmlRS_median <dbl>, JmlPuskesmas_median <dbl>, JmlPosyandu_median <dbl>,
## # JmlKlinik_median <dbl>
Interpretasi
Klaster 1
Klaster 2
Klaster 3
Klaster 4
Klaster 5
WCSS
Meskipun kelihatannya hasilnya bagus, cara terbaik untuk menemukan model terbaik adalah dengan mencoba model yang berbeda dengan jumlah cluster yang berbeda. Jadi, kita perlu memulai dari model dengan satu cluster, setelah itu mencoba model dengan dua cluster dan seterusnya. Semua prosedur ini perlu dilacak dengan menggunakan representasi grafis, yang disebut scree plot, di mana jumlah cluster diplot pada sumbu x, sedangkan WCSS pada sumbu y.
Dalam studi kasus ini, kami membangun 10 model k-means, yang masing-masing akan memiliki jumlah cluster yang berbeda, mencapai maksimum 10 cluster. Selain itu, kita hanya akan menggunakan sebagian dari dataset. Jadi, kami hanya menyertakan harga dan jumlah ulasan. Untuk memplot scree plot, kita perlu menyimpan jumlah kuadrat total dalam cluster dari semua model ke dalam variabel wss.
# library for visualization
library(ggplot2)
# Decide how many clusters to look at
n_clusters <- 10
# Initialize total within sum of squares error: wss
wss <- numeric(n_clusters)
set.seed(123)
# Look over 1 to n possible clusters
for (i in 1:n_clusters) {
# Fit the model: km.out
km.out <- kmeans(new_normalized_data, centers = i, nstart = 20)
# Save the within cluster sum of squares
wss[i] <- km.out$tot.withinss
}
# Produce a scree plot
wss_df <- tibble(clusters = 1:n_clusters, wss = wss)
scree_plot <- ggplot(wss_df, aes(x = clusters, y = wss, group = 1)) +
geom_point(size = 4)+
geom_line() +
scale_x_continuous(breaks = c(2, 4, 6, 8, 10)) +
xlab('Number of clusters')
scree_plot
Dengan melihat scree plot, kita dapat melihat bagaimana jumlah kuadrat total dalam klaster menurun seiring dengan bertambahnya jumlah klaster. Kriteria untuk memilih jumlah cluster adalah dengan menemukan siku sedemikian rupa sehingga Anda dapat menemukan titik di mana WCSS menurun jauh lebih lambat setelah menambahkan cluster lain. Dalam kasus ini, hal ini tidak begitu jelas, jadi kita akan menambahkan garis horizontal untuk mendapatkan ide yang lebih baik:
scree_plot +
geom_hline(
yintercept = wss,
linetype = 'dashed',
col = c(rep('#000000',3),'#FF0000', rep('#000000', 6)) # nambahin garis merah
)
Dari hasil di atas, terlihat bahwa patahan screeplot terbesar ada setelah klaster 4. Setelah itu, penurunan terjadi tidak begitu drastis seperti sebelumnya. Maka dari itu, berdasarkan screplot WCSS ini, 4 klaster menjadi model terbaik.
Calinski-Harabasz
# Inisialisasi vektor untuk menyimpan skor Calinski-Harabasz
set.seed(123)
ch_scores <- numeric(9) # menghitung index dengan iterasi 2-10 klaster
for (k in 2:10) {
clust <- kmeans(new_normalized_data, centers = k, nstart = 20)
ch_score <- cluster.stats(dist_mat, clust$cluster)$ch
ch_scores[k-1] <- ch_score
cat("k =", k, ": Calinski-Harabasz Index =", ch_score, "\n")
}
## k = 2 : Calinski-Harabasz Index = 18.90029
## k = 3 : Calinski-Harabasz Index = 16.49498
## k = 4 : Calinski-Harabasz Index = 20.09877
## k = 5 : Calinski-Harabasz Index = 20.75058
## k = 6 : Calinski-Harabasz Index = 22.50812
## k = 7 : Calinski-Harabasz Index = 24.00612
## k = 8 : Calinski-Harabasz Index = 26.15942
## k = 9 : Calinski-Harabasz Index = 31.48063
## k = 10 : Calinski-Harabasz Index = 31.01886
Perhatikan hasil pada saat k bernilai 5: 20.75058
Dunn Index
# Inisialisasi vektor untuk menyimpan skor Dunn
set.seed(123)
dunn_scores <- numeric(9) # Misalkan kita ingin mengevaluasi dari 2 sampai 10 klaster
for (k in 2:10) {
# Memotong pohon klaster untuk mendapatkan vektor klaster
clust <- kmeans(new_normalized_data, centers = k, nstart = 20)
# Menghitung indeks Dunn menggunakan matriks jarak dan klaster yang dihasilkan
dunn_scores[k-1] <- dunn(dist_mat, clust$cluster)
# Mencetak skor Dunn untuk jumlah klaster k
cat("Jumlah klaster:", k, "- Skor Dunn:", dunn_scores[k-1], "\n")
}
## Jumlah klaster: 2 - Skor Dunn: 0.1654657
## Jumlah klaster: 3 - Skor Dunn: 0.1323844
## Jumlah klaster: 4 - Skor Dunn: 0.1656845
## Jumlah klaster: 5 - Skor Dunn: 0.2351658
## Jumlah klaster: 6 - Skor Dunn: 0.347758
## Jumlah klaster: 7 - Skor Dunn: 0.347758
## Jumlah klaster: 8 - Skor Dunn: 0.3803649
## Jumlah klaster: 9 - Skor Dunn: 0.5148784
## Jumlah klaster: 10 - Skor Dunn: 0.3375632
Perhatikan hasil pada saat k bernilai 5: 0.2351658
Visualisasi keduanya
# Rentang jumlah klaster yang dievaluasi
k_range <- 2:10
# Plot untuk Indeks Calinski-Harabasz
plot(k_range, ch_scores, type = 'o', pch = 19, col = 'blue', xlab = 'Jumlah Klaster', ylab = 'Indeks Calinski-Harabasz',
main = 'Indeks Calinski-Harabasz vs. Jumlah Klaster')
abline(v = which.max(ch_scores) + 1, col = "red", lwd = 2, lty = 2)
# Plot untuk Indeks Dunn
plot(k_range, dunn_scores, type = 'o', pch = 19, col = 'red', xlab = 'Jumlah Klaster', ylab = 'Skor Dunn',
main = 'Skor Dunn vs. Jumlah Klaster')
abline(v = which.max(dunn_scores) + 1, col = "blue", lwd = 2, lty = 2)
Keduanya memberikan hasil 9 klaster.
Lalu, bagaimana memilihnya? kembali lagi semua harus tergantung iterasi. Untuk mendapatkan klaster terbaik akan sangat bergantung pada domain knowledge analis.
Pada tahap ini kita akan menentukan model terbaik dengan membandingkan indeks Calinski-Harabasz dan Dunn pada seluruh analisis dengan 5 klaster.
ch_scores <- numeric(4)
dunn_scores <- numeric(4)
# 1. Single Linkage
clusters_single <- cutree(hclust_single, 5)
ch_scores[1] <- cluster.stats(dist_mat, clusters_single)$ch
dunn_scores[1] <- dunn(dist_mat, clusters_single)
# 2. Complete Linkage
clusters_complete <- cutree(hclust_complete, 5)
ch_scores[2] <- cluster.stats(dist_mat, clusters_complete)$ch
dunn_scores[2] <- dunn(dist_mat, clusters_complete)
# 3. Average Linkage
clusters_avg <- cutree(hclust_avg, 5)
ch_scores[3] <- cluster.stats(dist_mat, clusters_avg)$ch
dunn_scores[3] <- dunn(dist_mat, clusters_avg)
# 4. K-Means
set.seed(123)
clust <- kmeans(new_normalized_data, centers = 5, nstart = 20)
ch_scores[4] <- cluster.stats(dist_mat, clust$cluster)$ch
dunn_scores[4] <- dunn(dist_mat, clust$cluster)
# Membuat dataframe
results_df <- data.frame(
Method = c("Single Linkage", "Complete Linkage", "Average Linkage", "K-Means"),
Calinski_Harabasz = ch_scores,
Dunn = dunn_scores
)
# Menampilkan dataframe
results_df
## Method Calinski_Harabasz Dunn
## 1 Single Linkage 5.369267 0.3571330
## 2 Complete Linkage 17.574473 0.3625070
## 3 Average Linkage 12.290364 0.2642953
## 4 K-Means 20.750582 0.2351658
Berdasarkan Calinski-Harabasz, model K-Means menjadi model clustering terbaik. Sedangkan berdasarkan Dunn, model Complete Linkage menjadi yang terbaik. Dalam hal ini keduanya bisa dipilih sesuai kebutuhan. Untuk analisis selanjutnya, kita akan memilih hasil pengelompokkan dari Complete Linkage.
Melihat rentang setiap fasilitas untuk mengidentifikasi rentang “tinggi”, “sedang”, “rendang” jumlah fasilitasnya di setiap kab/kota.
data_with_clusters_comp
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## Bogor 639 1788 348 25 101 4804 153
## Sukabumi 311 1205 147 7 58 3451 54
## Cianjur 268 1254 164 3 45 2896 6
## Bandung 302 1431 130 7 62 4198 131
## Garut 339 1583 159 6 65 3963 96
## Tasikmalaya 240 1090 116 1 40 2278 29
## Ciamis 106 751 57 4 37 1586 45
## Kuningan 94 650 41 7 37 1417 13
## Cirebon 183 923 103 10 57 2591 28
## Majalengka 103 668 52 3 32 1461 24
## Sumedang 101 612 76 2 32 1644 78
## Indramayu 193 892 116 6 49 2311 20
## Subang 151 872 102 7 40 1836 80
## Purwakarta 165 429 55 11 20 1010 77
## Karawang 145 890 97 20 50 2271 187
## Bekasi 304 917 178 44 39 2457 240
## Bandung Barat 151 704 91 6 31 2209 64
## Pangandaran 47 295 24 1 15 520 11
## Kota Bogor 120 223 98 17 24 965 94
## Kota Sukabumi 41 104 32 6 15 447 22
## Kota Bandung 234 634 132 33 73 1973 118
## Kota Cirebon 43 134 29 11 22 330 31
## Kota Bekasi 254 441 143 38 31 1546 0
## Kota Depok 206 275 134 20 32 1003 113
## Kota Cimahi 36 101 24 7 13 398 33
## Kota Tasikmalaya 69 208 50 13 20 840 35
## Kota Banjar 22 82 14 3 10 199 18
## Cluster
## Bogor 1
## Sukabumi 2
## Cianjur 2
## Bandung 2
## Garut 2
## Tasikmalaya 2
## Ciamis 3
## Kuningan 3
## Cirebon 2
## Majalengka 3
## Sumedang 3
## Indramayu 2
## Subang 3
## Purwakarta 3
## Karawang 4
## Bekasi 4
## Bandung Barat 3
## Pangandaran 3
## Kota Bogor 3
## Kota Sukabumi 3
## Kota Bandung 4
## Kota Cirebon 3
## Kota Bekasi 5
## Kota Depok 3
## Kota Cimahi 3
## Kota Tasikmalaya 3
## Kota Banjar 3
df <- data_with_clusters_comp
# Mengubah row names menjadi kolom "Kab/Kota"
df <- cbind("Kab/Kota" = row.names(df), df)
# Memilih semua kolom kecuali "Kab/Kota" dan kolom terakhir
kolom_dipilih <- df[, 2:(ncol(df)-1)]
# Fungsi untuk klasifikasi berdasarkan persentil
klasifikasi_persentil <- function(kolom) {
# Menghitung persentil 25 dan 75
persentil25 <- quantile(kolom, probs = 0.25, na.rm = TRUE)
persentil75 <- quantile(kolom, probs = 0.75, na.rm = TRUE)
# Mengklasifikasikan nilai
cut(kolom,
breaks = c(-Inf, persentil25, persentil75, Inf),
labels = c("rendah", "sedang", "tinggi"),
include.lowest = TRUE)
}
# Mengklasifikasikan semua kolom numerik yang dipilih
df_kategorisasi <- lapply(kolom_dipilih, klasifikasi_persentil)
# Menggabungkan kembali ke dataframe asli, mengganti kolom numerik yang asli dengan hasil klasifikasi
# Menyertakan kolom "Kab/Kota" dan kolom terakhir yang tidak diubah
df <- cbind(df["Kab/Kota"], df_kategorisasi, df[ncol(df)])
# Menampilkan hasil
df
## Kab/Kota JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas
## Bogor Bogor tinggi tinggi tinggi tinggi tinggi
## Sukabumi Sukabumi tinggi tinggi tinggi sedang tinggi
## Cianjur Cianjur tinggi tinggi tinggi rendah sedang
## Bandung Bandung tinggi tinggi sedang sedang tinggi
## Garut Garut tinggi tinggi tinggi sedang tinggi
## Tasikmalaya Tasikmalaya sedang tinggi sedang rendah sedang
## Ciamis Ciamis sedang sedang sedang rendah sedang
## Kuningan Kuningan rendah sedang rendah sedang sedang
## Cirebon Cirebon sedang tinggi sedang sedang tinggi
## Majalengka Majalengka sedang sedang sedang rendah sedang
## Sumedang Sumedang sedang sedang sedang rendah sedang
## Indramayu Indramayu sedang sedang sedang sedang sedang
## Subang Subang sedang sedang sedang sedang sedang
## Purwakarta Purwakarta sedang sedang sedang sedang rendah
## Karawang Karawang sedang sedang sedang tinggi tinggi
## Bekasi Bekasi tinggi sedang tinggi tinggi sedang
## Bandung Barat Bandung Barat sedang sedang sedang sedang sedang
## Pangandaran Pangandaran rendah sedang rendah rendah rendah
## Kota Bogor Kota Bogor sedang rendah sedang tinggi sedang
## Kota Sukabumi Kota Sukabumi rendah rendah rendah sedang rendah
## Kota Bandung Kota Bandung sedang sedang sedang tinggi tinggi
## Kota Cirebon Kota Cirebon rendah rendah rendah sedang rendah
## Kota Bekasi Kota Bekasi tinggi sedang tinggi tinggi sedang
## Kota Depok Kota Depok sedang rendah tinggi tinggi sedang
## Kota Cimahi Kota Cimahi rendah rendah rendah sedang rendah
## Kota Tasikmalaya Kota Tasikmalaya rendah rendah rendah sedang rendah
## Kota Banjar Kota Banjar rendah rendah rendah rendah rendah
## JmlPosyandu JmlKlinik Cluster
## Bogor tinggi tinggi 1
## Sukabumi tinggi sedang 2
## Cianjur tinggi rendah 2
## Bandung tinggi tinggi 2
## Garut tinggi tinggi 2
## Tasikmalaya sedang sedang 2
## Ciamis sedang sedang 3
## Kuningan sedang rendah 3
## Cirebon tinggi sedang 2
## Majalengka sedang sedang 3
## Sumedang sedang sedang 3
## Indramayu sedang rendah 2
## Subang sedang sedang 3
## Purwakarta sedang sedang 3
## Karawang sedang tinggi 4
## Bekasi tinggi tinggi 4
## Bandung Barat sedang sedang 3
## Pangandaran rendah rendah 3
## Kota Bogor rendah sedang 3
## Kota Sukabumi rendah rendah 3
## Kota Bandung sedang tinggi 4
## Kota Cirebon rendah sedang 3
## Kota Bekasi sedang rendah 5
## Kota Depok sedang tinggi 3
## Kota Cimahi rendah sedang 3
## Kota Tasikmalaya rendah sedang 3
## Kota Banjar rendah rendah 3
Setelah itu, melihat summary klasifikasi setiap klaster.
# Mengelompokkan dataframe berdasarkan klaster
list_df_by_klaster <- split(df, df$Cluster)
# Fungsi untuk membuat summary per klaster
create_summary <- function(df) {
# Membuat summary untuk setiap kolom kecuali 'Kab/Kota' dan 'klaster'
summary_list <- lapply(df[,2:(ncol(df)-1)], function(kolom) {
summary(kolom)
})
# Mengembalikan summary dalam bentuk dataframe
summary_df <- do.call(cbind, summary_list)
return(summary_df)
}
# Menerapkan fungsi summary ke setiap klaster
summary_per_klaster <- lapply(list_df_by_klaster, create_summary)
# Menampilkan summary untuk setiap klaster (opsional)
summary_per_klaster
## $`1`
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## rendah 0 0 0 0 0 0 0
## sedang 0 0 0 0 0 0 0
## tinggi 1 1 1 1 1 1 1
##
## $`2`
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## rendah 0 0 0 2 0 0 2
## sedang 3 1 4 5 3 2 3
## tinggi 4 6 3 0 4 5 2
##
## $`3`
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## rendah 7 7 7 5 7 7 4
## sedang 8 8 7 8 8 8 10
## tinggi 0 0 1 2 0 0 1
##
## $`4`
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## rendah 0 0 0 0 0 0 0
## sedang 2 3 2 0 1 2 0
## tinggi 1 0 1 3 2 1 3
##
## $`5`
## JmlSMP JmlSD JmlSMA JmlRS JmlPuskesmas JmlPosyandu JmlKlinik
## rendah 0 0 0 0 0 0 1
## sedang 0 1 0 0 1 1 0
## tinggi 1 0 1 1 0 0 0
Berikut ini adalah fasilitas yang masih dibutuhkan dalam masing-masing klaster karena kategorinya masih ‘rendah’:
Klaster 1: Tidak ada fasilitas yang masuk kategori ‘rendah’, yang berarti semua fasilitas sudah cukup atau melebihi kebutuhan di klaster ini.
Klaster 2:
Klaster 3 (Semua fasilitas di klaster ini memiliki jumlah ‘rendah’, yang berarti semua fasilitas ini masih dibutuhkan):
Klaster 4: Tidak ada fasilitas yang masuk kategori ‘rendah’, yang berarti semua fasilitas sudah cukup atau melebihi kebutuhan di klaster ini.
Klaster 5:
Dari hasil di atas kita bisa mengetahui fasilitas apa saja yang perlu dikembangkan untuk setiap klasternya.