0.1 Pendahuluan

Ini adalah sebuah set data yang dibuat melalui proses penggabungan data generik. Data ini mencakup informasi tentang harga rumah di lingkungan perkotaan di Paris. Data ini telah disusun untuk digunakan dalam konteks pembelajaran Model Regresi Linear. Dalam penelitian kali ini, data ini akan digunakan untuk mengembangkan model regresi linear. Lebih tepatnya, penelitian ini bertujuan untuk melakukan prediksi harga rumah berdasarkan karakteristiknya.

0.2 Persiapan Data

Saya akan melakukan pembacaan data dan kemudian menyimpannya ke dalam variabel yang bernama “house”.

house <- read.csv("data_input/ParisHousing.csv")
glimpse(house)
#> Rows: 10,000
#> Columns: 17
#> $ squareMeters      <int> 75523, 80771, 55712, 32316, 70429, 39223, 58682, 869…
#> $ numberOfRooms     <int> 3, 39, 58, 47, 19, 36, 10, 100, 3, 42, 21, 74, 31, 4…
#> $ hasYard           <int> 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1…
#> $ hasPool           <int> 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1…
#> $ floors            <int> 63, 98, 19, 6, 90, 17, 99, 11, 61, 15, 90, 21, 5, 77…
#> $ cityCode          <int> 9373, 39381, 34457, 27939, 38045, 39489, 6450, 98155…
#> $ cityPartRange     <int> 3, 8, 6, 10, 3, 8, 10, 3, 8, 5, 6, 4, 2, 8, 10, 6, 3…
#> $ numPrevOwners     <int> 8, 6, 8, 4, 7, 6, 9, 4, 3, 8, 8, 2, 9, 4, 5, 9, 9, 8…
#> $ made              <int> 2005, 2015, 2021, 2012, 1990, 2012, 1995, 2003, 2012…
#> $ isNewBuilt        <int> 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1…
#> $ hasStormProtector <int> 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1…
#> $ basement          <int> 4313, 3653, 2937, 659, 8435, 2009, 5930, 6326, 632, …
#> $ attic             <int> 9005, 2436, 8852, 7141, 2429, 4552, 9453, 4748, 5792…
#> $ garage            <int> 956, 128, 135, 359, 292, 757, 848, 654, 807, 591, 68…
#> $ hasStorageRoom    <int> 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1…
#> $ hasGuestRoom      <int> 7, 2, 9, 3, 4, 1, 5, 10, 5, 3, 10, 9, 4, 0, 7, 5, 9,…
#> $ price             <dbl> 7559082, 8085990, 5574642, 3232561, 7055052, 3926647…
summary(house)
#>   squareMeters   numberOfRooms       hasYard          hasPool      
#>  Min.   :   89   Min.   :  1.00   Min.   :0.0000   Min.   :0.0000  
#>  1st Qu.:25099   1st Qu.: 25.00   1st Qu.:0.0000   1st Qu.:0.0000  
#>  Median :50106   Median : 50.00   Median :1.0000   Median :0.0000  
#>  Mean   :49870   Mean   : 50.36   Mean   :0.5087   Mean   :0.4968  
#>  3rd Qu.:74610   3rd Qu.: 75.00   3rd Qu.:1.0000   3rd Qu.:1.0000  
#>  Max.   :99999   Max.   :100.00   Max.   :1.0000   Max.   :1.0000  
#>      floors          cityCode     cityPartRange   numPrevOwners   
#>  Min.   :  1.00   Min.   :    3   Min.   : 1.00   Min.   : 1.000  
#>  1st Qu.: 25.00   1st Qu.:24694   1st Qu.: 3.00   1st Qu.: 3.000  
#>  Median : 50.00   Median :50693   Median : 5.00   Median : 5.000  
#>  Mean   : 50.28   Mean   :50225   Mean   : 5.51   Mean   : 5.522  
#>  3rd Qu.: 76.00   3rd Qu.:75683   3rd Qu.: 8.00   3rd Qu.: 8.000  
#>  Max.   :100.00   Max.   :99953   Max.   :10.00   Max.   :10.000  
#>       made        isNewBuilt     hasStormProtector    basement    
#>  Min.   :1990   Min.   :0.0000   Min.   :0.0000    Min.   :    0  
#>  1st Qu.:1997   1st Qu.:0.0000   1st Qu.:0.0000    1st Qu.: 2560  
#>  Median :2006   Median :0.0000   Median :0.0000    Median : 5092  
#>  Mean   :2005   Mean   :0.4991   Mean   :0.4999    Mean   : 5033  
#>  3rd Qu.:2014   3rd Qu.:1.0000   3rd Qu.:1.0000    3rd Qu.: 7511  
#>  Max.   :2021   Max.   :1.0000   Max.   :1.0000    Max.   :10000  
#>      attic           garage       hasStorageRoom   hasGuestRoom   
#>  Min.   :    1   Min.   : 100.0   Min.   :0.000   Min.   : 0.000  
#>  1st Qu.: 2512   1st Qu.: 327.8   1st Qu.:0.000   1st Qu.: 2.000  
#>  Median : 5045   Median : 554.0   Median :1.000   Median : 5.000  
#>  Mean   : 5028   Mean   : 553.1   Mean   :0.503   Mean   : 4.995  
#>  3rd Qu.: 7540   3rd Qu.: 777.2   3rd Qu.:1.000   3rd Qu.: 8.000  
#>  Max.   :10000   Max.   :1000.0   Max.   :1.000   Max.   :10.000  
#>      price         
#>  Min.   :   10314  
#>  1st Qu.: 2516402  
#>  Median : 5016180  
#>  Mean   : 4993448  
#>  3rd Qu.: 7469092  
#>  Max.   :10006771

