Tahap 1 : Pendahuluan

1. Business Problem

Sebagai seorang data scientist, melakukan klasifikasi data menjadi bagian dari kemampuan dalam melakukan pengolahan data. Ada banyak metode klasifikasi data salah satunya metode Regresi Logistik. Metode ini mampu melakukan klasifikasi terhadap variable-variable numerik karena bagian dari metode regresi.Kemampuan metode tersebut menjadikannya cocok untuk di implementasikan pada dataset yang akan digunakan dalam project. Berikut permasalahan yang coba diselesaikan dalam project ini :

  1. Project ini melakukan prediksi menggunakan dataset varibel yang mayoritas bertipe numerik. Namun, melakukan feature engineering untuk membuat kolom baru yang akan dijadikan sebagai target. Target tersebut merupakan klasifikasi harga suatu rumah. Penentuan kelas positif = TRUE (harga rumah diatas 20000 USD) dan kelas negatif (harga rumah kurang dari 20000 USD). Pembuatan model regresi dilakukan dengan 2 model yaitu model base (menggunakan seluruh prediktor) dan model stepwise kemudian kedua model tersebut dibandingkan dan dipilih yang paling sesuai. model terpilih akan dilakukan prediksi dan evaluasi.

  2. Hasil evalusasi yang diperoleh dari model regresi logistik akan dibandingkan dengan model K-NN berdasarkan metrics evaluasinya.

2. Dataset

  • Dataset boston adalah informasi yang dikumpulkan oleh US Census Service terkait dengan harga perumahan dan informasi penunjang di area kawasan perumahan. Ukuran dataset relatif kecil hanya terdiri dari 14 kolom dan 506 baris.

  • Dataset ini dapat diunduh melalui https://www.kaggle.com/datasets/vikrishnan/boston-house-prices

Tahap 2 : Pembacaan dan Pemahaman Data

Tahapan ini adalah melakukan pembacaan data dan memahami data. Pada tahapan ini ditunjukan cara membaca data kemudian di simpan di dalam objek dan ditampilkan secara tabular. Kemudian diketahui informasi tiap kolom data, lalu tiap baris data di dataset.

1.Pembacaan Data

Tahapan ini adalah melakukan pembacaan data menggunakan fungsi base pada R yaitu read.csv() karena file dataset dalam project ini menggunakan file berformat csv. Kemudian menggunakan fungsi head() untuk melihat cuplikan data. Selanjutnya data dimasukan ke dalam objek yang diberi nama boston.

boston <- read.csv('HousingData.csv')
head(boston, n=3)  # menggunakan 3 data teratas 
##      CRIM ZN INDUS CHAS   NOX    RM  AGE    DIS RAD TAX PTRATIO      B LSTAT
## 1 0.00632 18  2.31    0 0.538 6.575 65.2 4.0900   1 296    15.3 396.90  4.98
## 2 0.02731  0  7.07    0 0.469 6.421 78.9 4.9671   2 242    17.8 396.90  9.14
## 3 0.02729  0  7.07    0 0.469 7.185 61.1 4.9671   2 242    17.8 392.83  4.03
##   MEDV
## 1 24.0
## 2 21.6
## 3 34.7

2.Pemahaman Data

1. Informasi mengenai setiap kolom

Dalam setiap kolomya diketahui informasi,

  • CRIM = per capita crime rate by town
  • ZN = proportion of residential land zoned for lots over 25,000 sq.ft.
  • INDUS = proportion of non-retail business acres per town.
  • CHAS = Charles River dummy variable (1 if tract bounds river; 0 otherwise)
  • NOX = nitric oxides concentration (parts per 10 million)
  • RM = average number of rooms per dwelling
  • AGE = proportion of owner-occupied units built prior to 1940
  • DIS = weighted distances to five Boston employment centres
  • RAD = index of accessibility to radial highways
  • TAX = full-value property-tax rate per $10,000
  • PTRATIO = pupil-teacher ratio by town
  • B = - 1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
  • LSTAT = % lower status of the population
  • MEDV = Median value of owner-occupied homes in $1000’s

2. Pengamatan yang diperoleh dari dataset

Dalam setiap barisnya, dataset ini terdiri dari informasi harga rumah di wilayah Boston MEDV, dilengkapi dengan data pelengkap yaitu data sekitar kawasan perumahan, data tarif pajak, data pendidikan dan ras yang tinggal di kawasan perumahan tersebut.

Tahap 3 : Pembersihan Data

1. Feature Engineering

Dalam dataset ini akan dilakukan klasifikasi data harga rumah yang ada di dalam variable MEDV, untuk itu akan dilakukan pembuatan kolom baru bernama class dimana akan bernilai False apabila berada dibawah 20000 USD dan class bernilai TRUE apabila lebih besar atau sama dengan 20000 USD. Setelah kolom baru terbentuk, kolom yang memberikan informasi harga rumah MEDV akan dihapus karena tidak digunakan.

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
boston <- boston |> 
  mutate(
  class = as.factor(ifelse(boston$MEDV > 20,'TRUE','FALSE'))) |> 
  select(-MEDV)

2. Cek Kesesuaian Tipe data

Tahap ini melakukan pemeriksaan tipe data. Apakah tipe dataset yang telah disimpan sesuai ? untuk itu lihat struktur data dengan menggunakan fungsi glimpse yang merupakan fungsi dari library dplyr, dimana fungsi ini memiliki kemampuan yang cepat dan tampilan yang lebih rapi dibandingkan fungsi base R.

