Rumah adalah salah satu bangunan yang memiliki lantai, dinding dan atap yang berfungsi sebagai tempat tinggal oleh individu, sekumpulan individu maupun keluarga sehingga mampu memberikan kenyamanan dan perlindungan bagi penghuninya dari berbagai ancaman sosial dan gangguan alam seperti penyakit dan bencana alam. Perumahan yang layak merupakan salah satu kebutuhan esensial bagi setiap orang yang pemenuhannya dijamin oleh UUD 1945 pasal 28 H ayat 1 bahwa setiap orang berhak hidup sejahtera lahir dan batin, bertempat tinggal, dan mendapatkan lingkungan hidup yang baik dan sehat serta berhak memperoleh pelayanan kesehatan. Menurut Badan Pusat Statistik, sejak tahun 2019 rumah tangga diklasifikasikan memiliki akses terhadap hunian/rumah layak huni apabila memenuhi 4 (empat) kriteria, yaitu:
kecukupan luas tempat tinggal minimal 7,2 m2 per kapita (sufficient living space)
memiliki akses terhadap air minum layak
memiliki akses terhadap sanitasi layak
ketahanan bangunan (durable housing), yaitu atap terluas berupa beton/ genteng/ seng/ kayu/ sirap; dinding terluas berupa tembok/ plesteran anyaman bambu/kawat, kayu/papan dan batang kayu; dan lantai terluas berupa marmer/ granit/ keramik/ parket/vinil/karpet/ ubin/tegel/teraso/ kayu/papan/ semen/bata merah.
Untuk melakukan analisis, beberapa packages yang digunakan adalah sebagai berikut:
# Import library untuk data wrangling
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.2 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.2 ✔ tibble 3.2.1
## ✔ lubridate 1.9.2 ✔ tidyr 1.3.0
## ✔ purrr 1.0.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
# Import library untuk visualisasi
library(factoextra) # Visualisasi hasil clustering
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(gridExtra) # Visualisasi karakteristik cluster
##
## Attaching package: 'gridExtra'
##
## The following object is masked from 'package:dplyr':
##
## combine
library(GGally) # Correlation matrix
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
library(ggiraphExtra)
library(sf) # Read data map
## Linking to GEOS 3.11.2, GDAL 3.6.2, PROJ 9.2.0; sf_use_s2() is TRUE
library(plotly) # Interactive Plotting
##
## Attaching package: 'plotly'
##
## The following object is masked from 'package:ggplot2':
##
## last_plot
##
## The following object is masked from 'package:stats':
##
## filter
##
## The following object is masked from 'package:graphics':
##
## layout
library(Rtsne)
# Machine Learning - Clustering
library(cluster)
library(factoextra)
library(mvnTest)
## Loading required package: mvtnorm
Data pada penelitian ini merupakan data Sekunder, yang berisikan informasi mengenai indikator rumah layak huni. Data yang digunakan diperoleh dari situs Badan Pusat Statistik (https://www.bps.go.id/) tahun 2022.
#Input data
data = rio::import("https://raw.githubusercontent.com/yoginurhamid/TPG/main/Data/Data%20TPG%20Rumah%20tidak%20layak%20huni.csv")
#Cek struktur data
glimpse(data)
## Rows: 35
## Columns: 5
## $ Provinsi <chr> …
## $ `Persentase Rumah Tangga menurut Provinsi, Tipe Daerah dan Luas Hunian per kapita <= 7,2 m2 (Persen)` <dbl> …
## $ `Persentase Rumah Tangga menurut Provinsi dan Sumber Air Minum Layak (Persen)` <dbl> …
## $ `Proporsi Rumah Tangga Yang Memiliki Akses Terhadap Layanan Sanitasi Layak (Persen)` <dbl> …
## $ `Persentase Rumah Tangga yang Menempati Rumah dengan Ketahanan Bangunan (Atap, Lantai, Dinding) Memenuhi Syarat menurut Provinsi dan Tipe Daerah (Persen)` <dbl> …
Dibagian ini variabel data akan disesuaikan tipe datanya, kemudian
agar memudahkan dalam kodingan tiap variabel akan diganti menjadi X1,
X2, dst, dan untuk variabel provinsi akan dijadikan sebagai
rowname atau nama dari tiap barisnya.
#Meng-assign nilai dari kolom Provinsi menjadi rownames
#rownames(data) = data$Provinsi
#Membuang peubah provinsi dan amatan Indonesia
indikator = data[-35,-1]
#Mengubah nama kolom
colnames(indikator)
## [1] "Persentase Rumah Tangga menurut Provinsi, Tipe Daerah dan Luas Hunian per kapita <= 7,2 m2 (Persen)"
## [2] "Persentase Rumah Tangga menurut Provinsi dan Sumber Air Minum Layak (Persen)"
## [3] "Proporsi Rumah Tangga Yang Memiliki Akses Terhadap Layanan Sanitasi Layak (Persen)"
## [4] "Persentase Rumah Tangga yang Menempati Rumah dengan Ketahanan Bangunan (Atap, Lantai, Dinding) Memenuhi Syarat menurut Provinsi dan Tipe Daerah (Persen)"
names(indikator)[names(indikator)==c("Persentase Rumah Tangga menurut Provinsi, Tipe Daerah dan Luas Hunian per kapita <= 7,2 m2 (Persen)","Persentase Rumah Tangga menurut Provinsi dan Sumber Air Minum Layak (Persen)","Proporsi Rumah Tangga Yang Memiliki Akses Terhadap Layanan Sanitasi Layak (Persen)","Persentase Rumah Tangga yang Menempati Rumah dengan Ketahanan Bangunan (Atap, Lantai, Dinding) Memenuhi Syarat menurut Provinsi dan Tipe Daerah (Persen)")] = c("x1","x2","x3","x4")
#cek data
str(indikator)
## 'data.frame': 34 obs. of 4 variables:
## $ x1: num 7.47 8.79 6.39 7.56 3.9 ...
## $ x2: num 89.7 92.1 85.2 90.1 79.2 ...
## $ x3: num 77.5 82.3 69.3 84.1 79.5 ...
## $ x4: num 93.3 89.3 97.4 94.2 95.2 ...
Keterangan:
x1 = Persentase rumah tangga menurut provinsi, tipe daerah dan luas hunian per kapita <= 7,2 m2 (persen)
x2 = Persentase Rumah Tangga menurut Provinsi dan Sumber Air Minum Layak (Persen)
x3 = Proporsi Rumah Tangga Yang Memiliki Akses Terhadap Layanan Sanitasi Layak (Persen)
x4 = Persentase Rumah Tangga yang Menempati Rumah dengan Ketahanan Bangunan (Atap, Lantai, Dinding) Memenuhi Syarat menurut Provinsi dan Tipe Daerah (Persen)
indikator %>%
is.na() %>%
colSums()
## x1 x2 x3 x4
## 0 0 0 0
Tidak terdapat missng value atau dapat dikatakan bahwa data sudah lengkap dan dapat dilanjutkan ke proses analisis.
summary(indikator)
## x1 x2 x3 x4
## Min. : 2.030 Min. :65.39 Min. :40.34 Min. :42.02
## 1st Qu.: 6.300 1st Qu.:81.58 1st Qu.:77.43 1st Qu.:84.26
## Median : 7.515 Median :89.83 Median :81.67 Median :90.98
## Mean : 8.745 Mean :87.64 Mean :81.00 Mean :85.44
## 3rd Qu.:10.332 3rd Qu.:93.25 3rd Qu.:84.93 3rd Qu.:94.03
## Max. :29.740 Max. :98.42 Max. :96.21 Max. :97.91
Dari informasi diatas dapat diketahui bahwa tiap provinsi memiliki karakteristik tersendiri, maka dari itu provinsi-provinsi akan diklasterkan berdasarkan kemiripan dari karakteristiknya.
#cek korelasi
ggcorr(indikator, label=TRUE)
Tidak terdapat korelasi yang tinggi antar peubah.
Terdapat beberapa peubah yang memiliki korelasi yang sedang yaitu 0.6 dan -0.6 sedangkan sisanya berkorelasi rendah.
Terdapat beberapa peubah yang tidak memiliki korelasi (nilai korelasi = 0), yaitu peubah x2 dan x3 dengan x4.
Peubah-peubah yang memiliki hubungan perlu diteliti terkait permasalahan multikolinearitas.
Pengujian multikolinearitas ini untuk melihat apakah ada variabel yang memberikan informasi yang sama dengan variabel lain atau biasa disebut redundan. Untuk menguji multikolinearitas akan dilihat dari nilai Variance Inflation Factor (VIF). Model dikatakan memiliki multikolinearitas jika nilai VIF > 10 yang mengindikasikan bahwa hasil estimasi yang kurang baik.
CekVIF <- function(data) {
corr = as.matrix(cor(data))
VIF = diag(solve(corr))
return(VIF)
}
CekVIF(indikator)
## x1 x2 x3 x4
## 2.006802 1.819638 2.837839 1.253604
Tidak terdapat multikolinearitas pada data yang digunakan sehingga dapat dilakukan analisis selanjutnya.
Outlier adalah pengamatan yang sangat menyimpang dari pengamatan lain sehingga, menimbulkan kecurigaan yang dihasilkan oleh mekanisme yang berbeda. Pengecekan outlier akan dilihat melalui visualisasi data dengan Boxplot.
# membagi jendela grafik menajdi 1 baris dan 4 kolom
par(mfrow=c(1,4))
# Looping Box-Plot
type <- c("x1", "x2", "x3", "x4")
for (i in type){
boxplot(indikator[,i],
main = paste("Peubah", i))
}
Pada peubah x1, x3, dan x4 terdapat outlier. Sedangkan peubah x2 tidak memuat outlier.
Dalam beberapa penelitian outlier diperlakukan dengan cara dibuang. Tapi memperlakukan outlier sebagai noise dapat mengakibatkan hilangnya informasi penting yang tersembunyi. Di banyak bidang, outlier lebih penting daripada data normal, karena dapat menunjukkan perilaku menyimpang atau awal dari pola baru.
Metode K-Means digunakan sebagai alternatif metode klaster untuk data dengan ukuran yang lebih besar. Hal ini dikarenakan metode ini memiliki kecepatan yang lebih tinggi jika dibandingkan dengan metode hirarki. Metode K-Means dapat digunakan untuk menjelaskan algoritma dalam penentuan suatu objek kedalam klaster tertentu berdasarkan rataan terdekat[4]. Dalam prosedur pembentukan K-Means Cluster terdapat langkah-langkah yang dapat dilakukan, antara lain:
Tentukan banyaknya klaster (k) yang akan dibentuk.
Random initialization: meletakkan k centroid secara random.
Cluster assignment: assign masing-masing observasi ke cluster terdekat berdasarkan perhitungan jarak.
Centroid update: menggeser centroid ke rata-rata (means) dari cluster yang terbentuk.
Ulangi langkah 3 dan 4 sampai tidak ada observasi yang clusternya berubah lagi.
Bertujuan untuk menyamakan skala data atau menghilangkan kontras antar variabel yang memiliki satuan berbeda.
indikator_scale = scale(indikator)
indikator_scale
## x1 x2 x3 x4
## 1 -0.237002449 0.26225821 -0.35943694 0.55516820
## 2 0.008308204 0.57162105 0.13315819 0.27183556
## 3 -0.437711165 -0.30681665 -1.19848385 0.83779778
## 4 -0.220276723 0.30936284 0.31302696 0.61774042
## 5 -0.900456260 -1.07576791 -0.14890873 0.68664017
## 6 0.331672246 -0.16422966 -0.24293104 0.32315884
## 7 -0.460012133 -1.85490396 -0.14482081 0.62477101
## 8 -1.160634225 -0.76895126 0.27112571 0.01803139
## 9 -0.917181987 -0.85042954 1.08666704 -3.05292882
## 10 -0.329923151 0.53215501 0.68911619 -1.73680302
## 11 2.349909891 1.31001796 1.20521690 -2.78295430
## 12 -0.170099544 0.68747298 -0.71304258 -0.57183483
## 13 -1.247979685 0.72311973 0.34470839 -0.10148858
## 14 -0.889305776 1.12796493 1.55473461 0.54110703
## 15 -0.900456260 0.94336571 0.01358634 -0.02907354
## 16 -0.774084106 0.64546075 0.42135701 -0.76869125
## 17 0.058485383 1.37239977 1.52714111 0.56149573
## 18 0.372557355 0.98792414 0.21696068 -0.25124008
## 19 1.101055658 -0.11203263 -0.74574599 -1.59548823
## 20 -0.539923937 -0.91790374 -0.36659082 0.82514272
## 21 -0.424702267 -1.35330330 -0.68136115 0.37659130
## 22 -0.398684470 -1.45897044 0.15870773 0.18887464
## 23 -0.372666674 -0.06365491 0.95380943 0.74780627
## 24 -0.049302631 0.29535876 0.12498234 0.87646601
## 25 -0.058594701 0.82878687 0.31200497 0.44830328
## 26 0.816718310 -0.11457883 -0.61186640 0.52142138
## 27 -0.400542884 0.54997839 1.14900791 0.03701397
## 28 -0.084612498 0.89116868 0.62064342 0.44970940
## 29 0.623443250 1.08467960 -0.12029325 0.79983261
## 30 0.184857537 -1.10250297 -0.21635952 0.29433344
## 31 0.840877693 0.56780176 -0.46265709 0.40260447
## 32 -0.342932049 0.05856251 -0.16423846 0.52001527
## 33 0.727514436 -0.77277056 -0.76414166 0.71124722
## 34 3.901685612 -2.83264331 -4.15507665 -1.34660547
## attr(,"scaled:center")
## x1 x2 x3 x4
## 8.745294 87.640000 80.997059 85.443529
## attr(,"scaled:scale")
## x1 x2 x3 x4
## 5.380932 7.854854 9.784912 14.223564
jarak <- get_dist(indikator)
fviz_dist(jarak, gradient = list(low="green", mid="white", high="purple"))
Menentukan jumlah klaster paling optimum untuk membagi 33 provinsi yang ada di Indonesia. Pada dasarnya nilai k optimum dapat ditentukan sendiri oleh peneliti, selain itu nilai k dapat ditentukan juga menggunakan bantuan grafik silhouette dan Elbow berikut.
###Silhouette
fviz_nbclust(x = indikator,
FUNcluster = kmeans,
method = 'silhouette',
k.max = 10)
# Menentukan jumlah klaster menggunakan metode silhouette
nbclust_result_silwidth <- fviz_nbclust(
x = indikator,
FUNcluster = kmeans,
method = 'silhouette',
k.max = 10,
verbose = FALSE # Matikan tampilan pesan tambahan
)
# Menampilkan nilai rata-rata silhouette pada grafik
sil_values_kmeans <- nbclust_result_silwidth$data
colnames(sil_values_kmeans) <- c("banyak_cluster","average_silwidth")
# Menampilkan grafikA
print(sil_values_kmeans)
## banyak_cluster average_silwidth
## 1 1 0.0000000
## 2 2 0.5795104
## 3 3 0.2686982
## 4 4 0.2103885
## 5 5 0.2902851
## 6 6 0.2829189
## 7 7 0.2802994
## 8 8 0.2148841
## 9 9 0.2397716
## 10 10 0.2324013
###Elbow
fviz_nbclust(x = indikator,
FUNcluster = kmeans,
method = 'wss',
k.max = 10)
# Menentukan jumlah klaster menggunakan metode elbow
nbclust_result_wss <- fviz_nbclust(
x = indikator,
FUNcluster = kmeans,
method = 'wss',
k.max = 10,
verbose = FALSE # Matikan tampilan pesan tambahan
)
# Menampilkan nilai wss pada grafik
wss_values_kmeans <- nbclust_result_wss$data
colnames(wss_values_kmeans) <- c("banyak_cluster","wss")
# Menampilkan grafikA
print(wss_values_kmeans)
## banyak_cluster wss
## 1 1 12827.346
## 2 2 7191.542
## 3 3 5756.010
## 4 4 3218.716
## 5 5 2578.630
## 6 6 2099.488
## 7 7 1651.640
## 8 8 1426.498
## 9 9 1715.396
## 10 10 1212.834
###Hiearchical Clustering
hc <- hclust(dist(indikator), method = "ward.D2")
# Contoh 2
#define linkage methods
m <- c( "average", "single", "complete", "ward")
names(m) <- c( "average", "single", "complete", "ward")
#function to compute agglomerative coefficient
ac <- function(x) {
agnes(indikator, method = x)$ac
}
#calculate agglomerative coefficient for each clustering linkage method
sapply(m, ac)
## average single complete ward
## 0.8348189 0.8046854 0.8613107 0.9031934
clust <- agnes(indikator, method = "ward")
clust
## Call: agnes(x = indikator, method = "ward")
## Agglomerative coefficient: 0.9031934
## Order of objects:
## [1] 1 32 4 24 2 25 28 29 3 33 6 26 31 5 20 7 21 22 30 8 12 13 15 18 16
## [26] 14 17 23 27 9 11 10 19 34
## Height (summary):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.604 5.781 11.323 18.009 16.913 106.168
##
## Available components:
## [1] "order" "height" "ac" "merge" "diss" "call"
## [7] "method" "order.lab" "data"
#produce dendrogram
pltree(clust, cex = 0.6, hang = -1, main = "Dendrogram")
#compute distance matrix
d <- dist(indikator, method = "euclidean")
#perform hierarchical clustering using Ward's method
final_clust <- hclust(d, method = "ward.D2" )
#cut the dendrogram into 2 clusters
groups <- cutree(final_clust, k=2)
#find number of observations in each cluster
table(groups)
## groups
## 1 2
## 29 5
#append cluster labels to original data
final_data <- cbind(data[-35,1], cluster = groups)
final_data
## cluster
## 1 "ACEH" "1"
## 2 "SUMATERA UTARA" "1"
## 3 "SUMATERA BARAT" "1"
## 4 "RIAU" "1"
## 5 "JAMBI" "1"
## 6 "SUMATERA SELATAN" "1"
## 7 "BENGKULU" "1"
## 8 "LAMPUNG" "1"
## 9 "KEP. BANGKA BELITUNG" "2"
## 10 "KEP. RIAU" "2"
## 11 "DKI JAKARTA" "2"
## 12 "JAWA BARAT" "1"
## 13 "JAWA TENGAH" "1"
## 14 "DI YOGYAKARTA" "1"
## 15 "JAWA TIMUR" "1"
## 16 "BANTEN" "1"
## 17 "BALI" "1"
## 18 "NUSA TENGGARA BARAT" "1"
## 19 "NUSA TENGGARA TIMUR" "2"
## 20 "KALIMANTAN BARAT" "1"
## 21 "KALIMANTAN TENGAH" "1"
## 22 "KALIMANTAN SELATAN" "1"
## 23 "KALIMANTAN TIMUR" "1"
## 24 "KALIMANTAN UTARA" "1"
## 25 "SULAWESI UTARA" "1"
## 26 "SULAWESI TENGAH" "1"
## 27 "SULAWESI SELATAN" "1"
## 28 "SULAWESI TENGGARA" "1"
## 29 "GORONTALO" "1"
## 30 "SULAWESI BARAT" "1"
## 31 "MALUKU" "1"
## 32 "MALUKU UTARA" "1"
## 33 "PAPUA BARAT" "1"
## 34 "PAPUA" "2"
knitr::kable(
cbind(c("1","2","3","4","5","6","7","8","9","10"),
sil_values_kmeans$average_silwidth,wss_values_kmeans$wss),
col.names=c("banyak_cluster","average_silwidth","elbow")
)
| banyak_cluster | average_silwidth | elbow |
|---|---|---|
| 1 | 0 | 12827.3457294118 |
| 2 | 0.57951036798724 | 7191.54159034483 |
| 3 | 0.268698157006044 | 5756.010475 |
| 4 | 0.210388486120705 | 3218.71626442308 |
| 5 | 0.29028508353269 | 2578.62985714286 |
| 6 | 0.282918933365156 | 2099.48768303419 |
| 7 | 0.280299406942361 | 1651.63978111111 |
| 8 | 0.214884063825177 | 1426.49840730159 |
| 9 | 0.23977161571419 | 1715.39552642857 |
| 10 | 0.232401255565058 | 1212.83400976191 |
Berdasarkan grafik dapat diperoleh nilai k optimum adalah 2.
clus<-kmeans(indikator,2)
clus
## K-means clustering with 2 clusters of sizes 29, 5
##
## Cluster means:
## x1 x2 x3 x4
## 1 7.612414 88.16897 81.64483 90.60069
## 2 15.316000 84.57200 77.24000 55.53200
##
## Clustering vector:
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
## 1 1 1 1 1 1 1 1 2 2 2 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1
## 27 28 29 30 31 32 33 34
## 1 1 1 1 1 1 1 2
##
## Within cluster sum of squares by cluster:
## [1] 3723.037 3468.504
## (between_SS / total_SS = 43.9 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss" "tot.withinss"
## [6] "betweenss" "size" "iter" "ifault"
fviz_cluster(clus,indikator) + theme_classic()
fviz_cluster(object = clus, data = indikator, palette = "jco", ggtheme = theme_minimal())
clusplot(indikator,clus$cluster,color=T,shade=T)
tabel.clus<-data.frame(data[-35,1],clus$cluster)
tabel.clus
## data..35..1. clus.cluster
## 1 ACEH 1
## 2 SUMATERA UTARA 1
## 3 SUMATERA BARAT 1
## 4 RIAU 1
## 5 JAMBI 1
## 6 SUMATERA SELATAN 1
## 7 BENGKULU 1
## 8 LAMPUNG 1
## 9 KEP. BANGKA BELITUNG 2
## 10 KEP. RIAU 2
## 11 DKI JAKARTA 2
## 12 JAWA BARAT 1
## 13 JAWA TENGAH 1
## 14 DI YOGYAKARTA 1
## 15 JAWA TIMUR 1
## 16 BANTEN 1
## 17 BALI 1
## 18 NUSA TENGGARA BARAT 1
## 19 NUSA TENGGARA TIMUR 2
## 20 KALIMANTAN BARAT 1
## 21 KALIMANTAN TENGAH 1
## 22 KALIMANTAN SELATAN 1
## 23 KALIMANTAN TIMUR 1
## 24 KALIMANTAN UTARA 1
## 25 SULAWESI UTARA 1
## 26 SULAWESI TENGAH 1
## 27 SULAWESI SELATAN 1
## 28 SULAWESI TENGGARA 1
## 29 GORONTALO 1
## 30 SULAWESI BARAT 1
## 31 MALUKU 1
## 32 MALUKU UTARA 1
## 33 PAPUA BARAT 1
## 34 PAPUA 2
indikator%>%
mutate(cluster=clus$cluster)%>%
group_by(cluster)%>%
summarise_all("mean")
## # A tibble: 2 × 5
## cluster x1 x2 x3 x4
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 7.61 88.2 81.6 90.6
## 2 2 15.3 84.6 77.2 55.5