LBB Regression Model: Abalone Ring Prediction

Introduction

Background

Linear Regression adalah model statistik yang menguji hubungan linear anatara dua variabel atau lebih. Variabel-variabel tersebut dikenal dengan istilah variabel terikat (dependent variable) dan variabel bebas (independent variable). Dimana:

  • Dependent Variable adalah faktor utama yang ingin kita prediksi; target variable (numeric)
  • Independent Variable adalah faktor-faktor yang kita hipotesa memiliki pengaruh terhadap target variable; predictor variable (numerical/categorical)

Hubungan linier pada dasarnya berarti bahwa ketika satu (atau lebih) variabel independen meningkat (atau menurun), variabel dependen meningkat (atau menurun) juga.

Linear regression adalah pendekatan untuk memprediksi target variable menggunakan predictor variable. Diasumsikan bahwa kedua variabel tersebut memiliki hubungan linear. Oleh karena itu, dalam linear regression, kita akan mencoba mencari fungsi linear yang memprediksi nilai target variable (y) seakurat mungkin sebagai fungsi dari predictor variable (x)

Kita tahu bahwa persamaan garis lurus pada dasarnya adalah:
\[y = mx + c\]

dimana :

\(m\) = kemiringan garis (slope)

\(c\) = intersep

Jadi pada dasarnya, algoritma linear regression memberi kita nilai paling optimal untuk intersep dan slope (dalam dua dimensi). Variabel y dan x tetap sama, karena merupakan fitur data dan tidak dapat diubah. Nilai yang bisa kita kendalikan adalah intersep (c) dan slope (m). Pada dasarnya apa yang dilakukan oleh algoritma linear regression adalah menyesuaikan beberapa baris pada titik data dan mengembalikan garis yang memiliki kesalahan (error) paling kecil.

Objective

Tujuan dari dibuatnya Learning By Building (LBB) ini adalah :

  • Membuat model linear regression pada dataset Abalone melakukan prediksi ukuran ring abolone berdasarkan pengukuran fisiknya.
  • Melakukan uji validitas terhadap model yang telah dibuat.
  • Melakukan interpretasi dan rekomendasi terhadap hasil prediksi menggunakan model linear regression

Data

Pada kesempatan kali ini saya akan melakukan pembuatan model linear regression menggunakan dataset Abalone. Dimana dataset tersebut berisi informasi dari ukuran fisik pada abalone, dari informasi tersebut kita dapat menentukan umur dari abalone itu sendiri.

Import Library

Pada Learning By Building: Linear Regression kita akan menggunakan beberapa library yang memiliki fungsi masing-masing, library yang digunakan antara lain :

  • dplyr : Digunakan dalam melakukan proses EDA maupun Data Manipulation.
  • GGally : Digunakan untuk membuat correlation matrix plot setiap variabel.
  • MLmetrics : Digunakan pada tahap evaluasi model.
  • performance : Digunakan ketika ingin membandingkan performa antar model.
  • lmtest : Digunakan saat ingin melakukan uji Breusch-Pagan.
  • car : Digunakan saat melakukan uji Multikolinearitas.
  • stringr : Digunakan saat tahap cleansing
library(dplyr) # Tools EDA/ Data Manipulation
library(GGally) # Tools plot korelasi
library(MLmetrics) # Tools evaluation model
library(performance) # Tools perbandingan performa antar model
library(lmtest) # Tools Uji Breusch-Pagan
library(car) # Tools Uji Multikolinearitas
library(stringr) # Tools cleansing

Import Data

Dataset yang digunakan adalah abalone.csv untuk mengimpor dataset tersebut kita akan menggunakan fungsi read.csv() dan akan disimpan ke dalam variabel abalone :

abalone <- read.csv('Data Input/abalone.csv')

Selanjutnya untuk langkah awal, kita akan menggunakan fungsi head() pada variabel caruntuk melihat apakah file Quikr_car.csv sudah berhasil disimpan di variabel abalone:

head(abalone)

Proses memasukan dataset abalone sudah berhasil dilakukan dan selanjutnya kita akan melakukan proses Exploratory Data Analysis.

