1 INTRODUCTION

Pada kesempatan kali ini, saya akan menganalisis data house pricing yang disediakan oleh kaggle. Data house pricing tersebut menunjukan harga rumah berdasarkan luasnya dan fitur-fitur yang dimiliki rumah tersebut. Dengan menggunakan model liner regresian, kita dapat memprediksi harga rumah berdasarkan variabel-variabel yang ada, yang nantinya dapat digunakan baik untuk consumer sebagai kriteria perbandingan harga dalam membeli rumah, maupun untuk developer sebagai acuan menentukan harga rumah berdasarkan variabel-variabel yang dimiliki rumah tersebut.

2 IMPORT LIBRARY & READ DATA

Berikut adalah library yang akan kita gunakan:

library(dplyr)
library(caret)
library(GGally)
library(MLmetrics)
library(rsample)
library(lmtest)
library(car)

Pertama-tama kita akan memanggil data yang sudah kita simpan dan meng-assignya ke object house_pricing

house_pricing <- read.csv("HousePrices_halfMil.csv")

Gunakan fungsi head dan glimpse untuk mendapatkan sedikit gambaran dari data yang akan kita analisis.

head(house_pricing)
glimpse(house_pricing)
## Rows: 500,000
## Columns: 16
## $ Area          <int> 164, 84, 190, 75, 148, 124, 58, 249, 243, 242, 61, 189, …
## $ Garage        <int> 2, 2, 2, 2, 1, 3, 1, 2, 1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 2,…
## $ FirePlace     <int> 0, 0, 4, 4, 4, 3, 0, 1, 0, 2, 4, 0, 0, 3, 3, 4, 0, 3, 3,…
## $ Baths         <int> 2, 4, 4, 4, 2, 3, 2, 1, 2, 4, 5, 4, 2, 3, 1, 1, 5, 3, 5,…
## $ White.Marble  <int> 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,…
## $ Black.Marble  <int> 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1,…
## $ Indian.Marble <int> 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,…
## $ Floors        <int> 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1,…
## $ City          <int> 3, 2, 2, 1, 2, 1, 3, 1, 1, 2, 1, 2, 1, 3, 3, 1, 3, 1, 3,…
## $ Solar         <int> 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0,…
## $ Electric      <int> 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1,…
## $ Fiber         <int> 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,…
## $ Glass.Doors   <int> 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1,…
## $ Swiming.Pool  <int> 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0,…
## $ Garden        <int> 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0,…
## $ Prices        <int> 43800, 37550, 49500, 50075, 52400, 54300, 34400, 50425, …

house_pricing terdiri dari kolom : - Area : luas rumah - Garage : jumlah garasi yang terdapat di rumah tersebut - FirePlace : jumlah perapian - Bath : jumlah kamar mandi - White.Marble : lantai menggunakan white marble - Black.Marble : lantai menggunakan black marble - Indian.Marbles : lantan menggunakan indian marbles - floor : jumlah lantai/tingkat rumah - City : lokasi dari rumah tersebut - Solar : menggunakan panel surya atau tidak - Electir : terdapat electric atau tidak - fiber ; terdapat fiber atau tidak - glass.doors : terdapat pintu kaca atau tidak - swimmping.Pool : terdapat kolam renang atau tidak - Garden : terdapat taman atau tidak - Prices : harga rumah

Cek missing value dengan fungi anyNA dan colSums(is.na)

anyNA(house_pricing)
## [1] FALSE
colSums(is.na(house_pricing))
##          Area        Garage     FirePlace         Baths  White.Marble 
##             0             0             0             0             0 
##  Black.Marble Indian.Marble        Floors          City         Solar 
##             0             0             0             0             0 
##      Electric         Fiber   Glass.Doors  Swiming.Pool        Garden 
##             0             0             0             0             0 
##        Prices 
##             0

Dari hasil kedau fungsi tersebut dapat kita lihat tidak ada missing values dalam setiap kolom dataset house pricing.

Dataset house_pricing tidak memiliki missing values.

3 DATA WRANGLING

Unutuk mempermudah proses analisis dan mendapatkan hasil yang lebih akurat, kita perlu terlebih dahulu membersihakan data dengan mengganti beberapa tipe data tersebut