glimpse(boston)
## Rows: 506
## Columns: 14
## $ CRIM    <dbl> 0.00632, 0.02731, 0.02729, 0.03237, 0.06905, 0.02985, 0.08829,…
## $ ZN      <dbl> 18.0, 0.0, 0.0, 0.0, 0.0, 0.0, 12.5, 12.5, 12.5, 12.5, 12.5, 1…
## $ INDUS   <dbl> 2.31, 7.07, 7.07, 2.18, 2.18, 2.18, 7.87, 7.87, 7.87, 7.87, 7.…
## $ CHAS    <int> 0, 0, 0, 0, 0, 0, NA, 0, 0, NA, 0, 0, 0, 0, NA, 0, 0, 0, 0, 0,…
## $ NOX     <dbl> 0.538, 0.469, 0.469, 0.458, 0.458, 0.458, 0.524, 0.524, 0.524,…
## $ RM      <dbl> 6.575, 6.421, 7.185, 6.998, 7.147, 6.430, 6.012, 6.172, 5.631,…
## $ AGE     <dbl> 65.2, 78.9, 61.1, 45.8, 54.2, 58.7, 66.6, 96.1, 100.0, 85.9, 9…
## $ DIS     <dbl> 4.0900, 4.9671, 4.9671, 6.0622, 6.0622, 6.0622, 5.5605, 5.9505…
## $ RAD     <int> 1, 2, 2, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,…
## $ TAX     <int> 296, 242, 242, 222, 222, 222, 311, 311, 311, 311, 311, 311, 31…
## $ PTRATIO <dbl> 15.3, 17.8, 17.8, 18.7, 18.7, 18.7, 15.2, 15.2, 15.2, 15.2, 15…
## $ B       <dbl> 396.90, 396.90, 392.83, 394.63, 396.90, 394.12, 395.60, 396.90…
## $ LSTAT   <dbl> 4.98, 9.14, 4.03, 2.94, NA, 5.21, 12.43, 19.15, 29.93, 17.10, …
## $ class   <fct> TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, …

insight :
1. seluruh data bertipe numerik
2. dataset terdiri dari 506 baris dan 14 kolom

Agar semakin representatif, maka kita perlu melihat masing-masing nilai unique(berbeda) dalam tiap kolomnya. Gunakan fungsi n_distinct untuk melihat keseluruhan data.

sapply(boston, n_distinct)
##    CRIM      ZN   INDUS    CHAS     NOX      RM     AGE     DIS     RAD     TAX 
##     485      27      77       3      81     446     349     412       9      66 
## PTRATIO       B   LSTAT   class 
##      46     357     439       2

insight :
1. terdapat dua kolom yang memiliki unique sedikit yaitu kolom CHAS dan kolom RAD
2. mayoritas kolom umumnnya memiliki nilai unique puluhan hingga ratusan

Dari insight yang diperoleh diatas, tipe data kolom CHAS akan di ubah menjadi tipe data factor karena kolom tersebut jika dilihat dari informasi kolom yang ada merupakan data biner. Sementara untuk data kolom RAD diubah karena mengacu pada informasi kolom yang merupakan nilai indeks. Ubah tipe data dapat dilakukan dengan menggunakan fungsi mutate() yang merupakan fungsi untuk memanipulasi data salah satunya ubah tipe data yang berasal dari library dplyr. Jangan lupa masukan ke dalam variable setelah ubah tipe data.

boston <- boston |> 
  mutate(
    
    CHAS = as.factor(CHAS),
    RAD = as.factor(RAD)
    
  )

3. Mengatasi Missing Value

Tahapan ini adalah melakukan cek missing value atau data NA. Dimana data tersebut akan dihapus jika terdapat pada dataset dikarenakan data missing value mampu menjadikan data tidak sesuai/ tidak representatif. Untuk mendeteksi apakah suatu dataset terdapat missing value gunakan fungsi anyNA(), dimana apabila hasilnya TRUE menunjukan bahwa dalam suatu dataset terdapat missing value.

anyNA(boston)
## [1] TRUE

Hasil diatas menunjukan adanya missing value pada dataset boston.Untuk itu kita lakukan inspeksi lebih lanjut untuk mengetahui seberapa banyak data misssing value ini.

colSums(is.na(boston)) # digunakan untuk melihat sebaran missing value pada masing-masing kolom
##    CRIM      ZN   INDUS    CHAS     NOX      RM     AGE     DIS     RAD     TAX 
##      20      20      20      20       0       0      20       0       0       0 
## PTRATIO       B   LSTAT   class 
##       0       0      20       0
dim(na.omit(boston)) #melihat dataset apabila missing value dihilangkan
## [1] 394  14

dari nilai diatas diketahui, apabila missing value dihapus maka akan menghapus lebih dari 20% data. (506-394)/506. Karena terlalu banyak data yang hilang jika dihapus maka, akan dilakukan imputasi atau memasukan nilai missing value menggunakan nilai mean. Nilai mean dipilih karena dapat mendeskripsikan keseluruhan nilai dalam dataset.

#Proses Imputasi mean
boston$CRIM <- ifelse(is.na(boston$CRIM),
                      ave(boston$CRIM, FUN = function(x) mean(x, na.rm = T)), boston$CRIM)

boston$ZN <- ifelse(is.na(boston$ZN),
                      ave(boston$ZN, FUN = function(x) mean(x, na.rm = T)), boston$ZN)

boston$INDUS <- ifelse(is.na(boston$INDUS),
                      ave(boston$INDUS, FUN = function(x) mean(x, na.rm = T)), boston$INDUS)

