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.
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.
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…
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.
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)
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.
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.
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
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.
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