Exploratory Data Analysis

Data abalone merupakan data hasil observarsi pengukuran fisik dari abalone. Untuk mengetahui jumlah baris dan kolom kita akan menggunakan fungsi dim()

dim(abalone)
#> [1] 4177    9

Data abalone memiliki 4177 baris dan 9 kolom, berikut adalah deskripsi kolom pada dataset abalone :

Name Data Type Measurement Unit Description
Sex nominal - M, F, and I (infant)
Length continuous mm Longest shell measurement
Diameter continuous mm perpendicular to length
Height continuous mm with meat in shell
Whole weight continuous grams whole abalone
Shucked weight continuous grams weight of meat
Viscera weight continuous grams gut weight (after bleeding)
Shell weight continuous grams after being dried
Rings integer +1.5 gives the age in years

Missing Values Check

Selanjutnya kita akan melakukan pengecekan missing values kita dapat menggunakan kombinasi fungsi colSums() dan is.na(), sebagai berikut :

colSums(is.na(abalone))
#>            Sex         Length       Diameter         Height   Whole.weight 
#>              0              0              0              0              0 
#> Shucked.weight Viscera.weight   Shell.weight          Rings 
#>              0              0              0              0

Jika dilihat dari hasil pengecekan di atas, data abalone tidak memiliki missing values. Sehingga kita dapat melanjutkan ke tahap selanjutnya.

Data Types

Pada tahap ini kita akan memastikan bahwa tipe data pada data abalone sudah sesuai dengan semestinya. Untuk melakukan pengecekan tersebut kita harus mengetahui tipe data saat ini. Terdapat beberapa fungsi yang bisa menampilkan informasi tersebut seperti glimpse(), head(), str(), dan lainya. Pada kesempatan ini saya akan menggunakan fungsi glimpse() untuk melihat tipe data abalone.

glimpse(abalone)
#> Rows: 4,177
#> Columns: 9
#> $ Sex            <chr> "M", "M", "F", "M", "I", "I", "F", "F", "M", "F", "F", …
#> $ Length         <dbl> 0.455, 0.350, 0.530, 0.440, 0.330, 0.425, 0.530, 0.545,…
#> $ Diameter       <dbl> 0.365, 0.265, 0.420, 0.365, 0.255, 0.300, 0.415, 0.425,…
#> $ Height         <dbl> 0.095, 0.090, 0.135, 0.125, 0.080, 0.095, 0.150, 0.125,…
#> $ Whole.weight   <dbl> 0.5140, 0.2255, 0.6770, 0.5160, 0.2050, 0.3515, 0.7775,…
#> $ Shucked.weight <dbl> 0.2245, 0.0995, 0.2565, 0.2155, 0.0895, 0.1410, 0.2370,…
#> $ Viscera.weight <dbl> 0.1010, 0.0485, 0.1415, 0.1140, 0.0395, 0.0775, 0.1415,…
#> $ Shell.weight   <dbl> 0.150, 0.070, 0.210, 0.155, 0.055, 0.120, 0.330, 0.260,…
#> $ Rings          <int> 15, 7, 9, 10, 7, 8, 20, 16, 9, 19, 14, 10, 11, 10, 10, …

Jika dilihat dari hasil pengecekan tipe data menggunakan glimpse() pada data abalone terdapat kolom/variabel yang memiliki tipe data yang kurang tepat. Seperti yang kita ketahui sebelumnya di deskirpsi kolom pada bagian Exploratory Data Analysis. Terdapat kolom yang nilainya merepresentasikan sebuah kategori. Kolom tersebut adalah Sex sehingga kita perlu melakukan perubahan tipe data dari chr menjadi fct.Selanjutnya kita akan merubah kolom Sex menggunakan fungsi mutate() dari package dplyr dikombinasikan dengan fungsi as.factor() dan as.integer().

abalone <- abalone %>% 
 mutate(Sex = as.factor(Sex)) 