boston$AGE <- ifelse(is.na(boston$AGE),
                      ave(boston$AGE, FUN = function(x) mean(x, na.rm = T)), boston$AGE)

boston$LSTAT <- ifelse(is.na(boston$LSTAT),
                      ave(boston$LSTAT, FUN = function(x) mean(x, na.rm = T)), boston$LSTAT)

Lakukan kembali periksa data missing value

colSums(is.na(boston))
##    CRIM      ZN   INDUS    CHAS     NOX      RM     AGE     DIS     RAD     TAX 
##       0       0       0      20       0       0       0       0       0       0 
## PTRATIO       B   LSTAT   class 
##       0       0       0       0

Dari proses imputasi yang sudah dilakukan, diketahui bahwa data factor tidak dapat dilakukan imputasi. Untuk itu missing value yang ada di kolom CHAS akan dihapuskan karena memiliki persentase yang kecil dibandingkan total data

boston <- na.omit(boston)
colSums(is.na(boston))
##    CRIM      ZN   INDUS    CHAS     NOX      RM     AGE     DIS     RAD     TAX 
##       0       0       0       0       0       0       0       0       0       0 
## PTRATIO       B   LSTAT   class 
##       0       0       0       0

4. Menghapus Data duplikat

melakukan penghapusan data yang sama jika ada. data dihapus karena akan memperkecil variasi data. Menghapus data duplikat dapat menggunakan fungsi distinct() yang terdapat pada library dplyr

boston <-  boston |>
  distinct()

5. Cek Kembali Structure Data

memastikan kembali kesesuaian tipe data. Hal ini penting untuk menghindari code yang belum dimasukan ke dalam objek sehingga tidak terjadi pernyimpanan hasil pengoalahan.

glimpse(boston)
## Rows: 486
## Columns: 14
## $ CRIM    <dbl> 0.00632, 0.02731, 0.02729, 0.03237, 0.06905, 0.02985, 0.14455,…
## $ ZN      <dbl> 18.0, 0.0, 0.0, 0.0, 0.0, 0.0, 12.5, 12.5, 12.5, 12.5, 12.5, 0…
## $ INDUS   <dbl> 2.31, 7.07, 7.07, 2.18, 2.18, 2.18, 7.87, 7.87, 7.87, 7.87, 7.…
## $ CHAS    <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ NOX     <dbl> 0.538, 0.469, 0.469, 0.458, 0.458, 0.458, 0.524, 0.524, 0.524,…
## $ RM      <dbl> 6.575, 6.421, 7.185, 6.998, 7.147, 6.430, 6.172, 5.631, 6.377,…
## $ AGE     <dbl> 65.2, 78.9, 61.1, 45.8, 54.2, 58.7, 96.1, 100.0, 94.3, 82.9, 3…
## $ DIS     <dbl> 4.0900, 4.9671, 4.9671, 6.0622, 6.0622, 6.0622, 5.9505, 6.0821…
## $ RAD     <fct> 1, 2, 2, 3, 3, 3, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,…
## $ TAX     <int> 296, 242, 242, 222, 222, 222, 311, 311, 311, 311, 311, 307, 30…
## $ PTRATIO <dbl> 15.3, 17.8, 17.8, 18.7, 18.7, 18.7, 15.2, 15.2, 15.2, 15.2, 15…
## $ B       <dbl> 396.90, 396.90, 392.83, 394.63, 396.90, 394.12, 396.90, 386.63…
## $ LSTAT   <dbl> 4.98000, 9.14000, 4.03000, 2.94000, 12.71543, 5.21000, 19.1500…
## $ class   <fct> TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,…

Tahap 4 : Analisis Data Eksploratif

Dikarenakan metode yang digunakan adalah regresi logistik. maka tahapan ini akan melakukan eksplorasi data yang menjadi target dengan seluruh prediktornya sehingga diharapkan dapat diketahui hubungan antara variable. Untuk menemukan hal tersebut dalam tahapan ini dilakukan cek data sebaran dan cek imbalance data.

1. Cek Sebaran Data

Untuk cek sebaran data gunakan fungsi summary() yang mampu memberikan nilai 5 summary number pada data numerik dan frekuensi tiap data pada factor.

summary(boston)
##       CRIM                ZN             INDUS        CHAS         NOX        
##  Min.   : 0.00632   Min.   :  0.00   Min.   : 0.460   0:452   Min.   :0.3850  
##  1st Qu.: 0.08227   1st Qu.:  0.00   1st Qu.: 5.190   1: 34   1st Qu.:0.4490  
##  Median : 0.28958   Median :  0.00   Median : 9.795           Median :0.5380  
##  Mean   : 3.56209   Mean   : 11.35   Mean   :10.990           Mean   :0.5537  
##  3rd Qu.: 3.61187   3rd Qu.: 11.21   3rd Qu.:18.100           3rd Qu.:0.6240  
##  Max.   :88.97620   Max.   :100.00   Max.   :27.740           Max.   :0.8710  
##                                                                               
##        RM             AGE              DIS              RAD     
##  Min.   :3.561   Min.   :  2.90   Min.   : 1.130   24     :123  
##  1st Qu.:5.887   1st Qu.: 45.73   1st Qu.: 2.104   5      :112  
##  Median :6.209   Median : 74.35   Median : 3.207   4      :107  
##  Mean   :6.297   Mean   : 68.36   Mean   : 3.789   3      : 37  
##  3rd Qu.:6.628   3rd Qu.: 93.60   3rd Qu.: 5.118   2      : 24  
##  Max.   :8.780   Max.   :100.00   Max.   :12.127   6      : 24  
##                                                    (Other): 59  
##       TAX           PTRATIO            B              LSTAT          class    
##  Min.   :187.0   Min.   :12.60   Min.   :  2.52   Min.   : 1.730   FALSE:204  
##  1st Qu.:277.5   1st Qu.:17.40   1st Qu.:375.61   1st Qu.: 7.183   TRUE :282  
##  Median :330.0   Median :19.00   Median :391.57   Median :11.730              
##  Mean   :405.5   Mean   :18.45   Mean   :356.89   Mean   :12.671              
##  3rd Qu.:666.0   3rd Qu.:20.20   3rd Qu.:396.30   3rd Qu.:16.500              
##  Max.   :711.0   Max.   :22.00   Max.   :396.90   Max.   :37.970              
## 