Selanjutnya saya akan mengubah data-data yang bersifat klasifikasi/dapat dikelompokkan, dengan menggunakan fungsi as.factor.

house <- house %>%
  mutate(across(-c(squareMeters, numberOfRooms, floors, numPrevOwners, made, basement, attic, price, garage, cityCode, made, cityPartRange, hasGuestRoom), as.factor))

glimpse(house)
#> Rows: 10,000
#> Columns: 17
#> $ squareMeters      <int> 75523, 80771, 55712, 32316, 70429, 39223, 58682, 869…
#> $ numberOfRooms     <int> 3, 39, 58, 47, 19, 36, 10, 100, 3, 42, 21, 74, 31, 4…
#> $ hasYard           <fct> 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1…
#> $ hasPool           <fct> 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1…
#> $ floors            <int> 63, 98, 19, 6, 90, 17, 99, 11, 61, 15, 90, 21, 5, 77…
#> $ cityCode          <int> 9373, 39381, 34457, 27939, 38045, 39489, 6450, 98155…
#> $ cityPartRange     <int> 3, 8, 6, 10, 3, 8, 10, 3, 8, 5, 6, 4, 2, 8, 10, 6, 3…
#> $ numPrevOwners     <int> 8, 6, 8, 4, 7, 6, 9, 4, 3, 8, 8, 2, 9, 4, 5, 9, 9, 8…
#> $ made              <int> 2005, 2015, 2021, 2012, 1990, 2012, 1995, 2003, 2012…
#> $ isNewBuilt        <fct> 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1…
#> $ hasStormProtector <fct> 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1…
#> $ basement          <int> 4313, 3653, 2937, 659, 8435, 2009, 5930, 6326, 632, …
#> $ attic             <int> 9005, 2436, 8852, 7141, 2429, 4552, 9453, 4748, 5792…
#> $ garage            <int> 956, 128, 135, 359, 292, 757, 848, 654, 807, 591, 68…
#> $ hasStorageRoom    <fct> 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1…
#> $ hasGuestRoom      <int> 7, 2, 9, 3, 4, 1, 5, 10, 5, 3, 10, 9, 4, 0, 7, 5, 9,…
#> $ price             <dbl> 7559082, 8085990, 5574642, 3232561, 7055052, 3926647…

0.3 Pembuatan Model

0.3.1 Pemisahan Data Train dan Data Test

Pertama saya akan memisahkan data sebanyak 80% untuk digunakan dalam melatih model regresi linear, dan sisa 20% dari data tersebut akan digunakan untuk menguji prediksi model regresi linear yang kita buat nanti.

index <- sample(nrow(house), size = 0.8 * nrow(house))
h_train <- house[index,]
h_test <- house[-index,]

0.3.2 Membuat Model Regresi Linear

Dengan menggunakan fungsi dibawah berikut, kita akan melatih sebuah model regresi linear dan kemudian menyimpannya ke dalam variabel yang bernama h_lm, dalam kasus ini kita menggunakan semua prediktor untuk memprediksi “price”.

h_lm <- lm(price~ ., data = h_train)