house.pricing_clean <- 
  house_pricing %>% 
  mutate_if(is.numeric, as.factor) %>% 
  mutate(Garage = as.numeric(Garage),
         Prices = as.numeric(Prices),
         Area =  as.numeric(Area),
         FirePlace = as.numeric(FirePlace),
         Baths = as.numeric(Baths))
glimpse(house.pricing_clean)
## Rows: 500,000
## Columns: 16
## $ Area          <dbl> 164, 84, 190, 75, 148, 124, 58, 249, 243, 242, 61, 189, …
## $ Garage        <dbl> 2, 2, 2, 2, 1, 3, 1, 2, 1, 1, 2, 2, 2, 3, 3, 3, 1, 3, 2,…
## $ FirePlace     <dbl> 1, 1, 5, 5, 5, 4, 1, 2, 1, 3, 5, 1, 1, 4, 4, 5, 1, 4, 4,…
## $ Baths         <dbl> 2, 4, 4, 4, 2, 3, 2, 1, 2, 4, 5, 4, 2, 3, 1, 1, 5, 3, 5,…
## $ White.Marble  <fct> 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,…
## $ Black.Marble  <fct> 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1,…
## $ Indian.Marble <fct> 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,…
## $ Floors        <fct> 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1,…
## $ City          <fct> 3, 2, 2, 1, 2, 1, 3, 1, 1, 2, 1, 2, 1, 3, 3, 1, 3, 1, 3,…
## $ Solar         <fct> 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0,…
## $ Electric      <fct> 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1,…
## $ Fiber         <fct> 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,…
## $ Glass.Doors   <fct> 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1,…
## $ Swiming.Pool  <fct> 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0,…
## $ Garden        <fct> 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0,…
## $ Prices        <dbl> 1399, 1149, 1627, 1650, 1743, 1819, 1023, 1664, 830, 539…

4 EDA

ggcorr(house.pricing_clean,label = TRUE, label_size = 3, hjust = 1, layout.exp = 1)
## Warning in ggcorr(house.pricing_clean, label = TRUE, label_size = 3, hjust
## = 1, : data in column(s) 'White.Marble', 'Black.Marble', 'Indian.Marble',
## 'Floors', 'City', 'Solar', 'Electric', 'Fiber', 'Glass.Doors', 'Swiming.Pool',
## 'Garden' are not numeric and were ignored

Penggunaan ggcorr tidak terlalu efektif karena mayoritas data lainnya bertipe factor. Tapi dari ggcorr tersebut kita dapat melihat bahwa prediktor bath, fireplace, garage, dan area memiliki korelasi positif terhadap Prices sebesar 0,1.

hist(house.pricing_clean$Prices)

Berikut distribusi variable prices. dapat kita liha mau variable price berdistirbusi normal.

boxplot(house.pricing_clean$Prices)

boxplot(house.pricing_clean$Area)

Dari kedua boxplot tersebut dapat disimpulkan tidak terdapat outlier yang terlalu signifikan.

Kita juga dapat melihat apakah benar penambahan jumlah variabel akan membuat harga rumah semakin tinggi dengan membuat barplot.

price.garage <- 
  house.pricing_clean %>% 
  select(Prices, Garage) %>% 
  group_by(Garage) %>% 
  summarise(Prices = mean(Prices)) %>% 
  ungroup()

price.bath <- 
  house.pricing_clean %>% 
  select(Prices, Baths) %>% 
  group_by(Baths) %>% 
  summarise(Prices = mean(Prices)) %>% 
  ungroup()

price.fireplace <- 
  house.pricing_clean %>% 
  select(Prices, FirePlace) %>% 
  group_by(FirePlace) %>% 
  summarise(Prices = mean(Prices)) %>% 
  ungroup()

price.floors <- 
  house.pricing_clean %>% 
  select(Prices, Floors) %>% 
  group_by(Floors) %>% 
  summarise(Prices = mean(Prices)) %>% 
  ungroup()
price.garage
price.bath
price.fireplace
price.floors
library(ggplot2)
ggplot(price.bath, mapping = aes(x = Prices, y = Baths)) +
  geom_bar(stat = "identity")

ggplot(price.fireplace, mapping = aes(x = Prices, y = FirePlace)) +
  geom_bar(stat = "identity")