glimpse(abalone)
#> Rows: 4,177
#> Columns: 9
#> $ Sex            <fct> M, M, F, M, I, I, F, F, M, F, F, M, M, F, F, M, I, F, M…
#> $ Length         <dbl> 0.455, 0.350, 0.530, 0.440, 0.330, 0.425, 0.530, 0.545,…
#> $ Diameter       <dbl> 0.365, 0.265, 0.420, 0.365, 0.255, 0.300, 0.415, 0.425,…
#> $ Height         <dbl> 0.095, 0.090, 0.135, 0.125, 0.080, 0.095, 0.150, 0.125,…
#> $ Whole.weight   <dbl> 0.5140, 0.2255, 0.6770, 0.5160, 0.2050, 0.3515, 0.7775,…
#> $ Shucked.weight <dbl> 0.2245, 0.0995, 0.2565, 0.2155, 0.0895, 0.1410, 0.2370,…
#> $ Viscera.weight <dbl> 0.1010, 0.0485, 0.1415, 0.1140, 0.0395, 0.0775, 0.1415,…
#> $ Shell.weight   <dbl> 0.150, 0.070, 0.210, 0.155, 0.055, 0.120, 0.330, 0.260,…
#> $ Rings          <int> 15, 7, 9, 10, 7, 8, 20, 16, 9, 19, 14, 10, 11, 10, 10, …

Setelah tipe data sudah sesuai kita akan melakukan pengecekan Outlier.

Outlier Check

Pada langkah ini, kita akan membuat boxplot pada setiap kolom yang memiliki tipe data int menggunakan fungsi boxplot() dan menambahkan $out untuk menampilkan nilai yang outlier.

boxplot(abalone$Length)$out

#>  [1] 0.175 0.170 0.075 0.130 0.110 0.160 0.200 0.165 0.190 0.175 0.200 0.175
#> [13] 0.155 0.195 0.165 0.155 0.180 0.150 0.160 0.185 0.195 0.195 0.200 0.185
#> [25] 0.140 0.185 0.135 0.160 0.130 0.180 0.165 0.190 0.170 0.180 0.175 0.155
#> [37] 0.200 0.190 0.180 0.200 0.200 0.165 0.190 0.165 0.175 0.170 0.140 0.160
#> [49] 0.185
boxplot(abalone$Diameter)$out

#>  [1] 0.150 0.150 0.130 0.130 0.055 0.100 0.090 0.120 0.145 0.120 0.145 0.125
#> [13] 0.150 0.140 0.125 0.110 0.145 0.110 0.105 0.125 0.100 0.110 0.140 0.120
#> [25] 0.130 0.150 0.135 0.105 0.135 0.130 0.110 0.150 0.095 0.130 0.115 0.130
#> [37] 0.150 0.125 0.125 0.135 0.115 0.145 0.150 0.140 0.150 0.135 0.150 0.145
#> [49] 0.125 0.130 0.120 0.150 0.150 0.125 0.130 0.105 0.105 0.120 0.135
boxplot(abalone$Height)$out

#>  [1] 0.010 0.030 0.030 0.035 0.030 0.020 0.035 0.025 0.025 0.015 0.000 0.515
#> [13] 0.250 0.035 0.250 0.025 1.130 0.035 0.015 0.030 0.030 0.250 0.025 0.030
#> [25] 0.025 0.035 0.035 0.020 0.000
boxplot(abalone$Whole.weight)$out

#>  [1] 2.5500 2.4990 2.8255 2.5550 2.3020 2.2730 2.2360 2.5050 2.6570 2.2500
#> [11] 2.5085 2.2550 2.2205 2.5155 2.7795 2.2260 2.5260 2.3810 2.3980 2.3305
#> [21] 2.2355 2.3235 2.2305 2.2635 2.2695 2.4925 2.3330 2.5480 2.3810 2.2385
boxplot(abalone$Shucked.weight)$out