insight:
- harga rumah diatas 20000 USD lebih banyak dibandingkan harga rumah yang kurang dari 20000 USD

2. Cek Imbalance Class

melihat proporsi target menggunakan prop table, alasan dilakukan tahapan ini adalah Proporsi yang seimbang penting agar model klasifikasi mempelajari karakteristik kelas positif maupun negatif secara seimbang, tidak dari satu kelas saja. Hal ini mencegah model dari hanya baik memprediksi 1 kelas saja.

prop.table(table(boston$class))
## 
##     FALSE      TRUE 
## 0.4197531 0.5802469

insight:
- Proporsi target belum balance perlu dilakukan balancing data

Tahap 5 : Cross Validation

Tahapan ini membagi data menjadi data train dan data test menggunakan subsetting index dengan fungsi sample, kemudian cek kembali proporsi kelas pada data train. Untuk membagi data menjadi dua gunakan fungsi sample() untuk melakukan sampling , gunakan set.seed() untuk mengunci data.

1. Subsetting Index

Subsetting dilakukan untuk mendapatkan nilai index melalui subset berdasarkan barisnya.

# mengunci nilai random
RNGkind(sample.kind = "Rounding") 
## Warning in RNGkind(sample.kind = "Rounding"): non-uniform 'Rounding' sampler
## used
set.seed(911)

# index sampling
index <- sample(nrow(boston), nrow(boston)*0.8) #nilai 0.8 atau 80% tidak mutlak tergantung kebutuhan

# splitting
boston_train <- boston[index,] #digunakan untuk membuat model
boston_test <- boston[-index,] #digunakan untuk pengujian 

2. Cek Proporsi Kelas

Proporsi kelas yang balance penting untuk data train karena kita akan melatih model menggunakan data train.

prop.table(table(boston_train$class))
## 
##     FALSE      TRUE 
## 0.4123711 0.5876289

3. Mengatasi Imbalance Data Train

Karena data train yang diperoleh belum balance maka akan dilakukan balancing data menggunakan upsampling. Balancing data hanya dilakukan pada data train untuk menjaga originalitas data test

RNGkind(sample.kind = "Rounding")
## Warning in RNGkind(sample.kind = "Rounding"): non-uniform 'Rounding' sampler
## used
set.seed(100)
library(caret)
## Warning: package 'caret' was built under R version 4.3.1
## Loading required package: ggplot2
## Loading required package: lattice
boston_train <- upSample(x = boston_train %>% select(-class),
                       y = boston_train$class,
                       yname = "class")

cek proporsi data yang telah dilakukan upsampling

prop.table(table(boston_train$class))
## 
## FALSE  TRUE 
##   0.5   0.5

Tahap 6 : Membuat Pemodelan Regresi Logistik

Tahapan ini membuat dua model regresi yaitu model regresi base dan model regresi step kemudian dibandingkan untuk mendapatkan model yang paling baik dari keduanya.

1. Model Base

  • membuat model dari seluruh predictor dengan anggapan bahwa semua prediktor berguna
  • menggunakan fungsi glm() dan data nya adalah data train
model_base <- glm(formula = class~.,
                  data = boston_train,
                  family = 'binomial')

summary(model_base)
## 
## Call:
## glm(formula = class ~ ., family = "binomial", data = boston_train)
## 
## Coefficients:
##               Estimate Std. Error z value     Pr(>|z|)    
## (Intercept)  12.717328   4.496647   2.828     0.004681 ** 
## CRIM         -0.186118   0.085945  -2.166     0.030345 *  
## ZN            0.026895   0.020271   1.327     0.184580    
## INDUS         0.103074   0.053724   1.919     0.055037 .  
## CHAS1         1.850113   0.808227   2.289     0.022074 *  
## NOX         -10.587685   3.319774  -3.189     0.001426 ** 
## RM            1.344480   0.482686   2.785     0.005346 ** 
## AGE          -0.043590   0.011828  -3.685     0.000228 ***
## DIS          -0.747318   0.203889  -3.665     0.000247 ***
## RAD2          0.721230   1.383539   0.521     0.602162    
## RAD3         -0.065644   1.145988  -0.057     0.954321    
## RAD4          0.121661   0.988138   0.123     0.902011    
## RAD5          0.588479   1.011756   0.582     0.560808    
## RAD6          0.990366   1.156904   0.856     0.391971    
## RAD7         16.954863 864.185872   0.020     0.984347    
## RAD8          2.179635   1.470085   1.483     0.138165    
## RAD24         4.347531   1.718803   2.529     0.011426 *  
## TAX          -0.006873   0.003564  -1.929     0.053762 .  
## PTRATIO      -0.376773   0.111130  -3.390     0.000698 ***
## B             0.006116   0.003013   2.030     0.042369 *  
## LSTAT        -0.317874   0.058372  -5.446 0.0000000516 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 632.15  on 455  degrees of freedom
## Residual deviance: 224.94  on 435  degrees of freedom
## AIC: 266.94
## 
## Number of Fisher Scoring iterations: 16