ggplot(price.garage, mapping = aes(x = Prices, y = Garage)) +
  geom_bar(stat = "identity")

ggplot(price.floors, mapping = aes(x = Prices, y = Floors)) +
  geom_bar(stat = "identity")

Dari visualisasi diatas dapat disimpulkan bahwa penambahan jumlah pada floor, garage, fireplace, dan bath membuat prices dari rumah tersebut juga bertambah.

5 BUILD MODEL

Pertama-tama kita harus menentukan target variabelnya terlebih dahulu. Target variabel ditentukan berdasarkan pertanyaan bisnis yang telah dibuatm yaitu prices. Prices dipilih karena kita ingin melihat pengaruh perubahan tiap prediktor terhadap prices atau harga dari rumah tersebut.

set.seed(20)
index <- initial_split(data = house.pricing_clean, 
                       prop = 0.8) 

data_train <- training(index)
data_test <-testing(index)
hp_model_all <- lm(formula = Prices~.,
               data = data_train)
hp_model <- step(hp_model_all,
                 direction = "backward",
                 trace = F)
summary(hp_model_all)
## 
## Call:
## lm(formula = Prices ~ ., data = data_train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -51.967  -0.005   0.000   0.006  44.971 
## 
## Coefficients: (1 not defined because of singularities)
##                      Estimate     Std. Error     t value            Pr(>|t|)
## (Intercept)    -202.962881973    0.001714104 -118407.579 <0.0000000000000002
## Area              0.999956449    0.000004357  229531.001 <0.0000000000000002
## Garage           59.996909787    0.000382790  156735.775 <0.0000000000000002
## FirePlace        29.998252425    0.000221354  135521.780 <0.0000000000000002
## Baths            49.997967221    0.000221105  226128.064 <0.0000000000000002
## White.Marble1   559.993372673    0.000765713  731335.874 <0.0000000000000002
## Black.Marble1   199.997434954    0.000765950  261110.267 <0.0000000000000002
## Indian.Marble1             NA             NA          NA                  NA
## Floors1         599.995533624    0.000625449  959303.254 <0.0000000000000002
## City2           139.997401453    0.000766233  182708.772 <0.0000000000000002
## City3           279.993291296    0.000766251  365406.896 <0.0000000000000002
## Solar1            9.998519446    0.000625451   15986.106 <0.0000000000000002
## Electric1        49.996838172    0.000625445   79938.012 <0.0000000000000002
## Fiber1          469.995520055    0.000625456  751444.965 <0.0000000000000002
## Glass.Doors1    177.995512561    0.000625454  284585.931 <0.0000000000000002
## Swiming.Pool1     0.000782374    0.000625450       1.251               0.211
## Garden1           0.000279301    0.000625456       0.447               0.655
##                   
## (Intercept)    ***
## Area           ***
## Garage         ***
## FirePlace      ***
## Baths          ***
## White.Marble1  ***
## Black.Marble1  ***
## Indian.Marble1    
## Floors1        ***
## City2          ***
## City3          ***
## Solar1         ***
## Electric1      ***
## Fiber1         ***
## Glass.Doors1   ***
## Swiming.Pool1     
## Garden1           
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1978 on 399984 degrees of freedom
## Multiple R-squared:      1,  Adjusted R-squared:      1 
## F-statistic: 1.602e+11 on 15 and 399984 DF,  p-value: < 0.00000000000000022
summary(hp_model)
## 
## Call:
## lm(formula = Prices ~ Area + Garage + FirePlace + Baths + White.Marble + 
##     Black.Marble + Floors + City + Solar + Electric + Fiber + 
##     Glass.Doors, data = data_train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -51.968  -0.005   0.000   0.006  44.970 
## 
## Coefficients:
##                     Estimate     Std. Error t value            Pr(>|t|)    
## (Intercept)   -202.962356944    0.001657128 -122478 <0.0000000000000002 ***
## Area             0.999956448    0.000004357  229531 <0.0000000000000002 ***
## Garage          59.996910016    0.000382790  156736 <0.0000000000000002 ***
## FirePlace       29.998253176    0.000221353  135522 <0.0000000000000002 ***
## Baths           49.997967742    0.000221104  226129 <0.0000000000000002 ***
## White.Marble1  559.993372309    0.000765711  731338 <0.0000000000000002 ***
## Black.Marble1  199.997435670    0.000765950  261110 <0.0000000000000002 ***
## Floors1        599.995533898    0.000625448  959305 <0.0000000000000002 ***
## City2          139.997402995    0.000766231  182709 <0.0000000000000002 ***
## City3          279.993292332    0.000766250  365407 <0.0000000000000002 ***
## Solar1           9.998518432    0.000625446   15986 <0.0000000000000002 ***
## Electric1       49.996838741    0.000625445   79938 <0.0000000000000002 ***
## Fiber1         469.995523028    0.000625451  751451 <0.0000000000000002 ***
## Glass.Doors1   177.995513531    0.000625452  284587 <0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1978 on 399986 degrees of freedom
## Multiple R-squared:      1,  Adjusted R-squared:      1 
## F-statistic: 1.849e+11 on 13 and 399986 DF,  p-value: < 0.00000000000000022

