1 Pendahuluan

Dataset yang digunakan adalah AmesHousing, yaitu data penjualan rumah di Kota Ames, Iowa, yang dikumpulkan oleh Dean De Cock (2011) sebagai alternatif modern dari dataset Boston Housing.

Berbeda dengan dataset bawaan R pada umumnya (iris, mtcars, airquality) yang dapat langsung dipanggil dengan data(), package AmesHousing tidak menyediakan objek siap pakai bernama ames. Package ini menyediakan fungsi make_ames() yang akan membangkitkan versi data yang sudah dibersihkan (cleaned) dan siap dianalisis. Oleh karena itu, dataset diperoleh melalui:

ames <- AmesHousing::make_ames()

bukan melalui data(ames).

Dataset asli (ames_raw) memiliki 2.930 observasi dan 82 variabel dengan banyak missing value (misalnya pada kolom Pool QC, Alley, Fireplace Qu). Namun versi make_ames() yang dipakai pada mini project ini sudah melalui proses cleaning, sehingga jumlah variabel menjadi 81 (kolom Order dan PID dihapus) dan praktis tidak memiliki missing value karena nilai NA pada variabel kategorik sudah dikodekan ulang menjadi level eksplisit (misalnya "No_Pool", "No_Alley_Access", "No_Garage").

2 Exploratory Data Analysis (EDA)

2.1 Memuat Dataset

install.packages("AmesHousing")
install.packages("tidyverse")
install.packages("caret")
install.packages("corrplot")
install.packages("rpart")
install.packages("rpart.plot")
install.packages("cluster")
install.packages("factoextra")

3 Load Library

library(AmesHousing)
library(tidyverse)
library(caret)
library(corrplot)
library(rpart)
library(rpart.plot)
library(cluster)
library(factoextra)
# install.packages("AmesHousing")
library(AmesHousing)
library(dplyr)
library(ggplot2)
library(corrplot)
library(rpart)
library(rpart.plot)
library(cluster)
library(factoextra)
library(caret)
library(gridExtra)
library(scales)

set.seed(123)

ames <- make_ames()
ames <- as.data.frame(ames)

dim(ames)
## [1] 2930   81

3.1 Memahami Struktur Data

str(ames[, 1:15])
## 'data.frame':    2930 obs. of  15 variables:
##  $ MS_SubClass : Factor w/ 16 levels "One_Story_1946_and_Newer_All_Styles",..: 1 1 1 1 6 6 12 12 12 6 ...
##  $ MS_Zoning   : Factor w/ 7 levels "Floating_Village_Residential",..: 3 2 3 3 3 3 3 3 3 3 ...
##  $ Lot_Frontage: num  141 80 81 93 74 78 41 43 39 60 ...
##  $ Lot_Area    : int  31770 11622 14267 11160 13830 9978 4920 5005 5389 7500 ...
##  $ Street      : Factor w/ 2 levels "Grvl","Pave": 2 2 2 2 2 2 2 2 2 2 ...
##  $ Alley       : Factor w/ 3 levels "Gravel","No_Alley_Access",..: 2 2 2 2 2 2 2 2 2 2 ...
##  $ Lot_Shape   : Factor w/ 4 levels "Regular","Slightly_Irregular",..: 2 1 2 1 2 2 1 2 2 1 ...
##  $ Land_Contour: Factor w/ 4 levels "Bnk","HLS","Low",..: 4 4 4 4 4 4 4 2 4 4 ...
##  $ Utilities   : Factor w/ 3 levels "AllPub","NoSeWa",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ Lot_Config  : Factor w/ 5 levels "Corner","CulDSac",..: 1 5 1 1 5 5 5 5 5 5 ...
##  $ Land_Slope  : Factor w/ 3 levels "Gtl","Mod","Sev": 1 1 1 1 1 1 1 1 1 1 ...
##  $ Neighborhood: Factor w/ 29 levels "North_Ames","College_Creek",..: 1 1 1 1 7 7 17 17 17 7 ...
##  $ Condition_1 : Factor w/ 9 levels "Artery","Feedr",..: 3 2 3 3 3 3 3 3 3 3 ...
##  $ Condition_2 : Factor w/ 8 levels "Artery","Feedr",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ Bldg_Type   : Factor w/ 5 levels "OneFam","TwoFmCon",..: 1 1 1 1 1 1 5 5 5 1 ...
# Ringkasan tipe data pada seluruh kolom
table(sapply(ames, class))
## 
##  factor integer numeric 
##      46      23      12

Interpretasi: Dataset terdiri dari 81 variabel, gabungan antara variabel numerik (luas bangunan, jumlah kamar, tahun dibangun, dll.) dan variabel kategorik/faktor (zona, tipe bangunan, kualitas material, lingkungan/Neighborhood, dll.). Variabel target untuk prediksi adalah Sale_Price.

3.2 Missing Value Analysis

na_count <- sapply(ames, function(x) sum(is.na(x)))
na_count[na_count > 0]
## named integer(0)
cat("Total missing value pada seluruh dataset (hasil make_ames()):", sum(na_count), "\n")
## Total missing value pada seluruh dataset (hasil make_ames()): 0

Interpretasi: Hasil make_ames() tidak memiliki missing value sama sekali. Hal ini bukan berarti data mentahnya bersih, melainkan karena package AmesHousing sudah melakukan proses data cleaning di balik layar.

3.3 Statistik Deskriptif