insight:
- Mayoritas data numerik adalah signifkan, dan data kategorik kurang signifikan - nilai Residual lebih kecil daripada Null, artinya keberadaan prediktor mampu memperbaiki hasil prediksi - tidak ada indikasi perfect separation - nilai AIC nya sebesar 259.24

2. Model Stepwise

  • Model stepwise digunakan karena memilki kemampuan dapat memilih hanya menggunakan data yang signifikan yang digunakan.
  • Penggunakan backward karena hanya butuh data full, kita tidak perlu nilai null nya
model_step <- step(object = model_base, 
                   direction = "backward", 
                   trace = F)

summary(model_step)
## 
## Call:
## glm(formula = class ~ CRIM + INDUS + CHAS + NOX + RM + AGE + 
##     DIS + RAD + TAX + PTRATIO + B + LSTAT, family = "binomial", 
##     data = boston_train)
## 
## Coefficients:
##               Estimate Std. Error z value     Pr(>|z|)    
## (Intercept)  12.391356   4.502772   2.752     0.005924 ** 
## CRIM         -0.165934   0.083922  -1.977     0.048014 *  
## INDUS         0.099617   0.054483   1.828     0.067490 .  
## CHAS1         1.910902   0.800704   2.387     0.017008 *  
## NOX         -10.283719   3.302218  -3.114     0.001845 ** 
## RM            1.384049   0.482929   2.866     0.004158 ** 
## AGE          -0.042631   0.011696  -3.645     0.000267 ***
## DIS          -0.588215   0.156438  -3.760     0.000170 ***
## RAD2          0.735569   1.375557   0.535     0.592828    
## RAD3         -0.479368   1.049676  -0.457     0.647900    
## RAD4         -0.112957   0.929413  -0.122     0.903267    
## RAD5          0.277171   0.956584   0.290     0.772007    
## RAD6          0.814458   1.116333   0.730     0.465645    
## RAD7         16.541511 871.757322   0.019     0.984861    
## RAD8          1.945169   1.447465   1.344     0.178998    
## RAD24         3.825666   1.612523   2.372     0.017669 *  
## TAX          -0.006096   0.003460  -1.762     0.078096 .  
## PTRATIO      -0.399850   0.110467  -3.620     0.000295 ***
## B             0.005744   0.002977   1.930     0.053667 .  
## LSTAT        -0.320784   0.058189  -5.513 0.0000000353 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 632.15  on 455  degrees of freedom
## Residual deviance: 226.86  on 436  degrees of freedom
## AIC: 266.86
## 
## Number of Fisher Scoring iterations: 16

insight:
- secara keseluruhan hanya berbeda sangat sedikit dengan model_base
- Nilai AIC sebesar 266.86

3. Komparasi Model Base dengan Model Step

Dari dua pemodelan yang sudah dibuat, kita perlu memilih salah satu untuk langkah selanjutnya. Beberapa pertimbangan pemilihan model yaitu
- prediktor yang signifikan ? model step lebih banyak nilai signifikan
- perbandingan nilai AIC

1. Perbandingan Nilai AIC

# bandingkan AIC
model_base$aic
## [1] 266.9428
model_step$aic
## [1] 266.8561

2. Perbandingan Nilai Deviance

# bandingkan Deviance
model_base$deviance
## [1] 224.9428
model_step$deviance
## [1] 226.8561

3. Perbandingan Jumlah Prediktor

  • model_base menggunakan 13 prediktor
  • model_step menggunakan 12 prediktor

    karena perbandingan yang sedikit, maka model yang dipilih adalah model_base. hal tersebut berdasarkan selisih AIC yang kecil dan nilai Deviance yang lebih besar.

4. Interpretasi Model Terpilih

summary(model_base)
## 
## Call:
## glm(formula = class ~ ., family = "binomial", data = boston_train)
## 
## Coefficients:
##               Estimate Std. Error z value     Pr(>|z|)    
## (Intercept)  12.717328   4.496647   2.828     0.004681 ** 
## CRIM         -0.186118   0.085945  -2.166     0.030345 *  
## ZN            0.026895   0.020271   1.327     0.184580    
## INDUS         0.103074   0.053724   1.919     0.055037 .  
## CHAS1         1.850113   0.808227   2.289     0.022074 *  
## NOX         -10.587685   3.319774  -3.189     0.001426 ** 
## RM            1.344480   0.482686   2.785     0.005346 ** 
## AGE          -0.043590   0.011828  -3.685     0.000228 ***
## DIS          -0.747318   0.203889  -3.665     0.000247 ***
## RAD2          0.721230   1.383539   0.521     0.602162    
## RAD3         -0.065644   1.145988  -0.057     0.954321    
## RAD4          0.121661   0.988138   0.123     0.902011    
## RAD5          0.588479   1.011756   0.582     0.560808    
## RAD6          0.990366   1.156904   0.856     0.391971    
## RAD7         16.954863 864.185872   0.020     0.984347    
## RAD8          2.179635   1.470085   1.483     0.138165    
## RAD24         4.347531   1.718803   2.529     0.011426 *  
## TAX          -0.006873   0.003564  -1.929     0.053762 .  
## PTRATIO      -0.376773   0.111130  -3.390     0.000698 ***
## B             0.006116   0.003013   2.030     0.042369 *  
## LSTAT        -0.317874   0.058372  -5.446 0.0000000516 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 632.15  on 455  degrees of freedom
## Residual deviance: 224.94  on 435  degrees of freedom
## AIC: 266.94
## 
## Number of Fisher Scoring iterations: 16