#>  [1] 1.0705 1.1465 1.0120 1.1335 1.0070 1.0950 1.0465 1.0265 1.0260 1.1090
#> [11] 1.1965 1.4880 1.1075 1.0465 1.1565 1.2320 1.0170 1.3510 0.9895 0.9925
#> [21] 1.1455 1.0300 1.0830 1.1155 1.3485 1.0715 1.0815 1.0685 0.9915 1.1280
#> [31] 1.0515 1.0050 1.0615 1.1055 1.2530 1.1705 1.1495 0.9815 0.9955 1.2395
#> [41] 1.0135 1.1455 1.2395 1.2455 1.1945 1.1330 1.0745 0.9840
boxplot(abalone$Viscera.weight)$out

#>  [1] 0.5410 0.5225 0.5090 0.5500 0.5195 0.5130 0.4985 0.5640 0.5190 0.4925
#> [11] 0.5195 0.5185 0.6415 0.7600 0.5900 0.5005 0.5120 0.5265 0.5235 0.5250
#> [21] 0.5410 0.5115 0.5750 0.5145 0.5745 0.5260
boxplot(abalone$Shell.weight)$out

#>  [1] 0.6750 0.7800 0.6350 1.0050 0.8150 0.7250 0.8500 0.6500 0.7600 0.6900
#> [11] 0.7100 0.7000 0.8970 0.6380 0.6785 0.7975 0.6300 0.6420 0.6430 0.6460
#> [21] 0.6585 0.8850 0.7250 0.8850 0.6650 0.6850 0.6600 0.7260 0.6855 0.7100
#> [31] 0.7250 0.6650 0.6745 0.6550 0.6570
boxplot(abalone$Rings)$out

#>   [1] 20 16 19 18 19 16 20 16 21 19 18 17 16 16 18 16 20 20 21 16 22  1  3  3 17
#>  [26] 19 22 16 22 18 20 17 17 19 26  3 21 19 23 23 18 16 16 22 16 20 18 17 16 18
#>  [51] 20 16 19 17 16 16 19 20 16 20 20 16 18 19 21 18 18 20 18 22 19 16 18 16 16
#>  [76] 17 17 21 17 17 21 16 29 17 19 17 19 23 17 16  3  3 20 17 16 20 17 17 19 18
#> [101] 19 16 17 18 18 17 21 19 17 16 18 18 19 17 19 21 23 22 23 16 16 16  2  3 17
#> [126] 18 17 20 17 17 20 20 16 17 17 21 17 17  3  3  3 16 17 19 27  3 16 18 16 17
#> [151] 19 17 20 21 16 21 25 19 18 16 27 18 17 17 17 17 17 17 18 20 19 23 16 16 17
#> [176] 17 23 23 18 17 17 21 17 16 19 18 17 17 20 18 18 19 16  3 16 16 17 17 16 18
#> [201] 18 18 16 16 23 16 20 17 16 20 18 19  3 20 24 21 18 16 20 18 17 17 16 16 18
#> [226] 16 18 19 18 17 17 18 18 24 17 16 16 16 16 17 16 19 16 16 16 17 20 19 17 17
#> [251] 16 19 19 18 16 19 18 18  3  3  3 16 16 18 19 16 16 17 16 16 19 18 20 16 21
#> [276] 17 20 16

Jika kita perhatikan bahwa pada data abalone memilik9 beberapa nilai outliers, tetapi saya akan tetap menggunakannya dikarenakan agar jumlah data nya akan tetap digunakan untuk modelling.

Variable Correlation

Sebelum dilakukan pembuatan model linear regression kita perlu untuk melakukan pengecekan korelasi antara target variable dengan predictor dengan data type numerik. Pada kasus ini kita ingin melakukan prediksi terhadap ukuran Rings suatu abalone berdasarkan dataframe abalone, maka target variable nya adalah kolom Rings. Untuk melakukan pengecekan korelasi kita akan menggunakan fungsi ggcorr() dari package GGally.

ggcorr(abalone, label = TRUE, label_size = 3, hjust =1)

Jika kita lihat pada correlation matrix diatas secara umum variabel-variabel prediktor memiliki nilai korelasi positif terhadap target variable. Dimana sebagai asumsi awal bahwa variabel-variabel prediktor tersebut jika nilai nya meningkat maka kolom Rings akan meningkat.