summary(
  ames %>%
    select(
      Sale_Price,
      Gr_Liv_Area,
      Total_Bsmt_SF,
      Lot_Area,
      Year_Built,
      TotRms_AbvGrd
    )
)
##    Sale_Price      Gr_Liv_Area   Total_Bsmt_SF     Lot_Area        Year_Built  
##  Min.   : 12789   Min.   : 334   Min.   :   0   Min.   :  1300   Min.   :1872  
##  1st Qu.:129500   1st Qu.:1126   1st Qu.: 793   1st Qu.:  7440   1st Qu.:1954  
##  Median :160000   Median :1442   Median : 990   Median :  9436   Median :1973  
##  Mean   :180796   Mean   :1500   Mean   :1051   Mean   : 10148   Mean   :1971  
##  3rd Qu.:213500   3rd Qu.:1743   3rd Qu.:1302   3rd Qu.: 11555   3rd Qu.:2001  
##  Max.   :755000   Max.   :5642   Max.   :6110   Max.   :215245   Max.   :2010  
##  TotRms_AbvGrd   
##  Min.   : 2.000  
##  1st Qu.: 5.000  
##  Median : 6.000  
##  Mean   : 6.443  
##  3rd Qu.: 7.000  
##  Max.   :15.000

1. Sale_Price (Harga Rumah)

Harga rumah memiliki nilai minimum sebesar 12.789 dan maksimum sebesar 755.000, menunjukkan rentang harga yang sangat lebar. Nilai rata-rata (180.796) lebih tinggi dibanding median (160.000), yang mengindikasikan distribusi harga rumah cenderung miring ke kanan (right-skewed) akibat adanya beberapa rumah dengan harga sangat tinggi.

2. Gr_Liv_Area (Luas Area Hunian)

Luas area hunian berkisar antara 334 hingga 5.642 kaki persegi. Nilai median sebesar 1.442 dan rata-rata sebesar 1.500 menunjukkan bahwa sebagian besar rumah memiliki luas hunian sekitar 1.400–1.500 kaki persegi. Adanya perbedaan antara nilai maksimum dan rata-rata mengindikasikan keberadaan beberapa rumah berukuran sangat besar.

3. Total_Bsmt_SF (Luas Basement)

Luas basement memiliki nilai minimum 0, yang berarti terdapat rumah tanpa basement. Rata-rata luas basement adalah 1.051 kaki persegi dengan median 990 kaki persegi, menunjukkan bahwa sebagian besar rumah memiliki basement dengan ukuran yang cukup besar.

4. Lot_Area (Luas Tanah)

Luas tanah bervariasi dari 1.300 hingga 215.245 kaki persegi. Nilai maksimum yang sangat tinggi dibandingkan kuartil ketiga (11.555) menunjukkan adanya beberapa properti dengan luas tanah yang jauh lebih besar dibanding mayoritas rumah, sehingga kemungkinan terdapat outlier pada variabel ini.

5. Year_Built (Tahun Pembangunan)

Rumah tertua dibangun pada tahun 1872, sedangkan rumah terbaru dibangun pada tahun 2010. Median tahun pembangunan adalah 1973, yang menunjukkan bahwa sekitar setengah dari rumah dalam dataset dibangun sebelum tahun tersebut dan setengahnya lagi setelahnya.

6. TotRms_AbvGrd (Jumlah Ruangan di Atas Permukaan Tanah)

Jumlah ruangan berkisar antara 2 hingga 15 ruangan, dengan rata-rata 6,44 ruangan dan median 6 ruangan. Hal ini menunjukkan bahwa sebagian besar rumah memiliki sekitar 5–7 ruangan, yang dapat merepresentasikan ukuran rumah menengah.

3.4 Distribusi Harga Rumah

ggplot(ames, aes(x = Sale_Price)) +
  geom_histogram(bins = 40, fill = "#2C7FB8", color = "white") +
  scale_x_continuous(
    labels = label_dollar(prefix = "$")
  ) +
  labs(
    title = "Distribusi Harga Jual Rumah",
    x = "Harga Jual (USD)",
    y = "Frekuensi"
  ) +
  theme_minimal()