summary(h_lm)
#> 
#> Call:
#> lm(formula = price ~ ., data = h_train)
#> 
#> Residuals:
#>     Min      1Q  Median      3Q     Max 
#> -7031.6 -1194.3     1.6  1191.3  6990.0 
#> 
#> Coefficients:
#>                        Estimate   Std. Error    t value             Pr(>|t|)
#> (Intercept)        6953.4521859 4540.7738863      1.531             0.125726
#> squareMeters         99.9998839    0.0007353 135992.631 < 0.0000000000000002
#> numberOfRooms         0.5328421    0.7353334      0.725             0.468702
#> hasYard1           3005.3725485   42.3398658     70.982 < 0.0000000000000002
#> hasPool1           2998.6705863   42.3406384     70.823 < 0.0000000000000002
#> floors               54.3020806    0.7307869     74.306 < 0.0000000000000002
#> cityCode             -0.0006563    0.0007314     -0.897             0.369529
#> cityPartRange        50.8214912    7.3430108      6.921     0.00000000000483
#> numPrevOwners        -5.9822412    7.4195645     -0.806             0.420106
#> made                 -3.3549948    2.2635523     -1.482             0.138332
#> isNewBuilt1         163.0616419   42.3430254      3.851             0.000119
#> hasStormProtector1  164.9213734   42.3181557      3.897     0.00009811610644
#> basement             -0.0021049    0.0073422     -0.287             0.774359
#> attic                -0.0018719    0.0073149     -0.256             0.798037
#> garage                0.1266406    0.0807322      1.569             0.116769
#> hasStorageRoom1      53.2120427   42.3618250      1.256             0.209105
#> hasGuestRoom         -2.6579644    6.6699515     -0.398             0.690274
#>                       
#> (Intercept)           
#> squareMeters       ***
#> numberOfRooms         
#> hasYard1           ***
#> hasPool1           ***
#> floors             ***
#> cityCode              
#> cityPartRange      ***
#> numPrevOwners         
#> made                  
#> isNewBuilt1        ***
#> hasStormProtector1 ***
#> basement              
#> attic                 
#> garage                
#> hasStorageRoom1       
#> hasGuestRoom          
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 1892 on 7983 degrees of freedom
#> Multiple R-squared:      1,  Adjusted R-squared:      1 
#> F-statistic: 1.158e+09 on 16 and 7983 DF,  p-value: < 0.00000000000000022

Dari summary di atas, dapat kita lihat bahwa terdapat beberapa variable yang berkolerasi kuat, diantaranya yaitu squareMeters, hasYard, hasPool, floors, CityPartRange, made, isNewBuilt, dan hasStormProtector. sedangkan sisanya tidak memberikan efek yang terlalu signifikan. Dari summary di atas juga menunjukan Adjusted R Square sebesar 1, ini artinya model ini dapat menjelaskan “price” sebaik 100%, ini adalah fenomena yang disebut “perfect fit” dan akan sangat jarang dijumpai jika dilakukan pada data yang sebenarnya, namun karena data yang kita gunakan adalah data yang dibuat oleh mesin untuk tujuan pembelajaran, maka Adj. R Square sebesar 1 bukanlah tidak mungkin dan cukup wajar.

0.4 Prediksi dan Evaluasi Model

0.4.1 Prediksi

Melakukan prediksi menggunakan data test (h_test) kemudian disimpan ke variabel h_pred

h_pred <- predict(object = h_lm, newdata = h_test %>% select(-price))

0.4.2 Evaluasi RMSE

Ini adalah RMSE pada data Train

RMSE(pred = h_lm$fitted.values, obs = h_train$price)
#> [1] 1889.793

Ini adalah RMSE pada data Test.

RMSE(pred = h_pred, obs = h_test$price)
#> [1] 1926.35

0.4.3 Linearity

h_res <- data.frame(residual = h_lm$residuals, fitted = h_lm$fitted.values)

h_res %>% ggplot(aes(fitted, residual)) + geom_point() + geom_smooth() + geom_hline(aes(yintercept = 0)) + 
    theme(panel.grid = element_blank(), panel.background = element_blank())

h_res

Dilihat dari plot di atas, model kita linear dengan sempurna.

0.4.4 Uji Normalitas

shapiro.test(h_lm$residuals[3:5000])
#> 
#>  Shapiro-Wilk normality test
#> 
#> data:  h_lm$residuals[3:5000]
#> W = 0.99842, p-value = 0.00006679

