Install Packages

pacman::p_load(tidyverse,
               tidyquant,
               tidyr,
               caret,
               leaflet,
               rpart,
               class,
               DT,
               timetk,
               forcats,
               plotly,
               hrbrthemes,
               corrplot,
               tint,
               tufte,
               prettydoc,
               rmdformats,
               ggplot2,
               tseries,
               plotly)

Import Data

data <- read_csv("house_data.csv")
## Rows: 21613 Columns: 21
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl  (20): id, price, bedrooms, bathrooms, sqft_living, sqft_lot, floors, wa...
## dttm  (1): date
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(data, 5)
## # A tibble: 5 × 21
##           id date                 price bedrooms bathrooms sqft_living sqft_lot
##        <dbl> <dttm>               <dbl>    <dbl>     <dbl>       <dbl>    <dbl>
## 1 7129300520 2014-10-13 00:00:00 221900        3      1           1180     5650
## 2 6414100192 2014-12-09 00:00:00 538000        3      2.25        2570     7242
## 3 5631500400 2015-02-25 00:00:00 180000        2      1            770    10000
## 4 2487200875 2014-12-09 00:00:00 604000        4      3           1960     5000
## 5 1954400510 2015-02-18 00:00:00 510000        3      2           1680     8080
## # ℹ 14 more variables: floors <dbl>, waterfront <dbl>, view <dbl>,
## #   condition <dbl>, grade <dbl>, sqft_above <dbl>, sqft_basement <dbl>,
## #   yr_built <dbl>, yr_renovated <dbl>, zipcode <dbl>, lat <dbl>, long <dbl>,
## #   sqft_living15 <dbl>, sqft_lot15 <dbl>

Struktur Data