Interpretasi: Grafik menunjukkan ekor yang memanjang ke arah kanan (nilai harga yang lebih tinggi). Mayoritas rumah di Ames dijual dengan harga yang relatif rendah hingga menengah, sementara hanya ada sebagian kecil rumah mewah yang memiliki harga sangat tinggi. Konsentrasi penjualan rumah paling banyak berada pada kisaran harga sekitar $130,000 hingga $160,000 (ditunjukkan oleh dua batang tertinggi yang mendekati frekuensi 450. Terdapat beberapa data titik (batang-batang kecil) yang terisolasi di sisi kanan, mulai dari kisaran $500,000 hingga hampir $800,000.

3.5 Boxplot Harga Rumah

ggplot(ames, aes(y = Sale_Price)) +
  geom_boxplot(fill = "#41B6C4") +
  scale_y_continuous(
    labels = label_dollar(prefix = "$")
  ) +
  labs(
    title = "Boxplot Harga Jual Rumah",
    y = "Harga Jual (USD)"
  ) +
  theme_minimal()

Interpretasi: Sebesar 50% dari total seluruh rumah di dataset ini terkonsentrasi di rentang harga yang cukup ketat, yaitu antara $130,000 hingga $215,000. Setiap rumah yang terjual dengan harga di atas $340,000 secara statistik dianggap sebagai pencilan (outliers). Terlihat ada penumpukan outliers yang sangat padat dari harga $340,000 hingga $500,000, serta beberapa pencilan ekstrem yang mendekati angka $600,000 dan bahkan $750,000

3.6 Korelasi Variabel Numerik

num_vars <- ames %>% select(where(is.numeric))
corr_matrix <- cor(num_vars, use = "complete.obs")
corrplot(corr_matrix, method = "color", type = "upper", tl.cex = 0.6, tl.col = "black",
         order = "hclust")

3.7 Variabel Paling Berkorelasi dengan Harga Rumah

# Overall_Qual disimpan sebagai factor (ordinal), sehingga perlu diubah ke numerik
# secara eksplisit agar ikut serta dalam analisis korelasi numerik.
ames$Overall_Qual_num <- as.numeric(ames$Overall_Qual)

num_vars2 <- ames %>% select(where(is.numeric))
cor_target <- sort(cor(num_vars2)[, "Sale_Price"], decreasing = TRUE)
head(cor_target, 11)
##       Sale_Price Overall_Qual_num      Gr_Liv_Area      Garage_Cars 
##        1.0000000        0.7992618        0.7067799        0.6475616 
##      Garage_Area    Total_Bsmt_SF     First_Flr_SF       Year_Built 
##        0.6401383        0.6325288        0.6216761        0.5584261 
##        Full_Bath   Year_Remod_Add     Mas_Vnr_Area 
##        0.5456039        0.5329738        0.5021960

Interpretasi: Variabel yang paling berkorelasi positif dengan Sale_Price adalah Overall_Qual (kualitas material & finishing keseluruhan, r ≈ 0.80), diikuti oleh Gr_Liv_Area (luas area hunian di atas tanah, r ≈ 0.71), Garage_Cars, Garage_Area, dan Total_Bsmt_SF. Temuan ini konsisten dengan intuisi domain: rumah yang lebih luas dan berkualitas lebih tinggi cenderung dijual lebih mahal. Variabel-variabel inilah yang akan dijadikan prediktor utama pada tahap pemodelan regresi.

3.8 Hubungan Luas Rumah dan Harga Rumah

ggplot(ames, aes(x = Gr_Liv_Area, y = Sale_Price)) +
  geom_point(alpha = 0.4, color = "#225EA8") +
  
  geom_smooth(method = "lm", color = "red", se = FALSE) +
  
  scale_y_continuous(labels = scales::dollar_format()) +
  
  labs(title = "Hubungan Luas Hunian (Gr_Liv_Area) dengan Harga Rumah",
       x = "Luas Area Hunian (sqft)", 
       y = "Sale Price (USD)") +
  theme_minimal()

Interpretasi: Median Garis merah geom_smooth(method = “lm”) akan bergerak naik dari kiri bawah ke kanan atas. Ini membuktikan secara visual bahwa variabel Gr_Liv_Area (luas lantai di atas tanah) memiliki hubungan linear positif yang sangat kuat dengan Sale_Price. Semakin luas rumah, harganya semakin mahal. Penggunaan parameter alpha = 0.4 sangat tepat. Bagian transparan yang menumpuk menjadi warna biru pekat menunjukkan di mana mayoritas ukuran dan harga rumah di Ames berada (biasanya menumpuk di rentang 1,000–2,000 sqft)

3.9 Harga Rumah Berdasarkan Kualitas Bangunan

ggplot(ames, aes(x = factor(Overall_Qual_num), y = Sale_Price)) +
  geom_boxplot(fill = "#7FCDBB") +
  
  scale_y_continuous(labels = scales::dollar_format()) + 
  
  labs(title = "Harga Rumah Berdasarkan Overall Quality",
       x = "Overall Quality (1 = Sangat Rendah, 10 = Sangat Tinggi)", 
       y = "Sale Price (USD)") +
  theme_minimal()

Interpretasi: Median harga rumah meningkat secara konsisten seiring naiknya skor kualitas bangunan (Overall_Qual). Pola monoton ini memperkuat temuan korelasi sebelumnya bahwa kualitas bangunan adalah salah satu prediktor harga yang paling kuat dan dapat diandalkan.

3.10 Persiapan untuk Klastering

# Variabel numerik yang merepresentasikan karakteristik fisik rumah dipilih
# untuk segmentasi (klastering), TANPA menyertakan Sale_Price -- karena tujuan
# klastering adalah mengelompokkan rumah berdasarkan karakteristik, bukan harga.
cluster_vars <- c("Gr_Liv_Area", "Total_Bsmt_SF", "Garage_Area", "Lot_Area",
                   "Overall_Qual_num", "Year_Built", "TotRms_AbvGrd", "Full_Bath")

cluster_data <- ames[, cluster_vars]
summary(cluster_data)
##   Gr_Liv_Area   Total_Bsmt_SF   Garage_Area        Lot_Area     
##  Min.   : 334   Min.   :   0   Min.   :   0.0   Min.   :  1300  
##  1st Qu.:1126   1st Qu.: 793   1st Qu.: 320.0   1st Qu.:  7440  
##  Median :1442   Median : 990   Median : 480.0   Median :  9436  
##  Mean   :1500   Mean   :1051   Mean   : 472.7   Mean   : 10148  
##  3rd Qu.:1743   3rd Qu.:1302   3rd Qu.: 576.0   3rd Qu.: 11555  
##  Max.   :5642   Max.   :6110   Max.   :1488.0   Max.   :215245  
##  Overall_Qual_num   Year_Built   TotRms_AbvGrd      Full_Bath    
##  Min.   : 1.000   Min.   :1872   Min.   : 2.000   Min.   :0.000  
##  1st Qu.: 5.000   1st Qu.:1954   1st Qu.: 5.000   1st Qu.:1.000  
##  Median : 6.000   Median :1973   Median : 6.000   Median :2.000  
##  Mean   : 6.095   Mean   :1971   Mean   : 6.443   Mean   :1.567  
##  3rd Qu.: 7.000   3rd Qu.:2001   3rd Qu.: 7.000   3rd Qu.:2.000  
##  Max.   :10.000   Max.   :2010   Max.   :15.000   Max.   :4.000

Interpretasi: Delapan variabel di atas dipilih karena merepresentasikan tiga dimensi utama karakteristik rumah: ukuran (Gr_Liv_Area, Total_Bsmt_SF, Lot_Area, TotRms_AbvGrd), fasilitas (Garage_Area, Full_Bath), dan kualitas/usia (Overall_Qual_num, Year_Built). Sale_Price sengaja tidak diikutsertakan agar segmentasi murni didasarkan pada karakteristik fisik rumah, bukan harga jualnya — hasil klaster nanti justru akan dipakai untuk menjelaskan pola harga (lihat bagian Profiling Cluster).

3.11 Menentukan Jumlah Cluster

cluster_scaled <- scale(cluster_data)  # standarisasi wajib sebelum k-means

fviz_nbclust(cluster_scaled, kmeans, method = "wss", k.max = 8) +
  labs(title = "Elbow Method untuk Menentukan Jumlah Cluster Optimal")

Interpretasi: Grafik elbow method menunjukkan penurunan tajam within-cluster sum of squares (WSS) hingga k = 3, setelah itu penurunan melandai. Titik “siku” (elbow) pada k = 3 mengindikasikan bahwa 3 cluster merupakan jumlah yang cukup optimal — menambah cluster lebih banyak tidak memberikan perbaikan yang signifikan, namun menambah kompleksitas interpretasi.

3.12 Persiapan Klasifikasi

# Label kelas dibuat dari Sale_Price menggunakan pembagian tertile (33%/66%)
# sehingga didapatkan 3 kelas yang seimbang jumlah anggotanya.
batas <- quantile(ames$Sale_Price, probs = c(1/3, 2/3))
batas
## 33.33333% 66.66667% 
##    139000    190000
ames$Price_Class <- cut(ames$Sale_Price,
                         breaks = c(-Inf, batas[1], batas[2], Inf),
                         labels = c("Murah", "Sedang", "Mahal"))

table(ames$Price_Class)
## 
##  Murah Sedang  Mahal 
##    981    980    969

Interpretasi: Karena Sale_Price adalah variabel numerik kontinu, untuk keperluan klasifikasi variabel ini perlu diubah menjadi kategori. Digunakan pembagian tertile (persentil ke-33 dan ke-66) sehingga rumah terbagi rata ke dalam tiga kelas: Murah (di bawah 139,000), Sedang, dan Mahal (di atas 190,000). Pendekatan tertile dipilih (dibanding median split 2 kelas) agar masalah klasifikasi lebih menantang dan lebih informatif untuk segmentasi pasar.

4 Workflow Data Mining pada AmesHousing (CRISP-DM)

Setelah tahap EDA selesai dilakukan, alur kerja data mining yang sesuai dengan kerangka CRISP-DM (Cross-Industry Standard Process for Data Mining) adalah melanjutkan ke tahap Modeling. Pada mini project ini, tahap Modeling mencakup tiga pendekatan sekaligus pada satu dataset yang sama:

  1. Regression — memprediksi harga rumah (Sale_Price) sebagai variabel numerik kontinu.
  2. Classification — mengklasifikasikan rumah ke dalam kategori harga (Murah/Sedang/Mahal).
  3. Clustering — mengelompokkan rumah ke dalam segmen berdasarkan karakteristik fisiknya (tanpa menggunakan label harga).

Ketiga pendekatan ini saling melengkapi: regresi menjawab “berapa harganya”, klasifikasi menjawab “termasuk kategori harga apa”, dan klastering menjawab “rumah ini mirip dengan kelompok rumah seperti apa”.

5 Modeling

5.1 Prediksi Harga Rumah (Regression)

5.1.1 Variabel Target

Variabel target (response) pada tahap regresi adalah Sale_Price, yaitu harga jual rumah dalam satuan dolar — variabel numerik kontinu.

5.1.2 Memilih Variabel Prediktor

# Prediktor dipilih berdasarkan hasil analisis korelasi pada tahap EDA
# (variabel dengan korelasi tertinggi terhadap Sale_Price).
pred_vars <- c("Overall_Qual_num", "Gr_Liv_Area", "Garage_Cars", "Total_Bsmt_SF",
               "Year_Built", "Full_Bath", "TotRms_AbvGrd", "Year_Remod_Add", "Fireplaces")

reg_data <- ames[, c("Sale_Price", pred_vars)]
head(reg_data, 3)
##   Sale_Price Overall_Qual_num Gr_Liv_Area Garage_Cars Total_Bsmt_SF Year_Built
## 1     215000                6        1656           2          1080       1960
## 2     105000                5         896           1           882       1961
## 3     172000                6        1329           1          1329       1958
##   Full_Bath TotRms_AbvGrd Year_Remod_Add Fireplaces
## 1         1             7           1960          2
## 2         1             5           1961          0
## 3         1             6           1958          0

Interpretasi: Sembilan prediktor dipilih berdasarkan kekuatan korelasinya dengan Sale_Price pada tahap EDA sebelumnya, mencerminkan dimensi kualitas (Overall_Qual_num), ukuran (Gr_Liv_Area, Total_Bsmt_SF, TotRms_AbvGrd), fasilitas (Garage_Cars, Full_Bath, Fireplaces), dan usia bangunan (Year_Built, Year_Remod_Add).

5.1.3 Membagi Data Training dan Testing

set.seed(123)
idx <- sample(1:nrow(reg_data), size = 0.8 * nrow(reg_data))
train_reg <- reg_data[idx, ]
test_reg  <- reg_data[-idx, ]

cat("Jumlah data training:", nrow(train_reg), "\n")
## Jumlah data training: 2344
cat("Jumlah data testing :", nrow(test_reg), "\n")
## Jumlah data testing : 586

Interpretasi: Data dibagi 80% untuk training dan 20% untuk testing menggunakan random sampling. Pembagian ini perlu dilakukan agar performa model dapat dievaluasi secara objektif pada data yang belum pernah dilihat model (unseen data), sehingga mencerminkan kemampuan generalisasi model.

5.1.4 Membangun Model Regresi

model_lm <- lm(Sale_Price ~ ., data = train_reg)
summary(model_lm)
## 
## Call:
## lm(formula = Sale_Price ~ ., data = train_reg)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -512863  -20042   -2467   15740  276960 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      -1.273e+06  9.838e+04 -12.934  < 2e-16 ***
## Overall_Qual_num  1.876e+04  8.856e+02  21.182  < 2e-16 ***
## Gr_Liv_Area       5.803e+01  3.257e+00  17.820  < 2e-16 ***
## Garage_Cars       1.246e+04  1.353e+03   9.208  < 2e-16 ***
## Total_Bsmt_SF     2.975e+01  2.138e+00  13.917  < 2e-16 ***
## Year_Built        2.923e+02  3.860e+01   7.572 5.25e-14 ***
## Full_Bath        -8.088e+03  2.003e+03  -4.038 5.57e-05 ***
## TotRms_AbvGrd    -2.047e+03  8.434e+02  -2.427   0.0153 *  
## Year_Remod_Add    3.240e+02  4.937e+01   6.563 6.46e-11 ***
## Fireplaces        8.969e+03  1.361e+03   6.591 5.38e-11 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 36510 on 2334 degrees of freedom
## Multiple R-squared:  0.7952, Adjusted R-squared:  0.7944 
## F-statistic:  1007 on 9 and 2334 DF,  p-value: < 2.2e-16

Interpretasi: Model regresi linear berganda (multiple linear regression) dibangun dengan Sale_Price sebagai variabel dependen dan kesembilan variabel di atas sebagai prediktor. Nilai R-squared pada data training sebesar 0.795 menunjukkan bahwa model mampu menjelaskan sekitar 79.5% variasi harga rumah. Koefisien Overall_Qual_num dan Gr_Liv_Area memiliki nilai p-value yang sangat kecil (signifikan), menegaskan kembali bahwa keduanya merupakan prediktor harga yang paling kuat.

5.1.5 Prediksi

pred_reg <- predict(model_lm, newdata = test_reg)
head(data.frame(Aktual = test_reg$Sale_Price, Prediksi = round(pred_reg)), 10)
##    Aktual Prediksi
## 3  172000   155485
## 6  195500   195402
## 15 212000   240965
## 22 170000   189150
## 26 142000   127894
## 42 275000   296872
## 43 259000   287277
## 50 205000   239524
## 53 160000   192046
## 55 184500   188385

5.1.6 Evaluasi

rmse_val <- sqrt(mean((test_reg$Sale_Price - pred_reg)^2))
mae_val  <- mean(abs(test_reg$Sale_Price - pred_reg))
r2_test  <- cor(test_reg$Sale_Price, pred_reg)^2

cat("RMSE (testing):", round(rmse_val, 1), "\n")
## RMSE (testing): 34118.4
cat("MAE  (testing):", round(mae_val, 1), "\n")
## MAE  (testing): 23210.4
cat("R-squared (testing):", round(r2_test, 3), "\n")
## R-squared (testing): 0.803
ggplot(data.frame(Aktual = test_reg$Sale_Price, Prediksi = pred_reg),
       aes(x = Aktual, y = Prediksi)) +
  geom_point(alpha = 0.4, color = "#2C7FB8") +
  geom_abline(slope = 1, intercept = 0, color = "red", linetype = "dashed") +
  labs(title = "Harga Aktual vs Harga Prediksi", x = "Harga Aktual", y = "Harga Prediksi") +
  theme_minimal()

Interpretasi: Pada data testing, model menghasilkan RMSE ≈ 34,118 dan R² ≈ 0.803. Artinya, secara rata-rata prediksi model meleset sekitar 34,118 dari harga aktual, dan model mampu menjelaskan sekitar 80.3% variasi harga pada data baru. Titik-titik pada scatter plot yang mengumpul di sekitar garis diagonal (merah putus-putus) mengindikasikan prediksi yang cukup akurat, meskipun terdapat penyimpangan lebih besar pada rumah-rumah dengan harga sangat tinggi — konsisten dengan outlier yang ditemukan pada tahap EDA.

5.2 Klasifikasi Rumah

5.2.1 Membuat Label Kelas

Label kelas (Price_Class: Murah/Sedang/Mahal) telah dibuat pada tahap Persiapan Klasifikasi di bagian EDA menggunakan pembagian tertile dari Sale_Price.

table(ames$Price_Class)
## 
##  Murah Sedang  Mahal 
##    981    980    969

5.2.2 Memilih Variabel

# Variabel prediktor untuk klasifikasi TIDAK menyertakan Sale_Price (sumber label)
# agar tidak terjadi data leakage.
class_vars <- c("Overall_Qual_num", "Gr_Liv_Area", "Garage_Cars", "Total_Bsmt_SF",
                 "Year_Built", "Full_Bath")

class_data <- ames[, c("Price_Class", class_vars)]
head(class_data, 3)
##   Price_Class Overall_Qual_num Gr_Liv_Area Garage_Cars Total_Bsmt_SF Year_Built
## 1       Mahal                6        1656           2          1080       1960
## 2       Murah                5         896           1           882       1961
## 3      Sedang                6        1329           1          1329       1958
##   Full_Bath
## 1         1
## 2         1
## 3         1

Interpretasi: Variabel prediktor untuk klasifikasi sengaja dipilih subset dari variabel regresi (enam variabel paling kuat) untuk menjaga model tetap sederhana dan mudah diinterpretasikan dalam bentuk pohon keputusan.

5.2.3 Split Data

set.seed(123)
idx2 <- sample(1:nrow(class_data), size = 0.8 * nrow(class_data))
train_class <- class_data[idx2, ]
test_class  <- class_data[-idx2, ]

cat("Jumlah data training:", nrow(train_class), "\n")
## Jumlah data training: 2344
cat("Jumlah data testing :", nrow(test_class), "\n")
## Jumlah data testing : 586

5.2.4 Model Decision Tree

tree_model <- rpart(Price_Class ~ ., data = train_class, method = "class")
rpart.plot(tree_model, type = 2, extra = 104, fallen.leaves = TRUE,
           main = "Decision Tree - Klasifikasi Kategori Harga Rumah")

Interpretasi: Pohon keputusan menunjukkan bahwa Overall_Qual_num dan Gr_Liv_Area menjadi split (pemisah) utama di simpul-simpul teratas, sekali lagi menegaskan bahwa kualitas bangunan dan luas hunian adalah faktor paling diskriminatif dalam menentukan kategori harga rumah.

5.2.5 Prediksi

pred_class <- predict(tree_model, newdata = test_class, type = "class")
head(data.frame(Aktual = test_class$Price_Class, Prediksi = pred_class), 10)
##    Aktual Prediksi
## 3  Sedang   Sedang
## 6   Mahal   Sedang
## 15  Mahal    Mahal
## 22 Sedang   Sedang
## 26 Sedang    Murah
## 42  Mahal    Mahal
## 43  Mahal    Mahal
## 50  Mahal    Mahal
## 53 Sedang   Sedang
## 55 Sedang   Sedang

5.2.6 Confusion Matrix

cm <- table(Prediksi = pred_class, Aktual = test_class$Price_Class)
cm
##         Aktual
## Prediksi Murah Sedang Mahal
##   Murah    130     43     7
##   Sedang    39    128    45
##   Mahal      3     22   169

Interpretasi - Total prediksi yang tepat: 130+128+169=427 rumah. - Total prediksi yang meleset: 43+7+45+39+3+22=159 rumah.

  • Kelas Mahal (Paling Akurat): Total rumah asli Mahal ada 7+45+169=221. Model berhasil menebak 169 di antaranya (≈76.5%). Model cukup sensitif dalam mengenali rumah mewah.
  • Kelas Murah: Total rumah asli Murah ada 130+39+3=172. Model berhasil menebak 130 di antaranya (≈75.6%).
  • Kelas Sedang (Paling Lemah): Total rumah asli Sedang ada 43+128+22=193. Model hanya berhasil menebak 128 di antaranya (≈66.3%).

Kenapa kelas Sedang akurasinya paling rendah? Ini hal yang wajar dalam data mining. Rumah kelas Sedang secara karakteristik berada di tengah-tengah, sehingga fiturnya sering kali tumpang tindih (overlap) dengan batas atas kelas Murah atau batas bawah kelas Mahal.

5.2.7 Accuracy

accuracy <- sum(diag(cm)) / sum(cm)
cat("Akurasi model Decision Tree:", round(accuracy, 3), "atau", round(accuracy*100,1), "%\n")
## Akurasi model Decision Tree: 0.729 atau 72.9 %
# Precision & recall per kelas sebagai pelengkap evaluasi
precision <- diag(cm) / rowSums(cm)
recall    <- diag(cm) / colSums(cm)
data.frame(Kelas = names(precision), Precision = round(precision,3), Recall = round(recall,3))
##         Kelas Precision Recall
## Murah   Murah     0.722  0.756
## Sedang Sedang     0.604  0.663
## Mahal   Mahal     0.871  0.765

Interpretasi: Model Decision Tree berhasil mengklasifikasikan kategori harga rumah dengan akurasi sekitar 72.9%. Dari confusion matrix terlihat bahwa kesalahan klasifikasi paling banyak terjadi antara kelas yang berdekatan (misalnya “Sedang” tertukar dengan “Mahal” atau “Murah”), sementara kesalahan antara “Murah” dan “Mahal” (dua kelas yang paling jauh) sangat jarang terjadi. Pola ini wajar karena batas antar kategori harga bersifat kontinu, bukan benar-benar terpisah secara alami.

5.3 Klastering Rumah

5.3.1 Memilih Variabel Numerik

Variabel numerik yang digunakan untuk klastering sama dengan yang telah dipilih pada tahap Persiapan untuk Klastering di bagian EDA (cluster_vars), yaitu kombinasi variabel ukuran, fasilitas, dan kualitas/usia rumah — tanpa menyertakan Sale_Price.

cluster_vars
## [1] "Gr_Liv_Area"      "Total_Bsmt_SF"    "Garage_Area"      "Lot_Area"        
## [5] "Overall_Qual_num" "Year_Built"       "TotRms_AbvGrd"    "Full_Bath"

5.3.2 Standarisasi

# Standarisasi (z-score) WAJIB dilakukan sebelum k-means karena variabel-variabel
# di atas memiliki satuan dan skala yang sangat berbeda (mis. Lot_Area dalam ribuan
# sqft vs Full_Bath dalam satuan 0-4). Tanpa standarisasi, variabel berskala besar
# akan mendominasi perhitungan jarak Euclidean.
cluster_scaled <- scale(cluster_data)
head(round(cluster_scaled, 2), 3)
##      Gr_Liv_Area Total_Bsmt_SF Garage_Area Lot_Area Overall_Qual_num Year_Built
## [1,]        0.31          0.07        0.26     2.74            -0.07      -0.38
## [2,]       -1.19         -0.38        1.20     0.19            -0.78      -0.34
## [3,]       -0.34          0.63       -0.75     0.52            -0.07      -0.44
##      TotRms_AbvGrd Full_Bath
## [1,]          0.35     -1.02
## [2,]         -0.92     -1.02
## [3,]         -0.28     -1.02

5.3.3 Menentukan Jumlah Cluster

Berdasarkan elbow method pada tahap EDA, dipilih k = 3 sebagai jumlah cluster optimal.

5.3.4 K-Means

set.seed(123)
km_model <- kmeans(cluster_scaled, centers = 3, nstart = 25)
km_model$centers
##   Gr_Liv_Area Total_Bsmt_SF Garage_Area    Lot_Area Overall_Qual_num Year_Built
## 1  -0.6448838   -0.46045001  -0.5462595 -0.14688945       -0.6813153 -0.6585472
## 2   0.2143664    0.06590425   0.1220086 -0.08688994        0.3084168  0.5019332
## 3   1.3947342    1.19587606   1.3181622  0.62917557        1.2854648  0.7747096
##   TotRms_AbvGrd  Full_Bath
## 1    -0.5012393 -0.8920637
## 2     0.1282737  0.7303585
## 3     1.1720677  0.9336439

5.3.5 Jumlah Anggota Tiap Cluster

table(Cluster = km_model$cluster)
## Cluster
##    1    2    3 
## 1378 1081  471

5.3.6 Visualisasi Cluster

fviz_cluster(km_model, data = cluster_scaled,
             geom = "point", ellipse.type = "convex", palette = "jco",
             ggtheme = theme_minimal(),
             main = "Visualisasi Cluster Rumah (PCA 2D)")

Interpretasi: 1. Cluster 1 (Warna Biru - Sisi Kanan)

  • Karakteristik Posisi: Berada di area nilai Dim1 positif yang tinggi (ke arah kanan).
  • Interpretasi Properti: Kelompok ini mewakili rumah-rumah dengan spesifikasi tinggi, mewah, atau berukuran besar. Karena posisinya mengumpul padat di kanan, properti di cluster ini memiliki kemiripan fitur yang sangat homogen satu sama lain (misalnya, sama-sama memiliki kualitas di atas rata-rata dan garasi luas).

2. Cluster 2 (Warna Kuning - Sisi Tengah)

  • Karakteristik Posisi: Berada tepat di tengah-tengah, menjembatani Cluster 1 dan Cluster 3.
  • Interpretasi Properti: Ini adalah kelompok rumah kelas menengah (standar/reguler). Rumah-rumah di cluster ini memiliki karakteristik yang rata-rata (tidak terlalu kecil/tua, tapi juga tidak terlalu mewah). Cluster ini sedikit beririsan (overlap) dengan Cluster 1 dan 3, menandakan adanya transisi fitur yang halus di area batas kelas menengah.

3. Cluster 3 (Warna Abu-abu - Sisi Kiri & Menyebar)

  • Karakteristik Posisi: Berada di area nilai Dim1 negatif yang rendah (ke arah kiri) dan bentuk poligonnya (convex hull) sangat melebar, terutama ke arah bawah (Dim2 negatif).
  • Interpretasi Properti: Kelompok ini mewakili rumah dengan spesifikasi rendah, ekonomis, atau bangunan tua/butuh renovasi.

Analisis Poligon yang Lebar: Bentuk poligon abu-abu yang sangat luas dan renggang mengindikasikan bahwa data di Cluster 3 memiliki variabilitas (keberagaman) yang sangat tinggi dibandingkan cluster lainnya. Ada rumah yang sangat ekstrem di ujung kiri bawah (jarak antar titik berjauhan), yang bisa dikaitkan dengan properti bernilai rendah namun memiliki karakteristik tanah/kondisi yang sangat tidak biasa (outliers dalam clustering).

5.3.7 Profiling Cluster

profil <- aggregate(cluster_data, by = list(Cluster = km_model$cluster), mean)
profil_n <- table(km_model$cluster)
profil$Jumlah_Rumah <- as.integer(profil_n)

# Tambahkan rata-rata Sale_Price per cluster untuk membantu interpretasi
profil$Avg_Sale_Price <- tapply(ames$Sale_Price, km_model$cluster, mean)

profil <- profil %>% mutate(across(where(is.numeric), ~round(., 1)))
profil
##   Cluster Gr_Liv_Area Total_Bsmt_SF Garage_Area Lot_Area Overall_Qual_num
## 1       1      1173.7         848.2       355.1   8990.4              5.1
## 2       2      1608.1        1080.3       498.9   9463.2              6.5
## 3       3      2204.7        1578.6       756.3  15105.8              7.9
##   Year_Built TotRms_AbvGrd Full_Bath Jumlah_Rumah Avg_Sale_Price
## 1     1951.4           5.7       1.1         1378       128389.7
## 2     1986.5           6.6       2.0         1081       191952.5
## 3     1994.8           8.3       2.1          471       308515.5

Interpretasi profil cluster:

ord <- order(profil$Avg_Sale_Price)
profil_sorted <- profil[ord, ]
profil_sorted
##   Cluster Gr_Liv_Area Total_Bsmt_SF Garage_Area Lot_Area Overall_Qual_num
## 1       1      1173.7         848.2       355.1   8990.4              5.1
## 2       2      1608.1        1080.3       498.9   9463.2              6.5
## 3       3      2204.7        1578.6       756.3  15105.8              7.9
##   Year_Built TotRms_AbvGrd Full_Bath Jumlah_Rumah Avg_Sale_Price
## 1     1951.4           5.7       1.1         1378       128389.7
## 2     1986.5           6.6       2.0         1081       191952.5
## 3     1994.8           8.3       2.1          471       308515.5

Berdasarkan rata-rata Sale_Price per cluster, dapat diberikan profil/segmentasi sebagai berikut (urutan dari harga rata-rata terendah ke tertinggi):

  • Cluster dengan harga rata-rata terendah: rumah berukuran lebih kecil (Gr_Liv_Area dan Total_Bsmt_SF lebih rendah), usia bangunan lebih tua (Year_Built lebih kecil), dan skor Overall_Qual lebih rendah — dapat dilabeli sebagai segmen “Rumah Ekonomis/Tua”.
  • Cluster menengah: ukuran dan kualitas berada di kisaran rata-rata pasar — segmen “Rumah Standar/Keluarga”.
  • Cluster dengan harga rata-rata tertinggi: luas hunian dan basement terbesar, jumlah kamar dan kamar mandi terbanyak, kualitas bangunan tertinggi, dan relatif baru dibangun — segmen “Rumah Premium/Mewah”.

meskipun klastering tidak menggunakan Sale_Price sama sekali sebagai input, hasil cluster yang terbentuk tetap selaras dengan tingkatan harga rumah yang sebenarnya. Ini menjadi bukti tambahan (validasi tidak langsung) bahwa karakteristik fisik rumah (ukuran, kualitas, usia) memang berasosiasi kuat dengan harga jualnya.

6 Insight

Berdasarkan keseluruhan analisis pada dataset AmesHousing (2.930 observasi, 81 variabel hasil make_ames()), dapat disimpulkan beberapa insight utama:

  1. Faktor utama yang memengaruhi harga rumah: Overall_Qual (kualitas bangunan) dan Gr_Liv_Area (luas area hunian) secara konsisten muncul sebagai prediktor terkuat di ketiga pendekatan (korelasi tertinggi pada EDA, koefisien paling signifikan pada regresi, dan node pemisah utama pada decision tree).

  2. Kemampuan memprediksi harga rumah: Model regresi linear dengan 9 prediktor mampu menjelaskan sekitar 80.3% variasi harga rumah pada data testing (R² ≈ 0.803), dengan rata-rata kesalahan prediksi (RMSE) sebesar 34,118. Untuk klasifikasi kategori harga (Murah/Sedang/ Mahal), model Decision Tree mencapai akurasi 72.9%, dengan kesalahan prediksi mayoritas terjadi pada kategori yang berdekatan, bukan kategori yang berlawanan.

  3. Segmentasi rumah berdasarkan karakteristik: K-Means dengan k = 3 berhasil mengelompokkan rumah menjadi tiga segmen alami — rumah ekonomis/tua, rumah standar/keluarga, dan rumah premium/mewah — tanpa menggunakan informasi harga sama sekali. Keselarasan segmen ini dengan tingkatan harga aktual menjadi validasi tambahan terhadap konsistensi temuan di seluruh tahap analisis.

Secara keseluruhan, dataset AmesHousing memungkinkan satu siklus penuh proses Data Mining sesuai kerangka CRISP-DM — mulai dari pemahaman data (EDA), hingga tiga jenis tugas pemodelan (Regression, Classification, Clustering) — dipraktikkan secara terpadu dalam satu studi kasus, dengan temuan yang saling memperkuat satu sama lain di setiap tahapnya.