interpretasi model :
- Interpretasi Kategorik
- nilai CHAS1 = 1.850113 ubah ke log of odds

exp(1.850113)
## [1] 6.360538

**insight*:
Rumah yang lebih dekat Sungai Charles (CHAS = 1) memiliki kemungkinan 6.3 kali lebih besar dibandingkan dengan rumah yang tidak dekat dengan Sungai Charles (CHAS = 0),dengan syarat variabel yang lain memiliki nilai yg sama

-Interpretasi Numerik
- nilai RM = 1.344480

exp(1.344480)
## [1] 3.836191

Insight: Setiap penambahan 1 poin dari RM akan meningkatkan kemungkinan harga rumah diatas 20000 USD sebesar 3.8 kali, dengan syarat variable lain tetap.

Tahap 7 : Pemodelan Prediksi

menggunakan data test menggunakan fungsi predict() untuk nilai peluang (respon) kemudian di save di kolom baru, klasifikasi dengan menggunakan ifelse dan di save ke kolom baru, lihat hasil prediksi

1. Prediksi probability class untuk data boston_test dan disimpan pada kolom baru bernama pred.Risk

boston_test$pred.Risk <- predict(object = model_base,
        newdata = boston_test,
        type = 'response')

2. kemudian Klasifikasikan data loans.test berdasarkan pred.Risk dan simpan pada kolom baru bernama pred.Label

# ubah peluang menjadi label prediksi
# ifelse(kondisi, benar, salah)
boston_test$pred.Label <- ifelse(boston_test$pred.Risk > 0.5, TRUE, FALSE)

3. Melihat Hasil Prediksi

# lihat hasil prediksi
boston_test %>% 
  select(class, pred.Label)
##     class pred.Label
## 5    TRUE       TRUE
## 7    TRUE      FALSE
## 8   FALSE      FALSE
## 23  FALSE      FALSE
## 28  FALSE      FALSE
## 31  FALSE      FALSE
## 34  FALSE       TRUE
## 35   TRUE       TRUE
## 51  FALSE      FALSE
## 56  FALSE       TRUE
## 60   TRUE       TRUE
## 63  FALSE       TRUE
## 67   TRUE       TRUE
## 70   TRUE       TRUE
## 71   TRUE       TRUE
## 80   TRUE       TRUE
## 81   TRUE       TRUE
## 113  TRUE       TRUE
## 122 FALSE      FALSE
## 123 FALSE      FALSE
## 128  TRUE      FALSE
## 135 FALSE      FALSE
## 136 FALSE      FALSE
## 139 FALSE      FALSE
## 145 FALSE      FALSE
## 150 FALSE      FALSE
## 151 FALSE      FALSE
## 154  TRUE       TRUE
## 156  TRUE       TRUE
## 157  TRUE       TRUE
## 165 FALSE      FALSE
## 169  TRUE       TRUE
## 171  TRUE       TRUE
## 173  TRUE       TRUE
## 174  TRUE       TRUE
## 175  TRUE       TRUE
## 176  TRUE       TRUE
## 186  TRUE       TRUE
## 187  TRUE       TRUE
## 188  TRUE       TRUE
## 201  TRUE      FALSE
## 206  TRUE       TRUE
## 211  TRUE       TRUE
## 212  TRUE       TRUE
## 217  TRUE       TRUE
## 218  TRUE       TRUE
## 232  TRUE       TRUE
## 237 FALSE       TRUE
## 245  TRUE       TRUE
## 247  TRUE       TRUE
## 250  TRUE       TRUE
## 256  TRUE       TRUE
## 258  TRUE       TRUE
## 263  TRUE       TRUE
## 268  TRUE       TRUE
## 277  TRUE      FALSE
## 280  TRUE       TRUE
## 297  TRUE       TRUE
## 299  TRUE       TRUE
## 302 FALSE      FALSE
## 304  TRUE       TRUE
## 312  TRUE       TRUE
## 313 FALSE      FALSE
## 324  TRUE       TRUE
## 328  TRUE       TRUE
## 332 FALSE      FALSE
## 333  TRUE       TRUE
## 336 FALSE      FALSE
## 343  TRUE       TRUE
## 347  TRUE       TRUE
## 349  TRUE      FALSE
## 352  TRUE      FALSE
## 363 FALSE      FALSE
## 370 FALSE      FALSE
## 374 FALSE      FALSE
## 377 FALSE      FALSE
## 384 FALSE      FALSE
## 386 FALSE      FALSE
## 388 FALSE      FALSE
## 389 FALSE      FALSE
## 393  TRUE      FALSE
## 397 FALSE      FALSE
## 399 FALSE      FALSE
## 402 FALSE      FALSE
## 414 FALSE      FALSE
## 420 FALSE      FALSE
## 425 FALSE      FALSE
## 433 FALSE      FALSE
## 437 FALSE      FALSE
## 438 FALSE      FALSE
## 446 FALSE      FALSE
## 449 FALSE      FALSE
## 456  TRUE       TRUE
## 459 FALSE      FALSE
## 460 FALSE      FALSE
## 477 FALSE      FALSE
## 484  TRUE       TRUE
## 485  TRUE       TRUE

Insight
- ada data yang diprediksi benar, ada juga yang diprediksi salah

Tahap 8 : Pemodelan Evaluasi

Evaluasi hasil model dilakukan dengan cara mengguanakn confusion matrix.

