library(dplyr) # Untuk manipulasi data tabular (select, filter, mutate)
##
## 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
library(ggplot2) # Untuk visualisasi grafis (scatter plot)
library(tidyr) # Untuk merapikan data
library(caret) # Untuk proses preprocessing (seperti dummy variables)
## Warning: package 'caret' was built under R version 4.5.3
## Loading required package: lattice
# Memuat library untuk algoritma clustering
library(flexclust) # Berisi fungsi kcca() yang akan kita gunakan untuk K-Medians
## Warning: package 'flexclust' was built under R version 4.5.3
library(cluster) # Untuk evaluasi silhouette score
df_kos <- read.csv("dataset_kos_final.csv", stringsAsFactors = FALSE)
str(df_kos)
## 'data.frame': 2485 obs. of 12 variables:
## $ harga : num 950000 1100000 1100000 700000 1500000 2200000 1350000 3100000 700000 3500000 ...
## $ deposit : num 0e+00 0e+00 0e+00 0e+00 5e+05 5e+05 0e+00 1e+06 0e+00 1e+06 ...
## $ luas_m2 : num 12 12 9 12 6 9 16 12 9 15 ...
## $ rating : num 0 0 0 0 1 4.8 0 5 4.1 4 ...
## $ transaksi : num 0 0 0 0 0 0 0 0 0 22 ...
## $ region : chr "Bogor" "Depok" "Tangerang Selatan" "Bogor" ...
## $ tipe_kos : chr "Kos Campur" "Kos Putra" "Kos Putra" "Kos Campur" ...
## $ listrik : chr "Ya" "Tidak" "Tidak" "Ya" ...
## $ fasilitas_AC : chr "Tidak" "Ya" "Ya" "Tidak" ...
## $ fasilitas_WiFi : chr "Tidak" "Ya" "Ya" "Tidak" ...
## $ fasilitas_KMDalam: chr "Ya" "Ya" "Ya" "Ya" ...
## $ fasilitas_Parkir : chr "Ya" "Ya" "Ya" "Ya" ...
head(df_kos)
# One-Hot Encoding untuk Kolom Kategorikal
dummy_model <- dummyVars(" ~ .", data = df_kos)
df_dummy <- data.frame(predict(dummy_model, newdata = df_kos))
# Standarisasi Kolom Numerikal (Z-score scaling)
df_scaled <- df_dummy
kolom_numerik <- c("harga", "deposit", "luas_m2", "rating", "transaksi")
df_scaled[kolom_numerik] <- scale(df_scaled[kolom_numerik])
summary(df_scaled[kolom_numerik])
## harga deposit luas_m2 rating
## Min. :-1.5650 Min. :-0.7838 Min. :-0.23922 Min. :-1.5263
## 1st Qu.:-0.6554 1st Qu.:-0.7838 1st Qu.:-0.08387 1st Qu.:-1.5263
## Median :-0.1883 Median :-0.1698 Median :-0.05072 Median : 0.6027
## Mean : 0.0000 Mean : 0.0000 Mean : 0.00000 Mean : 0.0000
## 3rd Qu.: 0.4605 3rd Qu.: 0.1372 3rd Qu.:-0.02173 3rd Qu.: 0.7416
## Max. :13.8254 Max. : 9.6546 Max. :37.01539 Max. : 0.7879
## transaksi
## Min. :-0.47841
## 1st Qu.:-0.47841
## Median :-0.39438
## Mean : 0.00000
## 3rd Qu.: 0.02577
## Max. : 9.81524
k_values <- 2:10
wss_values <- numeric(length(k_values))
set.seed(123)
for (j in 1:length(k_values)) {
k_current <- k_values[j]
model_kmed <- kcca(df_scaled, k = k_current, family = kccaFamily("kmedians"))
info_jarak <- info(model_kmed, "dists")
wss_values[j] <- sum(info_jarak^2)
}
plot(k_values, wss_values,
type = "b",
pch = 19,
col = "blue",
frame = FALSE,
xlab = "Jumlah Cluster (K)",
ylab = "Total Within-Cluster Jarak Kuadrat",
main = "Metode Elbow untuk Menentukan K Optimal",
xaxt = "n")
axis(1, at = k_values)
abline(v = 3, col = "red", lty = 2, lwd = 2)
set.seed(123)
k_optimal <- 3
kmed_final <- kcca(df_scaled, k = k_optimal, family = kccaFamily("kmedians"))
label_cluster <- clusters(kmed_final)
df_kos$Cluster <- as.factor(label_cluster)
cat("Jumlah data pada masing-masing Cluster:\n")
## Jumlah data pada masing-masing Cluster:
table(df_kos$Cluster)
##
## 1 2 3
## 967 277 1241
pca_result <- prcomp(df_scaled, center = TRUE, scale. = FALSE)
df_pca <- data.frame(
PC1 = pca_result$x[, 1],
PC2 = pca_result$x[, 2]
)
df_pca$Cluster <- as.factor(label_cluster)
ggplot(df_pca, aes(x = PC1, y = PC2, color = Cluster)) +
geom_point(alpha = 0.6, size = 2) + # alpha untuk transparansi titik
stat_ellipse(level = 0.95, linetype = 2) + # Menambahkan lingkaran (elips) batas cluster
theme_minimal() +
labs(
title = "Visualisasi Hasil Clustering K-Medians (Dimensi PCA)",
subtitle = paste("K =", k_optimal),
x = "Principal Component 1 (PC1)",
y = "Principal Component 2 (PC2)",
color = "Kelompok (Cluster)"
) +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
plot.subtitle = element_text(hjust = 0.5))
get_mode <- function(v) {
uniqv <- unique(v)
uniqv[which.max(tabulate(match(v, uniqv)))]
}
profil_numerik <- df_kos %>%
group_by(Cluster) %>%
summarise(
Jumlah_Kos = n(),
Median_Harga = median(harga, na.rm = TRUE),
Median_Deposit = median(deposit, na.rm = TRUE),
Median_Luas = median(luas_m2, na.rm = TRUE),
Median_Rating = median(rating, na.rm = TRUE),
Median_Transaksi = median(transaksi, na.rm = TRUE)
)
cat("--- Profil Numerik Tiap Cluster (Lengkap) ---\n")
## --- Profil Numerik Tiap Cluster (Lengkap) ---
print(profil_numerik)
## # A tibble: 3 × 7
## Cluster Jumlah_Kos Median_Harga Median_Deposit Median_Luas Median_Rating
## <fct> <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 967 1300000 150000 9.25 4.6
## 2 2 277 2545000 1000000 12 4.6
## 3 3 1241 1500000 200000 11 4.6
## # ℹ 1 more variable: Median_Transaksi <dbl>
profil_kategori <- df_kos %>%
group_by(Cluster) %>%
summarise(
Modus_Tipe_Kos = get_mode(tipe_kos),
Modus_Region = get_mode(region),
Modus_Listrik = get_mode(listrik),
Modus_AC = get_mode(fasilitas_AC),
Modus_WiFi = get_mode(fasilitas_WiFi),
Modus_KMDalam = get_mode(fasilitas_KMDalam),
Modus_Parkir = get_mode(fasilitas_Parkir)
)
cat("\n--- Profil Kategori/Fasilitas Tiap Cluster (Lengkap) ---\n")
##
## --- Profil Kategori/Fasilitas Tiap Cluster (Lengkap) ---
print(profil_kategori)
## # A tibble: 3 × 8
## Cluster Modus_Tipe_Kos Modus_Region Modus_Listrik Modus_AC Modus_WiFi
## <fct> <chr> <chr> <chr> <chr> <chr>
## 1 1 Kos Putri Depok Tidak Ya Ya
## 2 2 Kos Campur Jakarta Barat Tidak Ya Ya
## 3 3 Kos Campur Bekasi Tidak Ya Ya
## # ℹ 2 more variables: Modus_KMDalam <chr>, Modus_Parkir <chr>
Berdasarkan hasil pemodelan clustering K-Medians, pasar properti kos di dataset ini terbagi menjadi tiga segmen utama dengan karakteristik spesifik:
Fakta Data: Ini adalah segmen dengan harga sewa paling murah (Rp 1.300.000) dan luas kamar paling mungil (9.25 m2). Uang depositnya pun sangat ringan (Rp 150.000). Secara kategorikal, kos di segmen ini didominasi oleh tipe Kos Putri dan berlokasi di Depok.
Interpretasi & Persona: Mengingat Depok adalah salah satu pusat pendidikan (kampus besar seperti UI dan Gunadarma), kos dengan spesifikasi ini sangat menyasar mahasiswi yang mencari kepraktisan. Kamar tidak perlu terlalu luas, yang penting harganya terjangkau, aman (khusus putri), dan fasilitas dasarnya sudah modern (AC & WiFi).
Strategi Bisnis / Rekomendasi: Untuk kos tipe ini, promosi paling efektif dilakukan menjelang tahun ajaran baru perguruan tinggi. Karena depositnya murah, ini adalah daya tarik besar bagi kantong mahasiswa.
Fakta Data: Ini adalah populasi terbesar di dataset (1.241 kos). Harganya berada di titik tengah (Rp 1.500.000) dengan ukuran kamar yang sangat pas (11 m2) dan deposit wajar (Rp 200.000). Yang paling menarik, tingkat transaksinya adalah yang tertinggi (3). Tipe kos didominasi Kos Campur di wilayah Bekasi.
Interpretasi & Persona: Ini adalah kos tipe “Sweet Spot” alias yang paling dicari pasar. Penghuninya kemungkinan besar adalah pekerja kerah putih muda (first-jobber) kaum komuter yang bekerja di Jakarta tapi indekos di daerah satelit seperti Bekasi untuk menekan biaya hidup, namun tetap menginginkan privasi dan kenyamanan ruang yang pas.
Strategi Bisnis / Rekomendasi: Kos di segmen ini adalah pendorong pendapatan utama (cash cow) karena tingkat transaksinya tinggi (cepat penuh / laku). Pemilik kos atau platform bisa memberikan fitur booking cepat atau layanan ekstra (seperti layanan pembersihan) karena segmen pekerja biasanya rela membayar sedikit lebih mahal untuk kenyamanan.