Statistik W (0.99845): Nilai statistik W yang mendekati 1 menunjukkan bahwa distribusi dari data yang diuji cenderung mendekati distribusi normal. p-value (0.00008117): Nilai p-value yang sangat rendah menunjukkan bahwa data memiliki bukti statistik yang cukup kuat untuk menolak hipotesis nol. Dalam konteks ini, hipotesis nol adalah bahwa data yang diuji memiliki distribusi normal.

0.4.5 Auto-Korelasi

durbinWatsonTest(h_lm)
#>  lag Autocorrelation D-W Statistic p-value
#>    1     0.008741072      1.982204   0.382
#>  Alternative hypothesis: rho != 0

D-W Statistic: Nilai D-W Statistic adalah 2.014816. Nilai D-W Statistic berkisar antara 0 dan 4. Nilai 2 adalah nilai tengah yang mengindikasikan bahwa tidak ada otokorelasi dalam data.p-value: Nilai p-value adalah 0.486. P-value ini digunakan untuk menguji apakah ada otokorelasi yang signifikan dalam data. Dalam hal ini, p-value yang tinggi (0.486) menunjukkan bahwa tidak ada bukti yang cukup untuk menyatakan adanya otokorelasi yang signifikan dalam data.

0.4.6 Multicollinearity

vif(h_lm)
#>      squareMeters     numberOfRooms           hasYard           hasPool 
#>          1.001772          1.003064          1.001409          1.001781 
#>            floors          cityCode     cityPartRange     numPrevOwners 
#>          1.002002          1.000866          1.001002          1.002255 
#>              made        isNewBuilt hasStormProtector          basement 
#>          1.000876          1.001829          1.000752          1.001605 
#>             attic            garage    hasStorageRoom      hasGuestRoom 
#>          1.001207          1.002788          1.002807          1.002945

Tidak ada vif yang bernilai di atas 10, artinya tidak ada hubungan yang kuat di antara variabel-variabel prediktor.

0.4.7 Heterocedasticity

bptest(h_lm)
#> 
#>  studentized Breusch-Pagan test
#> 
#> data:  h_lm
#> BP = 1305.9, df = 16, p-value < 0.00000000000000022

Nilai BP yang tinggi (1354.9) menunjukkan adanya indikasi kuat bahwa heteroskedastisitas mungkin terjadi dalam model regresi linear. p-value yang sangat rendah (< 0.00000000000000022), hampir mendekati nol. Hal ini mengindikasikan bahwa model memiliki bukti statistik yang sangat kuat untuk menolak hipotesis nol, yang berarti bahwa heteroskedastisitas ada dalam model regresi ini.

0.5 Kesimpulan

Menggunakan Root Mean Squared Error (RMSE) untuk mengevaluasi kinerja model. RMSE pada data pelatihan adalah sekitar 1883.283, sementara RMSE pada data uji adalah sekitar 1953.94. RMSE yang lebih rendah di data pelatihan menunjukkan kinerja model yang baik dalam mengikuti data pelatihan. Namun, perbedaan antara RMSE data pelatihan dan uji mungkin mengindikasikan sedikit overfitting. Grafik residual menunjukkan bahwa model cukup linear dengan residual yang tersebar merata di sepanjang garis horizontal nol. Uji Shapiro-Wilk menunjukkan bahwa data residual memiliki distribusi yang mendekati normal dengan nilai W mendekati 1. P-value yang rendah menunjukkan bukti statistik yang kuat untuk menolak hipotesis bahwa data residual tidak berdistribusi normal. Uji Durbin-Watson menunjukkan bahwa tidak ada bukti yang cukup kuat untuk menyatakan adanya otokorelasi yang signifikan dalam data residual. Tidak ada vif (variance inflation factor) yang bernilai di atas 10, menunjukkan bahwa tidak ada hubungan kuat antara variabel prediktor. Uji Breusch-Pagan menunjukkan adanya indikasi kuat bahwa heteroskedastisitas mungkin terjadi dalam model regresi linear. P-value yang sangat rendah mengindikasikan adanya heteroskedastisitas dalam model.

Model regresi linear memiliki nilai RMSE yang rendah, namun perbedaan antara RMSE data pelatihan dan uji menunjukkan adanya sedikit overfitting. Model cukup linear, distribusi residual mendekati normal, tidak ada otokorelasi yang signifikan, dan tidak ada multicollinearity yang signifikan. Namun, heteroskedastisitas terdeteksi dalam model, yang mungkin perlu diperbaiki untuk meningkatkan kualitas prediksi.