# confusion matrix
library(caret)

eval_log <- confusionMatrix(data = as.factor(boston_test$pred.Label),  #ubah ke factor dahulu
                reference = boston_test$class,
                positive = "TRUE")                           #definisikan kelas positif 

eval_log
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction FALSE TRUE
##      FALSE    40    7
##      TRUE      4   47
##                                             
##                Accuracy : 0.8878            
##                  95% CI : (0.808, 0.9426)   
##     No Information Rate : 0.551             
##     P-Value [Acc > NIR] : 0.0000000000005976
##                                             
##                   Kappa : 0.7746            
##                                             
##  Mcnemar's Test P-Value : 0.5465            
##                                             
##             Sensitivity : 0.8704            
##             Specificity : 0.9091            
##          Pos Pred Value : 0.9216            
##          Neg Pred Value : 0.8511            
##              Prevalence : 0.5510            
##          Detection Rate : 0.4796            
##    Detection Prevalence : 0.5204            
##       Balanced Accuracy : 0.8897            
##                                             
##        'Positive' Class : TRUE              
## 

Insight:
- Re-call/Sensitivity = dari semua data aktual yang positif, model mampu memprediksi benar sebesar 87.04%
- Specificity = dari semua data aktual yang negatif, model mampu memprediksi benar sebesar 90.91%
- Accuracy = model mampu memprediksi dengan benar target sebesar 88.78%
- Precision/Pos Pred Value = dari semua hasil prediksi, model mampu memprediksi benar kelas positif sebesar 92.16%

Tahap 9: Metode K-NN sebagai Model Pembanding Regresi Logistik

K-nearest neighbors atau knn adalah algoritma yang berfungsi untuk melakukan klasifikasi suatu data berdasarkan data pembelajaran (train data sets), yang diambil dari k tetangga terdekatnya (nearest neighbors). Dengan k merupakan banyaknya tetangga terdekat.

1. Read Data

melakukan pembacaan data

head(boston)
##      CRIM ZN INDUS CHAS   NOX    RM  AGE    DIS RAD TAX PTRATIO      B    LSTAT
## 1 0.00632 18  2.31    0 0.538 6.575 65.2 4.0900   1 296    15.3 396.90  4.98000
## 2 0.02731  0  7.07    0 0.469 6.421 78.9 4.9671   2 242    17.8 396.90  9.14000
## 3 0.02729  0  7.07    0 0.469 7.185 61.1 4.9671   2 242    17.8 392.83  4.03000
## 4 0.03237  0  2.18    0 0.458 6.998 45.8 6.0622   3 222    18.7 394.63  2.94000
## 5 0.06905  0  2.18    0 0.458 7.147 54.2 6.0622   3 222    18.7 396.90 12.71543
## 6 0.02985  0  2.18    0 0.458 6.430 58.7 6.0622   3 222    18.7 394.12  5.21000
##   class
## 1  TRUE
## 2  TRUE
## 3  TRUE
## 4  TRUE
## 5  TRUE
## 6  TRUE

2. Data Wrangling

cek tipe data pada data boston

glimpse(boston)
## Rows: 486
## Columns: 14
## $ CRIM    <dbl> 0.00632, 0.02731, 0.02729, 0.03237, 0.06905, 0.02985, 0.14455,…
## $ ZN      <dbl> 18.0, 0.0, 0.0, 0.0, 0.0, 0.0, 12.5, 12.5, 12.5, 12.5, 12.5, 0…
## $ INDUS   <dbl> 2.31, 7.07, 7.07, 2.18, 2.18, 2.18, 7.87, 7.87, 7.87, 7.87, 7.…
## $ CHAS    <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ NOX     <dbl> 0.538, 0.469, 0.469, 0.458, 0.458, 0.458, 0.524, 0.524, 0.524,…
## $ RM      <dbl> 6.575, 6.421, 7.185, 6.998, 7.147, 6.430, 6.172, 5.631, 6.377,…
## $ AGE     <dbl> 65.2, 78.9, 61.1, 45.8, 54.2, 58.7, 96.1, 100.0, 94.3, 82.9, 3…
## $ DIS     <dbl> 4.0900, 4.9671, 4.9671, 6.0622, 6.0622, 6.0622, 5.9505, 6.0821…
## $ RAD     <fct> 1, 2, 2, 3, 3, 3, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,…
## $ TAX     <int> 296, 242, 242, 222, 222, 222, 311, 311, 311, 311, 311, 307, 30…
## $ PTRATIO <dbl> 15.3, 17.8, 17.8, 18.7, 18.7, 18.7, 15.2, 15.2, 15.2, 15.2, 15…
## $ B       <dbl> 396.90, 396.90, 392.83, 394.63, 396.90, 394.12, 396.90, 386.63…
## $ LSTAT   <dbl> 4.98000, 9.14000, 4.03000, 2.94000, 12.71543, 5.21000, 19.1500…
## $ class   <fct> TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,…

membuat objek baru tanpa data factor karena model ini adalah model numerik

boston_knn <- boston |> select(-CHAS,-RAD)

3. Exploratory Data Analysis

cek proporsi kelas

prop.table(table(boston_knn$class))
## 
##     FALSE      TRUE 
## 0.4197531 0.5802469

4. Cross Validation

membagi dataset menjadi dua data

# mengunci nilai random
RNGkind(sample.kind = "Rounding") 
## Warning in RNGkind(sample.kind = "Rounding"): non-uniform 'Rounding' sampler
## used
set.seed(911)