str(data)
## spc_tbl_ [21,613 × 21] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id           : num [1:21613] 7.13e+09 6.41e+09 5.63e+09 2.49e+09 1.95e+09 ...
##  $ date         : POSIXct[1:21613], format: "2014-10-13" "2014-12-09" ...
##  $ price        : num [1:21613] 221900 538000 180000 604000 510000 ...
##  $ bedrooms     : num [1:21613] 3 3 2 4 3 4 3 3 3 3 ...
##  $ bathrooms    : num [1:21613] 1 2.25 1 3 2 4.5 2.25 1.5 1 2.5 ...
##  $ sqft_living  : num [1:21613] 1180 2570 770 1960 1680 ...
##  $ sqft_lot     : num [1:21613] 5650 7242 10000 5000 8080 ...
##  $ floors       : num [1:21613] 1 2 1 1 1 1 2 1 1 2 ...
##  $ waterfront   : num [1:21613] 0 0 0 0 0 0 0 0 0 0 ...
##  $ view         : num [1:21613] 0 0 0 0 0 0 0 0 0 0 ...
##  $ condition    : num [1:21613] 3 3 3 5 3 3 3 3 3 3 ...
##  $ grade        : num [1:21613] 7 7 6 7 8 11 7 7 7 7 ...
##  $ sqft_above   : num [1:21613] 1180 2170 770 1050 1680 ...
##  $ sqft_basement: num [1:21613] 0 400 0 910 0 1530 0 0 730 0 ...
##  $ yr_built     : num [1:21613] 1955 1951 1933 1965 1987 ...
##  $ yr_renovated : num [1:21613] 0 1991 0 0 0 ...
##  $ zipcode      : num [1:21613] 98178 98125 98028 98136 98074 ...
##  $ lat          : num [1:21613] 47.5 47.7 47.7 47.5 47.6 ...
##  $ long         : num [1:21613] -122 -122 -122 -122 -122 ...
##  $ sqft_living15: num [1:21613] 1340 1690 2720 1360 1800 ...
##  $ sqft_lot15   : num [1:21613] 5650 7639 8062 5000 7503 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   id = col_double(),
##   ..   date = col_datetime(format = ""),
##   ..   price = col_double(),
##   ..   bedrooms = col_double(),
##   ..   bathrooms = col_double(),
##   ..   sqft_living = col_double(),
##   ..   sqft_lot = col_double(),
##   ..   floors = col_double(),
##   ..   waterfront = col_double(),
##   ..   view = col_double(),
##   ..   condition = col_double(),
##   ..   grade = col_double(),
##   ..   sqft_above = col_double(),
##   ..   sqft_basement = col_double(),
##   ..   yr_built = col_double(),
##   ..   yr_renovated = col_double(),
##   ..   zipcode = col_double(),
##   ..   lat = col_double(),
##   ..   long = col_double(),
##   ..   sqft_living15 = col_double(),
##   ..   sqft_lot15 = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
summary(data)
##        id                 date                            price        
##  Min.   :1.000e+06   Min.   :2014-05-02 00:00:00.00   Min.   :  75000  
##  1st Qu.:2.123e+09   1st Qu.:2014-07-22 00:00:00.00   1st Qu.: 321950  
##  Median :3.905e+09   Median :2014-10-16 00:00:00.00   Median : 450000  
##  Mean   :4.580e+09   Mean   :2014-10-29 04:38:01.96   Mean   : 540088  
##  3rd Qu.:7.309e+09   3rd Qu.:2015-02-17 00:00:00.00   3rd Qu.: 645000  
##  Max.   :9.900e+09   Max.   :2015-05-27 00:00:00.00   Max.   :7700000  
##     bedrooms        bathrooms      sqft_living       sqft_lot      
##  Min.   : 0.000   Min.   :0.000   Min.   :  290   Min.   :    520  
##  1st Qu.: 3.000   1st Qu.:1.750   1st Qu.: 1427   1st Qu.:   5040  
##  Median : 3.000   Median :2.250   Median : 1910   Median :   7618  
##  Mean   : 3.371   Mean   :2.115   Mean   : 2080   Mean   :  15107  
##  3rd Qu.: 4.000   3rd Qu.:2.500   3rd Qu.: 2550   3rd Qu.:  10688  
##  Max.   :33.000   Max.   :8.000   Max.   :13540   Max.   :1651359  
##      floors        waterfront            view          condition    
##  Min.   :1.000   Min.   :0.000000   Min.   :0.0000   Min.   :1.000  
##  1st Qu.:1.000   1st Qu.:0.000000   1st Qu.:0.0000   1st Qu.:3.000  
##  Median :1.500   Median :0.000000   Median :0.0000   Median :3.000  
##  Mean   :1.494   Mean   :0.007542   Mean   :0.2343   Mean   :3.409  
##  3rd Qu.:2.000   3rd Qu.:0.000000   3rd Qu.:0.0000   3rd Qu.:4.000  
##  Max.   :3.500   Max.   :1.000000   Max.   :4.0000   Max.   :5.000  
##      grade          sqft_above   sqft_basement       yr_built   
##  Min.   : 1.000   Min.   : 290   Min.   :   0.0   Min.   :1900  
##  1st Qu.: 7.000   1st Qu.:1190   1st Qu.:   0.0   1st Qu.:1951  
##  Median : 7.000   Median :1560   Median :   0.0   Median :1975  
##  Mean   : 7.657   Mean   :1788   Mean   : 291.5   Mean   :1971  
##  3rd Qu.: 8.000   3rd Qu.:2210   3rd Qu.: 560.0   3rd Qu.:1997  
##  Max.   :13.000   Max.   :9410   Max.   :4820.0   Max.   :2015  
##   yr_renovated       zipcode           lat             long       
##  Min.   :   0.0   Min.   :98001   Min.   :47.16   Min.   :-122.5  
##  1st Qu.:   0.0   1st Qu.:98033   1st Qu.:47.47   1st Qu.:-122.3  
##  Median :   0.0   Median :98065   Median :47.57   Median :-122.2  
##  Mean   :  84.4   Mean   :98078   Mean   :47.56   Mean   :-122.2  
##  3rd Qu.:   0.0   3rd Qu.:98118   3rd Qu.:47.68   3rd Qu.:-122.1  
##  Max.   :2015.0   Max.   :98199   Max.   :47.78   Max.   :-121.3  
##  sqft_living15    sqft_lot15    
##  Min.   : 399   Min.   :   651  
##  1st Qu.:1490   1st Qu.:  5100  
##  Median :1840   Median :  7620  
##  Mean   :1987   Mean   : 12768  
##  3rd Qu.:2360   3rd Qu.: 10083  
##  Max.   :6210   Max.   :871200