Cross-Validation

Sebelum memasuki tahap modelling, dataframe abalone akan melalui tahap data pre-processing terlebih dahulu yaitu cross-validation. Tujuan dilakukannya cross-validation adalah membagi dataset kita menjadi dua bagian, yaitu data train dan test yang nanti kedepannya kita akan menggunakan data train untuk pembuatan model, sedangkan untuk data test akan digunakan untuk evaluasi model. Mengapa perlu dilakukan pembagian tersebut? dikarenakan agar kita melakukan evaluasi tidak menggunakan informasi yang sama saat melakukan pemodelan, sehingga hasil evaluasi dapat dibilang akan lebih ‘nyata’ karena data yang dilakukan evaluasi belum pernah dimasukan ke dalam model.

Kita akan menggunakan fungsi RNGkind() dan set.seed() untuk menghasilkan kombinasi angka random yang akan mengontrol saat dilakukannya splitting data.

RNGkind(sample.kind = 'Rounding')
set.seed(666)

Selanjutnya kita akan membagi data kita dengan ratio 80:20, fungsi yang digunakan adalah sample() yang akan di assign ke variabel index. Nantinya variabel index akan digunakan untuk subsetting pada data abalone.

index <- sample(nrow(abalone), size = nrow(abalone)*0.8)

abalone_train <- abalone[index,]
abalone_test <- abalone[-index,]

Setelah dilakukan pemisahan data menjadi abalone_train dan abalone_test, maka kita dapat melakukan tahap selanjutnya yaitu modelling menggunakan data abalone_train.

Create Model

Kita akan membuat model multiple linear regression menggunakan semua variabel prediktor, dengan target variabel Rings. Untuk membuat model tersebut kita akan menggunakan fungsi lm() dengan data abalone_train.

model_abalone_all <- lm(Rings ~ ., abalone_train)

Salah satu metric untuk melihat performa atau evaluasi dari suatu model multiple linear regression menggunakan nilai adj r-squared yang bisa di dapatkan dari hasil fungsi summary().

summary(model_abalone_all)
#> 
#> Call:
#> lm(formula = Rings ~ ., data = abalone_train)
#> 
#> Residuals:
#>     Min      1Q  Median      3Q     Max 
#> -8.5924 -1.3097 -0.3296  0.8674 13.6010 
#> 
#> Coefficients:
#>                 Estimate Std. Error t value Pr(>|t|)    
#> (Intercept)      3.92774    0.32958  11.917  < 2e-16 ***
#> SexI            -0.80231    0.11582  -6.927 5.13e-12 ***
#> SexM             0.05156    0.09339   0.552    0.581    
#> Length          -1.13283    1.99866  -0.567    0.571    
#> Diameter        12.40536    2.46263   5.037 4.97e-07 ***
#> Height           8.91110    1.61918   5.503 4.01e-08 ***
#> Whole.weight    10.16770    0.81447  12.484  < 2e-16 ***
#> Shucked.weight -20.90954    0.92043 -22.717  < 2e-16 ***
#> Viscera.weight -12.31069    1.45151  -8.481  < 2e-16 ***
#> Shell.weight     7.76846    1.24944   6.218 5.68e-10 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 2.205 on 3331 degrees of freedom
#> Multiple R-squared:  0.545,  Adjusted R-squared:  0.5438 
#> F-statistic: 443.4 on 9 and 3331 DF,  p-value: < 2.2e-16

Jika dilihat dari hasil summary() kita dapat melakukan beberapa interpretasi terhadap model tersebut :

  • Beberapa variabel prediktor memiliki nilai slope positif yang berarti naiknya 1 nilai pada variabel prediktor tersebut akan menambahkan nilai sebesar slope variabel dari target variabel atau Rings. Variabel tersebut adalah SexM, Diameter, Height, Whole.weight dan Shell.weight.
  • Begitupun sebaliknya variabel prediktor yang memiliki nilai slope negatif yang berarti naiknya 1 nilai pada variabel tersebut akan mengurangkan nilai sebesar slope variabel dari target variabel atau Rings. Variabel tersebut adalah SexI, Length, Shucked.weight dan Viscera.weight.
  • Jika dilihat dari p-value terdapat variabel yang tidak signifikan di model tersebut yaitu SexM dan Length.
  • model_abalone_all memiliki nilai adjusted R-squared sebesari 54.38%