Proses stepwise backward menghilangkan prediktor indian marble, swimming pool, dan garden karena dirasa 3 prediktor tersebut tidak memiliki signifikansi yang kuat terhadap prices dari rumah. Nilai dari adjusted R-squared = 1, artinya informasi sudah ditangkap dengan sangat baik.

pred_model.all <- predict(object = hp_model_all,
                      newdata = data_test)
## Warning in predict.lm(object = hp_model_all, newdata = data_test): prediction
## from a rank-deficient fit may be misleading
pred_hp.model <- predict(object = hp_model,
                newdata = data_test)

6 MODEL EVALUATION & ASSUMPTION

6.1 RMSE

RMSE(y_pred =  pred_model.all, y_true =  data_test$Prices)
## [1] 0.2953036
RMSE(y_pred = pred_hp.model, y_true = data_test$Prices)
## [1] 0.2953008

Kedua model tersebut memiliki RMSE yang sudah baik. Model dengan stepwise memiliki RMSE yang sedikit lebih kecil dari Model dengan semua prediktor. Kita akan memilih hp_model atau model dengan stepwise backward.

6.2 Normality

hist(hp_model$residuals, breaks = 10)

Hal tersebut terjadi karena nilai r-squared = 1 yang artinya informasi ditangkap dengan sangat baik, selisi prediksi dengan nilai aslinya sekitaran 0.

shapiro.test(hp_model$residuals[sample(5000)])
## 
##  Shapiro-Wilk normality test
## 
## data:  hp_model$residuals[sample(5000)]
## W = 0.10607, p-value < 0.00000000000000022

Dari histogram dan saphiro test, model dikatakan sudah berdistribusi normal.

6.3 Homoscedasticity

bptest(hp_model)
## 
##  studentized Breusch-Pagan test
## 
## data:  hp_model
## BP = 23.118, df = 13, p-value = 0.04028

p value dari hp model < 0.05 yang artinya terdapat Heteroscedasticity pada model tersebut

6.4 Multicollinearity

vif(hp_model)
##                  GVIF Df GVIF^(1/(2*Df))
## Area         1.000034  1        1.000017
## Garage       1.000078  1        1.000039
## FirePlace    1.000014  1        1.000007
## Baths        1.000041  1        1.000020
## White.Marble 1.332075  1        1.154156
## Black.Marble 1.332086  1        1.154160
## Floors       1.000025  1        1.000013
## City         1.000055  2        1.000014
## Solar        1.000013  1        1.000006
## Electric     1.000015  1        1.000008
## Fiber        1.000032  1        1.000016
## Glass.Doors  1.000038  1        1.000019

Nilai vif tiap prediktor kurang dari 10 artinya tidak terdapat multocollinearity pada model tersebut.

7 CONCLUSION

Kedual model mampu menghasilkan prediksi yang baik. Model dengan stepwise menghasilkan performa yang sedikit lebih baik dibandingkan model dengan semua prediktor dengan nilai adjusted r-squarednya = 1 dan RMSE-nya adalah 0.2953008. Model dengan stepwise (hp_model) berhasil memenuhi 2 asumsi yaitu normalitas dan multocollinearity, namun masih terdapat Heteroscedasticity. Heteroscedasticity mengidentifikasikan masih ada pola yang belum tertangkap