Informasi yang di dapat terdiri dari 21 variabel yang terdiri dari ID properti, tanggal penjualan, harga properti, jumlah kamar tidur, jumlah kamar mandi, luas ruang hidup, luas lahan, jumlah lantai, keberadaan waterfront (pantai atau tepi danau), pemandangan, kondisi properti, tingkat kualitas bangunan (grade), luas di atas tanah (sqft_above), luas di bawah tanah (sqft_basement), tahun pembangunan, tahun renovasi, kode pos, latitude dan longitude, serta luas ruang hidup (sqft_living15) dan luas lahan (sqft_lot15).

Exploratory Data Analysis

Korelasi Variabel

correlation_matrix <- cor(data %>% select(price, bedrooms, bathrooms, sqft_living, sqft_lot, floors, view, condition, grade, sqft_above, sqft_basement, yr_built, yr_renovated, lat, long, sqft_living15, sqft_lot15))
print(correlation_matrix)
##                    price    bedrooms   bathrooms sqft_living     sqft_lot
## price         1.00000000  0.30834960  0.52513751  0.70203505  0.089660861
## bedrooms      0.30834960  1.00000000  0.51588364  0.57667069  0.031703243
## bathrooms     0.52513751  0.51588364  1.00000000  0.75466528  0.087739662
## sqft_living   0.70203505  0.57667069  0.75466528  1.00000000  0.172825661
## sqft_lot      0.08966086  0.03170324  0.08773966  0.17282566  1.000000000
## floors        0.25679389  0.17542894  0.50065317  0.35394929 -0.005200991
## view          0.39729349  0.07953185  0.18773702  0.28461119  0.074710106
## condition     0.03636179  0.02847210 -0.12498193 -0.05875259 -0.008958250
## grade         0.66743426  0.35696673  0.66498253  0.76270448  0.113621124
## sqft_above    0.60556730  0.47760016  0.68534248  0.87659660  0.183512281
## sqft_basement 0.32381602  0.30309338  0.28377003  0.43504297  0.015286202
## yr_built      0.05401153  0.15417807  0.50601944  0.31804877  0.053080367
## yr_renovated  0.12643379  0.01884082  0.05073898  0.05536293  0.007643505
## lat           0.30700348 -0.00893101  0.02457295  0.05252946 -0.085682788
## long          0.02162624  0.12947298  0.22304184  0.24022330  0.229520859
## sqft_living15 0.58537890  0.39163752  0.56863429  0.75642026  0.144608174
## sqft_lot15    0.08244715  0.02924422  0.08717536  0.18328555  0.718556752
##                     floors         view    condition       grade    sqft_above
## price          0.256793888  0.397293488  0.036361789  0.66743426  0.6055672984
## bedrooms       0.175428935  0.079531852  0.028472104  0.35696673  0.4776001614
## bathrooms      0.500653173  0.187737024 -0.124981933  0.66498253  0.6853424759
## sqft_living    0.353949290  0.284611186 -0.058752587  0.76270448  0.8765965987
## sqft_lot      -0.005200991  0.074710106 -0.008958250  0.11362112  0.1835122809
## floors         1.000000000  0.029443820 -0.263767946  0.45818251  0.5238847103
## view           0.029443820  1.000000000  0.045989737  0.25132058  0.1676493441
## condition     -0.263767946  0.045989737  1.000000000 -0.14467367 -0.1582136164
## grade          0.458182514  0.251320585 -0.144673671  1.00000000  0.7559229376
## sqft_above     0.523884710  0.167649344 -0.158213616  0.75592294  1.0000000000
## sqft_basement -0.245704542  0.276946579  0.174104914  0.16839182 -0.0519433068
## yr_built       0.489319425 -0.053439851 -0.361416562  0.44696320  0.4238983517
## yr_renovated   0.006338401  0.103917288 -0.060617787  0.01441428  0.0232846879
## lat            0.049614131  0.006156732 -0.014941006  0.11408406 -0.0008164986
## long           0.125419028 -0.078399712 -0.106500448  0.19837215  0.3438030175
## sqft_living15  0.279885265  0.280439082 -0.092824268  0.71320209  0.7318702924
## sqft_lot15    -0.011269187  0.072574568 -0.003405523  0.11924790  0.1940498619
##               sqft_basement    yr_built yr_renovated           lat        long
## price            0.32381602  0.05401153  0.126433793  0.3070034800  0.02162624
## bedrooms         0.30309338  0.15417807  0.018840823 -0.0089310097  0.12947298
## bathrooms        0.28377003  0.50601944  0.050738978  0.0245729528  0.22304184
## sqft_living      0.43504297  0.31804877  0.055362927  0.0525294622  0.24022330
## sqft_lot         0.01528620  0.05308037  0.007643505 -0.0856827882  0.22952086
## floors          -0.24570454  0.48931942  0.006338401  0.0496141310  0.12541903
## view             0.27694658 -0.05343985  0.103917288  0.0061567321 -0.07839971
## condition        0.17410491 -0.36141656 -0.060617787 -0.0149410064 -0.10650045
## grade            0.16839182  0.44696320  0.014414281  0.1140840571  0.19837215
## sqft_above      -0.05194331  0.42389835  0.023284688 -0.0008164986  0.34380302
## sqft_basement    1.00000000 -0.13312410  0.071322902  0.1105379580 -0.14476477
## yr_built        -0.13312410  1.00000000 -0.224873518 -0.1481224021  0.40935620
## yr_renovated     0.07132290 -0.22487352  1.000000000  0.0293976092 -0.06837237
## lat              0.11053796 -0.14812240  0.029397609  1.0000000000 -0.13551178
## long            -0.14476477  0.40935620 -0.068372369 -0.1355117836  1.00000000
## sqft_living15    0.20035498  0.32622890 -0.002672555  0.0488579321  0.33460498
## sqft_lot15       0.01727618  0.07095793  0.007853765 -0.0864188072  0.25445129
##               sqft_living15   sqft_lot15
## price           0.585378904  0.082447153
## bedrooms        0.391637524  0.029244224
## bathrooms       0.568634290  0.087175361
## sqft_living     0.756420259  0.183285551
## sqft_lot        0.144608174  0.718556752
## floors          0.279885265 -0.011269187
## view            0.280439082  0.072574568
## condition      -0.092824268 -0.003405523
## grade           0.713202093  0.119247897
## sqft_above      0.731870292  0.194049862
## sqft_basement   0.200354983  0.017276181
## yr_built        0.326228900  0.070957926
## yr_renovated   -0.002672555  0.007853765
## lat             0.048857932 -0.086418807
## long            0.334604984  0.254451288
## sqft_living15   1.000000000  0.183191749
## sqft_lot15      0.183191749  1.000000000
corrplot::corrplot(correlation_matrix, method = "circle", type = "upper")