Tuning Model (Stepwise)

Selanjutnya kita akan mencoba tuning model menggunakan dengan metode stepwise, fungsi yang digunakan adalah step(). Kita akan menggunakan model_abalone_all sebagai object, dengan parameter direction ‘backward’.

model_abalone_backward <- step(object = model_abalone_all,
                             direction = 'backward', 
                             trace = 0)

kita dapat melihat hasil model_abalone_backward menggunakan fungsi summary()

summary(model_abalone_backward)
#> 
#> Call:
#> lm(formula = Rings ~ Sex + Diameter + Height + Whole.weight + 
#>     Shucked.weight + Viscera.weight + Shell.weight, data = abalone_train)
#> 
#> Residuals:
#>     Min      1Q  Median      3Q     Max 
#> -8.5698 -1.3077 -0.3312  0.8647 13.6374 
#> 
#> Coefficients:
#>                 Estimate Std. Error t value Pr(>|t|)    
#> (Intercept)      3.86685    0.31155  12.412  < 2e-16 ***
#> SexI            -0.80661    0.11556  -6.980 3.55e-12 ***
#> SexM             0.05085    0.09337   0.545    0.586    
#> Diameter        11.15705    1.10170  10.127  < 2e-16 ***
#> Height           8.89560    1.61878   5.495 4.19e-08 ***
#> Whole.weight    10.16941    0.81438  12.487  < 2e-16 ***
#> Shucked.weight -20.94418    0.91831 -22.807  < 2e-16 ***
#> Viscera.weight -12.39125    1.44439  -8.579  < 2e-16 ***
#> Shell.weight     7.79350    1.24853   6.242 4.86e-10 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> Residual standard error: 2.205 on 3332 degrees of freedom
#> Multiple R-squared:  0.545,  Adjusted R-squared:  0.5439 
#> F-statistic: 498.9 on 8 and 3332 DF,  p-value: < 2.2e-16

Dari hasil tersebut kita dapat menginterpretasikan sebagai berikut:

  • Jika dilihat dari variabel prediktor yang digunakan, pada model_abalone_backward tidak menggunakan variabel Length.
  • Nilai adjusted R-squared pada model tersebut sedikit lebih baik dibandingkan model_abalone_all dengan nilai 54.39%.

Prediction

Ketika kita sudah memiliki model_abalone_all dan model_abalone_backward, kita dapat melakukan prediksi menggunakan data abalone_test sehingga kita bisa menggunakan hasil predikisi tersebut untuk dilakukannya evaluasi. Untuk melakukan prediksi sebuah data kita akan menggunakan fungsi predict().

pred_abalone_all <- predict(
  object = model_abalone_all,
  newdata = abalone_test,
  interval = 'prediction',
  level = 0.95
)

head(pred_abalone_all)
#>          fit      lwr      upr
#> 1   9.292264 4.964093 13.62043
#> 5   6.781816 2.454521 11.10911
#> 13 10.605720 6.278030 14.93341
#> 15 10.468863 6.139252 14.79847
#> 16 11.122350 6.794977 15.44972
#> 22  7.674684 3.347691 12.00168
pred_abalone_backward <- predict(
  object = model_abalone_backward,
  newdata = abalone_test,
  interval = 'prediction',
  level = 0.95
)

head(pred_abalone_backward)
#>          fit      lwr      upr
#> 1   9.277729 4.950292 13.60517
#> 5   6.766354 2.439831 11.09288
#> 13 10.613264 6.286094 14.94043
#> 15 10.488872 6.160256 14.81749
#> 16 11.113333 6.786513 15.44015
#> 22  7.690938 3.364751 12.01712

Model Evaluation