# index sampling
index <- sample(nrow(boston_knn), nrow(boston_knn)*0.8) #nilai 0.8 atau 80% tidak mutlak tergantung kebutuhan

# splitting
boston_train_knn <- boston_knn[index,] #digunakan untuk membuat model
boston_test_knn <- boston_knn[-index,] #digunakan untuk pengujian

cek proporsi data

prop.table(table(boston_train_knn$class))
## 
##     FALSE      TRUE 
## 0.4123711 0.5876289

melakukan upsampling karena data imbalance

RNGkind(sample.kind = "Rounding")
## Warning in RNGkind(sample.kind = "Rounding"): non-uniform 'Rounding' sampler
## used
set.seed(100)
library(caret)

boston_train_knn <- upSample(x = boston_train_knn %>% select(-class),
                       y = boston_train_knn$class,
                       yname = "class")
prop.table(table(boston_train_knn$class))
## 
## FALSE  TRUE 
##   0.5   0.5

5. Data Preprocessing

membuat variable target dan prediktornya

# prediktor data train
boston_knn_train_x <- boston_train_knn %>% select_if(is.numeric) 

# target data train
boston_knn_train_y <- boston_train_knn[,"class"]

# prediktor data test
boston_knn_test_x <- boston_test_knn %>% select_if(is.numeric)

# target data test
boston_knn_test_y <- boston_test_knn[,"class"]

melakukan scalling data

# scaling data
# train
boston_knn_train_xs <- scale(x = boston_knn_train_x) # data prediktor untuk data train

# test
boston_knn_test_xs <- scale(x = boston_knn_test_x,
                      center = attr(boston_knn_train_xs, "scaled:center"), #nilai rata rata data
                      scale = attr(boston_knn_train_xs,"scaled:scale")) # nilai data train

menentuka nilai K optimum

sqrt(nrow(boston_train_knn))
## [1] 21.35416
library(class) 
pred_knn <- knn(train = boston_knn_train_xs, # prediktor data train
                test = boston_knn_test_xs, # prediktor data test
                cl = boston_knn_train_y, # label dari data train
                k = 21)
head(pred_knn)
## [1] TRUE  TRUE  FALSE FALSE FALSE FALSE
## Levels: FALSE TRUE

6. Data Preprocessing

melakukan pemodelan

library(caret)
eval_knn <- confusionMatrix(pred_knn, boston_knn_test_y, positive = "TRUE")
eval_knn
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction FALSE TRUE
##      FALSE    37    8
##      TRUE      7   46
##                                           
##                Accuracy : 0.8469          
##                  95% CI : (0.7601, 0.9117)
##     No Information Rate : 0.551           
##     P-Value [Acc > NIR] : 0.0000000004645 
##                                           
##                   Kappa : 0.6913          
##                                           
##  Mcnemar's Test P-Value : 1               
##                                           
##             Sensitivity : 0.8519          
##             Specificity : 0.8409          
##          Pos Pred Value : 0.8679          
##          Neg Pred Value : 0.8222          
##              Prevalence : 0.5510          
##          Detection Rate : 0.4694          
##    Detection Prevalence : 0.5408          
##       Balanced Accuracy : 0.8464          
##                                           
##        'Positive' Class : TRUE            
## 

Tahap 10: Kesimpulan

1. Pemilihan Model Regresi

eval_model_base <- data_frame(AIC = model_base$aic[1],
                              Deviance = model_base$deviance[1])
## Warning: `data_frame()` was deprecated in tibble 1.1.0.
## ℹ Please use `tibble()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
eval_model_base
## # A tibble: 1 × 2
##     AIC Deviance
##   <dbl>    <dbl>
## 1  267.     225.
eval_model_step <- data_frame(AIC = model_step$aic[1],
                              Deviance = model_step$deviance[1])
eval_model_step
## # A tibble: 1 × 2
##     AIC Deviance
##   <dbl>    <dbl>
## 1  267.     227.

Conclusion:
dari hasil diatas model_base dipilih karena meskipun memberikan AIC yang lebih tinggi namun juga memberikan nilai Deviance yang rendah. Dimana selisih perbedaan nilai Deviance lebih besar dari AIC.

2. Pemilihan antara Model Regresi dan KNN

eval_log_table <- data_frame(Accuracy = eval_log$overall[1],
                       Recall = eval_log$byClass[1],
                       Specificity = eval_log$byClass[2],
                       Precision = eval_log$byClass[3])
eval_log_table
## # A tibble: 1 × 4
##   Accuracy Recall Specificity Precision
##      <dbl>  <dbl>       <dbl>     <dbl>
## 1    0.888  0.870       0.909     0.922
eval_knn_table <- data_frame(Accuracy = eval_knn$overall[1],
                                 Recall = eval_knn$byClass[1],
                                 Specificity = eval_knn$byClass[2],
                                 Precision = eval_knn$byClass[3])
eval_knn_table
## # A tibble: 1 × 4
##   Accuracy Recall Specificity Precision
##      <dbl>  <dbl>       <dbl>     <dbl>
## 1    0.847  0.852       0.841     0.868

Conclusion:
- Dari nilai diatas, jika ditinjau dari 4 matriks evaluasi diperoleh bahwa nilai model dari Logistic Regression mampu memberikan hasil yang sedikit lebih baik dalam memprediksi data dibandingkan dengan model KNN
- metrics evaluasi Recall, diutamakan dalam penelitian ini karena diharapkan model tidak keliru dalam memprediksi kelas harga rumah yang seharusnya bernilai dibawah 20000 USD ternyata diatas 20000 USD, menjadikan pembelian rumah tertunda.