Variabel price memiliki korelasi yang kuat dengan sqft_living (0.585) dan bathrooms (0.569), menunjukkan bahwa ukuran ruang hidup dan jumlah kamar mandi merupakan faktor penting yang mempengaruhi harga properti. grade juga memiliki korelasi tinggi dengan price (0.713), menandakan bahwa kualitas properti juga berpengaruh saat penentuan harga. Variabel sqft_living15 memiliki korelasi moderat dengan price (0.200), menunjukkan hubungan dengan ukuran ruang hidup di properti sekitar. Dari plot ini bisa disimpulkan bisa melihat hubungan antara variabel.

Distribusi Harga

ggplot(data, aes(x = price)) +
  geom_histogram(binwidth = 50000, fill = "blue", color = "grey") +
  labs(title = "Distribusi Harga", x = "Harga", y = "Frekuensi") +
  theme_minimal()

Pembuatan gambaran distribusi harga properti menggunakan histogram menggambarkan cara harga-harga tersebut tersebar di dalam set data. Dengan melihat histogram ini, kita dapat mengetahui apakah distribusi harga properti cenderung normal, miring ke arah tertentu, atau apakah terdapat beberapa puncak (bimodal atau multimodal). Visualisasi ini memberikan gambaran awal mengenai variasi harga properti dalam set data dan membantu dalam mengidentifikasi kecenderungan atau pola tertentu yang mungkin perlu diteliti lebih lanjut untuk analisis yang lebih mendalam.