Dikarenakan tujuan dari pembuatan model adalah untuk menghasilkan sebuah prediksi dari sebuah data baru (dalam kasus ini menggunakan data abalone_test). Maka diperlukan sebuah evaluasi dari model tersebut untuk melihat apakah model yang sudah kita buat sudah cocok dengan data yang kita gunakan apa belum. Kita akan melakukan evaluasi menggunakan MAPE.

Mean Absolute Percentage Error (MAPE)

MAPE menunjukkan seberapa besar penyimpangannya dalam bentuk persentase. Untuk melakukan perhitungan error tersebut kita akan menggunakan fungsi MAPE().

\[ MAPE = \frac{1}{n} \sum\frac{|\hat y - y|}{y} \]

MAPE(y_pred = pred_abalone_all, y_true = abalone_test$Rings)
#> [1] 0.3879198
MAPE(y_pred = pred_abalone_backward, y_true = abalone_test$Rings)
#> [1] 0.3877925

Dapat dilihat bahwa nilai MAPE dari model_abalone_all dan model_abalone_backward tidak berbeda jauh. Nilai MAPE model_abalone_all sebesar 38.79%, sedangkan model_abalone_backward memiliki error sebesar 38.77%.

Assumption Check

Terdapat beberapa asumsi yang diterapkan oleh model. Regresi linear memiliki beberapa asumsi yang perlu dipenuhi agar interpretasi yang didapatkan tidak bersifat bias. Asumsi ini hanya perlu dipenuhi jika tujuan membuat model regresi linear adalah menginginkan interpretasi atau melihat efek dari setiap prediktor terhadap nilai target variabel. Jika hanya ingin menggunakan regresi linear untuk melakukan prediksi, maka asumsi model tidak wajib dipenuhi.

Linearity

Untuk menguji apakah variabel target dan prediktor memiliki hubungan linear. Dapat dilihat dengan nilai korelasi menggunakan function ggcorr() atau dapat menggunakan uji statistik cor.test(). (ingin mendapatkan p-value < alpha agar tolak \(H_0\))

Linearity artinya target variabel dengan prediktornya memiliki hubungan yang linear atau hubungannya bersifat garis lurus. Selain itu, efek atau nilai koefisien antar variabel bersifat additive. Jika linearity ini tidak terpenuhi, maka otomatis semua nilai koefisien yang kita dapatkan tidak valid karena model berasumsi bahwa pola yang akan kita buat adalah linear.

Linearity hypothesis test:

\[ H_0: korelasi\ tidak\ signifikan\\ H_1: korelasi\ signifikan \]

ggcorr(abalone, label= T, label_size = 3, hjust = 1)

Normality of Residual

Harapannya ketika membuat model linear regression, error yang dihasilkan berdistribusi normal. Artinya error banyak berkumpul disekitar angka 0. Untuk menguji asumsi ini dapat dilakukan:

Uji statistik menggunakan shapiro.test(). (harapannya pvalue > alpha agar keputusan yang diambil adalah gagal tolak H0)

H0: error berdistribusi normal H1: error tidak berdistribusi normal

harapannya p-value > 0.05

Shapiro-Wilk hypothesis test:

hist(model_abalone_all$residuals)

shapiro.test(model_abalone_all$residuals)
#> 
#>  Shapiro-Wilk normality test
#> 
#> data:  model_abalone_all$residuals
#> W = 0.92577, p-value < 2.2e-16
shapiro.test(model_abalone_backward$residuals)
#> 
#>  Shapiro-Wilk normality test
#> 
#> data:  model_abalone_backward$residuals
#> W = 0.92544, p-value < 2.2e-16

Jika dilhat dari hasil shapiro.tes() nilai residual/error pada hasil prediksi tidak berdistribusi normal, yang mana artinya dari hasil prediksi errornya banyak yang mengumpul di titik 0.

Homoscedasticity of Residual

Homocesdasticity menunjukkan bahwa residual atau error bersifat konstan atau tidak membentuk pola tertentu. Jika error membentuk pola tertentu seperti garis linear atau mengerucut, maka kita sebut dengan Heterocesdasticity dan akan berpengaruh pada nilai standard error pada estimate/koefisien prediktor yang bias (terlalu sempit atau terlalu lebar).