Hubungan Harga dengan Luas Rumah

ggplot(data, aes(x = sqft_living, y = price)) +
  geom_point(alpha = 0.5, color = "red") +
  labs(title = "Harga vs Luas Rumah", x = "Luas Rumah", y = "Harga") +
  theme_minimal()

Dari grafik, terlihat bahwa sebagian besar rumah memiliki luas di rentang 0 sampai 5000, dan dapat disimpulkan bahwa ada hubungan antara luas rumah dan harga. Ketika luas rumah meningkat, harga juga cenderung meningkat secara signifikan.

Harga Rumah Berdasarkan Jumlah Kamar Tidur

ggplot(data, aes(x = factor(bedrooms), y = price)) +
    geom_boxplot(fill = "lightblue") +
    labs(title = "Distribusi Harga Berdasarkan Jumlah Kamar Tidur", x = "Jumlah Kamar Tidur", y = "Harga") +
    theme_minimal()

Dari grafik tersebut diketahui bahwa semakin banyak kamar, berpengaruh terhadap kenaikan harga rumah.

Rata-rata Harga Rumah

data$date <- as.Date(data$date)

monthly_avg_price <- data %>%
    group_by(month = format(date, "%Y-%m")) %>%
    summarise(avg_price = mean(price))

monthly_avg_price$month <- as.Date(paste0(monthly_avg_price$month, "-01"))

ggplot(monthly_avg_price, aes(x = month, y = avg_price)) +
    geom_line(color = "blue") +
    labs(title = "Tren Harga Rata-rata Bulanan Properti", x = "Bulan", y = "Harga Rata-rata") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

Grafik di atas menunjukkan tren harga rumah, dengan terlihat adanya lonjakan harga pada bulan April 2015.

Data Preprocessing

missing_data <- sapply(data, function(x) sum(is.na(x)))
print(missing_data)
##            id          date         price      bedrooms     bathrooms 
##             0             0             0             0             0 
##   sqft_living      sqft_lot        floors    waterfront          view 
##             0             0             0             0             0 
##     condition         grade    sqft_above sqft_basement      yr_built 
##             0             0             0             0             0 
##  yr_renovated       zipcode           lat          long sqft_living15 
##             0             0             0             0             0 
##    sqft_lot15 
##             0

Dari hasil di atas variabel-variabel di atas tidak memiliki nilai yang hilang (missing values). Artinya, data tersebut lengkap dan tidak ada data yang hilang sehingga tidak memerlukan tindakan untuk menangani data yang hilang. Hal ini menandakan bahwa dataset tersebut dapat digunakan untuk analisis lebih lanjut tanpa perlu melakukan imputasi atau penghapusan baris yang mengandung nilai yang hilang.