Homocesdasticity bisa dicek secara visual dengan melihat apakah ada pola antara hasil prediksi dari data dengan nilai residualnya. Pada plot berikut terlihat bahwa tidak terdapat pola tertentu sehingga kita bisa menyimpulkan bahwa model sudah memiliki error yang konstan.

Berikut adalah beberapa pola yang dapat terbentuk dan menyebabkan Heteroscesdasticity.

Breusch-Pagan hypothesis test: (harapannya p-value > alpha agar gagal tolak H0)

\[ H_0: Variansi\ error\ menyebar\ konstan\ (Homoscedasticity)\\ H_1: Variansi\ error\ menyebar\ tidak\ konstan\ membentuk\ pola\ (Heteroscedasticity) \]

bptest(model_abalone_all)
#> 
#>  studentized Breusch-Pagan test
#> 
#> data:  model_abalone_all
#> BP = 345.29, df = 9, p-value < 2.2e-16
bptest(model_abalone_backward)
#> 
#>  studentized Breusch-Pagan test
#> 
#> data:  model_abalone_backward
#> BP = 338.77, df = 8, p-value < 2.2e-16

Nilai dari hasil bptest() kedua model memiliki p-value lebih kecil dari 0.05 yang berarti bahwa variansi error menyebar tidak konstan membentuk pola (Heteroscedasticity).

No Multicolinearity

Harapannya pada model linear regression, tidak terjadi multikolinearitas. Multikolinearitas terjadi ketika antar variabel prediktor yang digunakan pada model memiliki hubungan yang kuat. Ada atau tidak multikolinearitas dapat dilihat dari nilai VIF(Variance Inflation Factor):

Ketika nilai VIF lebih dari 10 artinya terjadi multikolinearitas. Harapannya mendapatkan VIF < 10

vif(model_abalone_all)
#>                      GVIF Df GVIF^(1/(2*Df))
#> Sex              1.558553  2        1.117327
#> Length          39.522842  1        6.286719
#> Diameter        40.913532  1        6.396369
#> Height           3.271041  1        1.808602
#> Whole.weight   111.232730  1       10.546693
#> Shucked.weight  28.774969  1        5.364230
#> Viscera.weight  17.627981  1        4.198569
#> Shell.weight    21.154552  1        4.599408
vif(model_abalone_backward)
#>                      GVIF Df GVIF^(1/(2*Df))
#> Sex              1.551196  2        1.116006
#> Diameter         8.190034  1        2.861823
#> Height           3.270109  1        1.808344
#> Whole.weight   111.231196  1       10.546620
#> Shucked.weight  28.648145  1        5.352396
#> Viscera.weight  17.458938  1        4.178389
#> Shell.weight    21.128100  1        4.596531

Dari hasil uji multikolinearitas pada kedua model, masih terdapat variabel yang memiliki nilai VIF lebih dari 10 yaitu Whole.weight dikarenakan kolom ini merupakan berat total dari abalone tersebut.

Conclusion

Dapat disimpulkan dari pembuatan kedua model multiple linear regression sebagai berikut:

  • Nilai Adjusted R-squared dari kedua model tersebut tidak berbeda jauh dengan nilai 54.38% untuk model_abalone_all sedangkan pada model_abalone_backward memiliki nilai 54.39%.
  • Nilai MAPE pada model_abalone_all sebesar 38.79%, sedangkan untuk model_abalone_backward sebesar 38.77%.
  • Dari uji asumsi linearity semua variabel prediktor memiliki hubungan linear dengan target variabel.
  • Nilai residual/error pada hasil prediksi tidak berdistribusi normal.
  • Variansi error dari kedua model menyebar tidak konstan membentuk pola (Heteroscedasticity).
  • Terdapat Multikolinearitas pada variabel Whole.weight.
 

A work by Muhammad Yusuf Ibrahim

myusufibrahim@outlook.com