Membangun Model Sederhana

set.seed(123)
train_index <- createDataPartition(data$price, p = 0.8, list = FALSE)
train_data <- data[train_index, ]
test_data <- data[-train_index, ]

model1 <- train(price ~ ., data = train_data, method = "lm", trControl = trainControl(method = "cv", number = 10))

train_limited_model <- function(data, formula, method = "lm", max_features = 3) {
    fit <- train(formula, data = data, method = method, trControl = trainControl(method = "cv", number = 10))
    return(fit)
}


model2_formula <- as.formula("price ~ bedrooms + bathrooms + sqft_living")
model2 <- train_limited_model(train_data, model2_formula)


model3_formula <- as.formula("price ~ sqft_lot + floors + view")
model3 <- train_limited_model(train_data, model3_formula)


model4_formula <- as.formula("price ~ condition + grade + sqft_above")
model4 <- train_limited_model(train_data, model4_formula)

model5_formula <- as.formula("price ~ yr_built + yr_renovated + zipcode")
model5 <- train_limited_model(train_data, model5_formula)

results <- list(
    model1 = model1,
    model2 = model2,
    model3 = model3,
    model4 = model4,
    model5 = model5
)

Koding ini mengembangkan lima model regresi linear untuk meramalkan harga properti berdasarkan data latihan yang dipisahkan dari dataset utama dengan rasio 80-20. Model pertama menggunakan semua variabel independen sebagai prediktor, sedangkan model-model berikutnya menggunakan kombinasi maksimal tiga variabel independen yang dianggap memiliki potensi pengaruh terhadap harga properti. Setiap model dilatih menggunakan validasi silang dengan 10 lipatan untuk mengevaluasi kinerja dan mencegah overfitting. Penelitian ini bertujuan untuk membandingkan performa model-model yang dibangun dengan berbagai kombinasi variabel dalam memprediksi harga properti, untuk menentukan model terbaik dalam hal akurasi dan kompleksitas.

Model Evaluation

results_df <- data.frame(
    Model = c("Model 1", "Model 2", "Model 3", "Model 4", "Model 5"),
    RMSE = c(199283.5, 256001.3, 319103.2, 257411.5, 358359.4),
    Rsquared = c(0.6991357, 0.5026754, 0.2255492, 0.4967233, 0.02341441))

ggplot(results_df, aes(x = Model, y = RMSE, fill = Model)) +
    geom_bar(stat = "identity", position = position_dodge()) +
    labs(title = "Perbandingan RMSE Model", x = "Model", y = "RMSE") +
    theme_minimal() +
    scale_fill_brewer(palette = "Set1") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

Berdasarkan hasil di atas diketahui bahwa model 1 memiliki RMSE yang lebih rendah dibandingkan dengan model yang lainnya

ggplot(results_df, aes(x = Model, y = Rsquared, fill = Model)) +
    geom_bar(stat = "identity", position = position_dodge()) +
    labs(title = "Perbandingan R-squared Model", x = "Model", y = "R-squared") +
    theme_minimal() +
    scale_fill_brewer(palette = "Set1") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

  Berkaitan dengan Nilai RMSE yang sudah dibandingkan dari seluruh model, dengan menggunakan acuan R-squareed juga diketahui bahwa model1 yang menjadi model dengan R-Squared tertinggi.

Kesimpulan

Dari lima model yang dikembangkan, model pertama (model1) menunjukkan kinerja terbaik dengan nilai RMSE terendah (199283.5), nilai R-squared tertinggi (0.6991357), dan nilai MAE terendah (125940). Hal ini mengindikasikan bahwa model pertama, yang menggunakan 20 variabel independen, memberikan prediksi yang lebih akurat daripada model-model lainnya. Dengan mempertimbangkan semua variabel independen yang tersedia, model ini mampu memberikan prediksi yang lebih mendekati harga sebenarnya dan memiliki kemampuan penjelasan yang lebih baik.