Car Price Prediction

Reynaldi Gevin

01/06/2022

1. Hello World

Selamat datang di Rmd saya. Rmd ini saya buat untuk meningkatkan pemahaman saya tentang Machine Learning dengan Model Regresi Linier menggunakan bahasa R.

2. Business Goal

Kita diminta untuk memodelkan harga mobil dengan variabel bebas yang tersedia. Ini akan digunakan oleh manajemen untuk memahami bagaimana sebenarnya harga bervariasi dengan variabel independen. Oleh karena itu, mereka dapat memanipulasi desain mobil, strategi bisnis, dll. untuk memenuhi tingkat harga tertentu. Selanjutnya, model tersebut akan menjadi cara yang baik bagi manajemen untuk memahami dinamika harga pasar baru.

3. Brief explanation about the data

Dataset berisi beberapa parameter yang dianggap berpengaruh terhadap harga mobil.

3.1. Import Data

df1 <- read.csv("CarPrice_Assignment.csv")
rmarkdown::paged_table(df1)

3.2. Meta Data

  • Car_ID : Unique id of each observation (Interger)

  • Symboling : Its assigned insurance risk rating, A value of +3 indicates that the auto is risky, -3 that it is probably pretty safe.(Categorical)

  • carCompany : Name of car company (Categorical)

  • fueltype : Car fuel type i.e gas or diesel (Categorical)

  • aspiration : Aspiration used in a car (Categorical)

  • doornumber : Number of doors in a car (Categorical)

  • carbody : body of car (Categorical)

  • rivewheel : type of drive wheel (Categorical)

  • enginelocation : Location of car engine (Categorical)

  • wheelbase : Weelbase of car (Numeric)

  • carlength : Length of car (Numeric)

  • carwidth : Width of car (Numeric)

  • carheight : height of car (Numeric)

  • curbweight : The weight of a car without occupants or baggage. (Numeric)

  • enginetype : Type of engine. (Categorical)

  • cylindernumber : cylinder placed in the car (Categorical)

  • enginesize : Size of car (Numeric)

  • fuelsystem : Fuel system of car (Categorical)

  • boreratio : Boreratio of car (Numeric)

  • stroke : Stroke or volume inside the engine (Numeric)

  • compressionratio : compression ratio of car (Numeric)

  • horsepower : Horsepower (Numeric)

  • peakrpm : car peak rpm (Numeric)

  • citympg : Mileage in city (Numeric)

  • highwaympg : Mileage on highway (Numeric)

  • price(Dependent variable) : Price of car (Numeric)

4. Data Wrangling

Di tahapan ini akan dilakukan inspeksi secara mendalam serta perbaikan terhadap data set yang digunakan, agar nanti data ini dapat siap dipakai untuk pemodelan menggunakan machine learning.

4.1. Look deeper into the column with character data type

i =  1
while (i < 27){
  s <- df1 %>% select(i)
  t <- df1[,i]
  if (is.character(t) == TRUE) {
    print(colnames(s))
    print(unique(t))
    print("~~~~~~~**~~~~~~~")
  }
  else {
    print("###")
  }
  i = i +1
}
## [1] "###"
## [1] "###"
## [1] "CarName"
##   [1] "alfa-romero giulia"              "alfa-romero stelvio"            
##   [3] "alfa-romero Quadrifoglio"        "audi 100 ls"                    
##   [5] "audi 100ls"                      "audi fox"                       
##   [7] "audi 5000"                       "audi 4000"                      
##   [9] "audi 5000s (diesel)"             "bmw 320i"                       
##  [11] "bmw x1"                          "bmw x3"                         
##  [13] "bmw z4"                          "bmw x4"                         
##  [15] "bmw x5"                          "chevrolet impala"               
##  [17] "chevrolet monte carlo"           "chevrolet vega 2300"            
##  [19] "dodge rampage"                   "dodge challenger se"            
##  [21] "dodge d200"                      "dodge monaco (sw)"              
##  [23] "dodge colt hardtop"              "dodge colt (sw)"                
##  [25] "dodge coronet custom"            "dodge dart custom"              
##  [27] "dodge coronet custom (sw)"       "honda civic"                    
##  [29] "honda civic cvcc"                "honda accord cvcc"              
##  [31] "honda accord lx"                 "honda civic 1500 gl"            
##  [33] "honda accord"                    "honda civic 1300"               
##  [35] "honda prelude"                   "honda civic (auto)"             
##  [37] "isuzu MU-X"                      "isuzu D-Max "                   
##  [39] "isuzu D-Max V-Cross"             "jaguar xj"                      
##  [41] "jaguar xf"                       "jaguar xk"                      
##  [43] "maxda rx3"                       "maxda glc deluxe"               
##  [45] "mazda rx2 coupe"                 "mazda rx-4"                     
##  [47] "mazda glc deluxe"                "mazda 626"                      
##  [49] "mazda glc"                       "mazda rx-7 gs"                  
##  [51] "mazda glc 4"                     "mazda glc custom l"             
##  [53] "mazda glc custom"                "buick electra 225 custom"       
##  [55] "buick century luxus (sw)"        "buick century"                  
##  [57] "buick skyhawk"                   "buick opel isuzu deluxe"        
##  [59] "buick skylark"                   "buick century special"          
##  [61] "buick regal sport coupe (turbo)" "mercury cougar"                 
##  [63] "mitsubishi mirage"               "mitsubishi lancer"              
##  [65] "mitsubishi outlander"            "mitsubishi g4"                  
##  [67] "mitsubishi mirage g4"            "mitsubishi montero"             
##  [69] "mitsubishi pajero"               "Nissan versa"                   
##  [71] "nissan gt-r"                     "nissan rogue"                   
##  [73] "nissan latio"                    "nissan titan"                   
##  [75] "nissan leaf"                     "nissan juke"                    
##  [77] "nissan note"                     "nissan clipper"                 
##  [79] "nissan nv200"                    "nissan dayz"                    
##  [81] "nissan fuga"                     "nissan otti"                    
##  [83] "nissan teana"                    "nissan kicks"                   
##  [85] "peugeot 504"                     "peugeot 304"                    
##  [87] "peugeot 504 (sw)"                "peugeot 604sl"                  
##  [89] "peugeot 505s turbo diesel"       "plymouth fury iii"              
##  [91] "plymouth cricket"                "plymouth satellite custom (sw)" 
##  [93] "plymouth fury gran sedan"        "plymouth valiant"               
##  [95] "plymouth duster"                 "porsche macan"                  
##  [97] "porcshce panamera"               "porsche cayenne"                
##  [99] "porsche boxter"                  "renault 12tl"                   
## [101] "renault 5 gtl"                   "saab 99e"                       
## [103] "saab 99le"                       "saab 99gle"                     
## [105] "subaru"                          "subaru dl"                      
## [107] "subaru brz"                      "subaru baja"                    
## [109] "subaru r1"                       "subaru r2"                      
## [111] "subaru trezia"                   "subaru tribeca"                 
## [113] "toyota corona mark ii"           "toyota corona"                  
## [115] "toyota corolla 1200"             "toyota corona hardtop"          
## [117] "toyota corolla 1600 (sw)"        "toyota carina"                  
## [119] "toyota mark ii"                  "toyota corolla"                 
## [121] "toyota corolla liftback"         "toyota celica gt liftback"      
## [123] "toyota corolla tercel"           "toyota corona liftback"         
## [125] "toyota starlet"                  "toyota tercel"                  
## [127] "toyota cressida"                 "toyota celica gt"               
## [129] "toyouta tercel"                  "vokswagen rabbit"               
## [131] "volkswagen 1131 deluxe sedan"    "volkswagen model 111"           
## [133] "volkswagen type 3"               "volkswagen 411 (sw)"            
## [135] "volkswagen super beetle"         "volkswagen dasher"              
## [137] "vw dasher"                       "vw rabbit"                      
## [139] "volkswagen rabbit"               "volkswagen rabbit custom"       
## [141] "volvo 145e (sw)"                 "volvo 144ea"                    
## [143] "volvo 244dl"                     "volvo 245"                      
## [145] "volvo 264gl"                     "volvo diesel"                   
## [147] "volvo 246"                      
## [1] "~~~~~~~**~~~~~~~"
## [1] "fueltype"
## [1] "gas"    "diesel"
## [1] "~~~~~~~**~~~~~~~"
## [1] "aspiration"
## [1] "std"   "turbo"
## [1] "~~~~~~~**~~~~~~~"
## [1] "doornumber"
## [1] "two"  "four"
## [1] "~~~~~~~**~~~~~~~"
## [1] "carbody"
## [1] "convertible" "hatchback"   "sedan"       "wagon"       "hardtop"    
## [1] "~~~~~~~**~~~~~~~"
## [1] "drivewheel"
## [1] "rwd" "fwd" "4wd"
## [1] "~~~~~~~**~~~~~~~"
## [1] "enginelocation"
## [1] "front" "rear" 
## [1] "~~~~~~~**~~~~~~~"
## [1] "###"
## [1] "###"
## [1] "###"
## [1] "###"
## [1] "###"
## [1] "enginetype"
## [1] "dohc"  "ohcv"  "ohc"   "l"     "rotor" "ohcf"  "dohcv"
## [1] "~~~~~~~**~~~~~~~"
## [1] "cylindernumber"
## [1] "four"   "six"    "five"   "three"  "twelve" "two"    "eight" 
## [1] "~~~~~~~**~~~~~~~"
## [1] "###"
## [1] "fuelsystem"
## [1] "mpfi" "2bbl" "mfi"  "1bbl" "spfi" "4bbl" "idi"  "spdi"
## [1] "~~~~~~~**~~~~~~~"
## [1] "###"
## [1] "###"
## [1] "###"
## [1] "###"
## [1] "###"
## [1] "###"
## [1] "###"
## [1] "###"

Proses ini bertujuan untuk melihat secara lebih detil unique value dari data kategorik didalam dataset.

Selain kolom dengan tipe data character akan dicetak “###” sedangkan untuk kolom dengan tipe data character akan di print unique valuenya

4.2. Clean the words that are still typos

df1$CarName <- gsub("maxda", "mazda", df1$CarName)
df1$CarName <- gsub("Nissan", "nissan", df1$CarName)
df1$CarName <- gsub("toyouta", "toyota", df1$CarName)
df1$CarName <- gsub("vw", "volkswagen", df1$CarName)
df1$CarName <- gsub("vokswagen","volkswagen", df1$CarName)
df1$CarName <- gsub("porcshce", "porsche", df1$CarName)

Setelah diinspeksi setiap unique value dari kolom-kolom tersebut, ternyata beberapa kata masih belum tepat penulisannya sehingga harus diperbaiki. Hal ini dikarenakan kemungkinan adanya kesalahan dalam proses penginputan data.

4.3. Create a new column named cars

df1$cars <- sapply(strsplit(df1$CarName," "), "[", 1)
df1$cars <- sapply(gsub("-","_", df1$cars), "[", 1)

Dibuatlah satu kolom tambahan bernama cars, kolom ini berisi merek dari tiap nama mobil didalam dataset. Proses ini dilakukan dengan mengambil 1 kata pertama dari kolom “CarName” kemudian value tersebut dimasukkan kedalam kolom baru bernama cars. Penambahan kolom ini bertujuan agar nantinya saat proses EDA dapat di ekstrak insight lebih dari dataset yang dipakai.

4.4. Set data type

df1 <- df1 %>% mutate_if(is.character, as.factor)
str(df1)
## 'data.frame':    205 obs. of  27 variables:
##  $ car_ID          : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ symboling       : int  3 3 1 2 2 2 1 1 1 0 ...
##  $ CarName         : Factor w/ 142 levels "alfa-romero giulia",..: 1 3 2 4 5 9 5 7 6 8 ...
##  $ fueltype        : Factor w/ 2 levels "diesel","gas": 2 2 2 2 2 2 2 2 2 2 ...
##  $ aspiration      : Factor w/ 2 levels "std","turbo": 1 1 1 1 1 1 1 1 2 2 ...
##  $ doornumber      : Factor w/ 2 levels "four","two": 2 2 2 1 1 2 1 1 1 2 ...
##  $ carbody         : Factor w/ 5 levels "convertible",..: 1 1 3 4 4 4 4 5 4 3 ...
##  $ drivewheel      : Factor w/ 3 levels "4wd","fwd","rwd": 3 3 3 2 1 2 2 2 2 1 ...
##  $ enginelocation  : Factor w/ 2 levels "front","rear": 1 1 1 1 1 1 1 1 1 1 ...
##  $ wheelbase       : num  88.6 88.6 94.5 99.8 99.4 ...
##  $ carlength       : num  169 169 171 177 177 ...
##  $ carwidth        : num  64.1 64.1 65.5 66.2 66.4 66.3 71.4 71.4 71.4 67.9 ...
##  $ carheight       : num  48.8 48.8 52.4 54.3 54.3 53.1 55.7 55.7 55.9 52 ...
##  $ curbweight      : int  2548 2548 2823 2337 2824 2507 2844 2954 3086 3053 ...
##  $ enginetype      : Factor w/ 7 levels "dohc","dohcv",..: 1 1 6 4 4 4 4 4 4 4 ...
##  $ cylindernumber  : Factor w/ 7 levels "eight","five",..: 3 3 4 3 2 2 2 2 2 2 ...
##  $ enginesize      : int  130 130 152 109 136 136 136 136 131 131 ...
##  $ fuelsystem      : Factor w/ 8 levels "1bbl","2bbl",..: 6 6 6 6 6 6 6 6 6 6 ...
##  $ boreratio       : num  3.47 3.47 2.68 3.19 3.19 3.19 3.19 3.19 3.13 3.13 ...
##  $ stroke          : num  2.68 2.68 3.47 3.4 3.4 3.4 3.4 3.4 3.4 3.4 ...
##  $ compressionratio: num  9 9 9 10 8 8.5 8.5 8.5 8.3 7 ...
##  $ horsepower      : int  111 111 154 102 115 110 110 110 140 160 ...
##  $ peakrpm         : int  5000 5000 5000 5500 5500 5500 5500 5500 5500 5500 ...
##  $ citympg         : int  21 21 19 24 18 19 19 19 17 16 ...
##  $ highwaympg      : int  27 27 26 30 22 25 25 25 20 22 ...
##  $ price           : num  13495 16500 16500 13950 17450 ...
##  $ cars            : Factor w/ 22 levels "alfa_romero",..: 1 1 1 2 2 2 2 2 2 2 ...

Dilakukan penyesuaian tipe data, hal ini menjadi sagat penting karena untuk dapat menganalisisnya tiap kolom harus memiliki tipe data yang tepat sesuai dengan value yang ada didalamnya.

Semua kolom yang bertipe data character diubah menjadi factor, kolom dengan tipe data integer dan numeric sudah tepat

4.5. Cek missing value

colSums(is.na(df1))
##           car_ID        symboling          CarName         fueltype 
##                0                0                0                0 
##       aspiration       doornumber          carbody       drivewheel 
##                0                0                0                0 
##   enginelocation        wheelbase        carlength         carwidth 
##                0                0                0                0 
##        carheight       curbweight       enginetype   cylindernumber 
##                0                0                0                0 
##       enginesize       fuelsystem        boreratio           stroke 
##                0                0                0                0 
## compressionratio       horsepower          peakrpm          citympg 
##                0                0                0                0 
##       highwaympg            price             cars 
##                0                0                0

Tidak ada nilai yang kosong di dalam dataset yang dipakai

4.6. Cek Duplicate

ifelse(sum(duplicated(df1)) == 0, "Tidak ada data yang duplikat", "Ada data yang duplikat")
## [1] "Tidak ada data yang duplikat"

5. Simple EDA

Exploratory Data Analysis (EDA) atau dikenal pula dengan analisis data eksploratif merupakan pendekatan analisis untuk suatu data guna membuat gambaran keseluruhan (summary) data sehingga mudah untuk dipahami. Metode analisis ini menyediakan berbagai alat untuk meringkas dan memperoleh wawasan tentang sekumpulan data dengan cepat menggunakan grafik sebagai bentuk visualisasi data, tanpa menggunakan model statistik, atau formulasi hipotesis.

5.1. Facet Grid

ggplot(df1, aes(drivewheel,price, fill = doornumber)) + 
geom_boxplot() + facet_grid(fueltype~carbody) + 
theme(legend.title = element_text(size=15),
     legend.text = element_text(size = 12),
     axis.title.x = element_text(size = 15),
      axis.title.y = element_text(size = 15),
     axis.text.x = element_text(size = 10),
     axis.text.y = element_text(size = 10),
     strip.text = element_text(size = 12)) + 
scale_y_continuous(label = scales::comma_format()) +
  labs(title = "Analyze data distribution using facet grid", 
       subtitle = "Drivewheel x Price x Doornumber x Fueltype x Carbody") +
  theme_dark()

Insight :

  1. Sebagian besar mobil yang ada di dataset ini adalah mobil dengan jenis RWD

  2. Mobil dengan jenis RWD juga rata-rata paling mahal diantara jenis lainnya

  3. Mobil RWD didistribusikan di semua kategori carbody

  4. Jenis bahan bakar didominasi oleh gasoline dan masih sedikit mobil yang menggunakan solar

  5. Mobil convertible dan hardtop kebanyakan adalah mobil bertipe dua pintu

  6. Mobil wagon dan beberapa sedan kebanyakan bertipe dua pintu

5.2. Barplot

harga <- df1 %>% 
  group_by(cars) %>% 
  summarise(mean_price = min(price)) %>% 
  arrange(desc(mean_price))

ggplot(harga, aes(x = mean_price,
                  y = reorder(cars, mean_price),
                  fill = mean_price)) +
  geom_col() +
  scale_fill_gradient(low = "blue", high = "black") +
  theme_minimal() +
  labs(title = 'What is the most expensive car brand name?' ,
       x = 'Price',
       y = "Cars",
       fill = "Price Rate") +
  theme_minimal()

Insight :

Mobil dengan merk Jaguar mempunyai harga rata-rata paling mahal dan Subaru adalah merk mobil dengan harga rata-rata paling murah

6. Building Model

6.1. Prepare data

Sebelum melakukan modeling, terlebih dahulu untuk mempersiapkan data yang akan kita modelkan. Salah satu caranya adalah dengan mengeluarkan outliers yang ada di dalam kolom kategori. Dalam hal ini outliers yang dimaksud adalah kategori yang mengandung frekuensi yang paling sedikit dibandingkan dengan kateogri lainnya didalam satu kolom yang sama.

cylinder <- df1 %>% count(cylindernumber) %>% filter(n > 4)
df1 <- df1 %>% 
  filter(cylindernumber %in% c("five","four","six","eight"))
df1$cylindernumber <- factor(df1$cylindernumber, unique(df1$cylindernumber))

fuel <- df1 %>% count(fuelsystem) %>% filter(n > 4)
df1 <- df1 %>% 
  filter(fuelsystem %in% c("1bbl","2bbl","idi","mpfi","spdi"))
df1$fuelsystem <- factor(df1$fuelsystem, unique(df1$fuelsystem))

engine <- df1 %>% count(enginetype) %>% filter(n > 4)
df1 <- df1 %>% 
  filter(enginetype %in% c("dohc","l","ohc","ohcf","ohcv"))
df1$enginetype <- factor(df1$enginetype, unique(df1$enginetype))

Dalam kasus ini saya mengeluarkan kategori yang frekuensinya kurang dari 3 kali

Mari kita lihat apakah ada pola yang mengindikasi korelasi antar variabel yang akan kita modelkan

df_clean <- df1 %>% select(-c(car_ID,CarName,cars,symboling))
ggcorr(df_clean, label = TRUE, label_size = 2.9, hjust = 1, layout.exp = 2)

Dapat dilihat bahwa terdapat korelasi yang tinggi antar prediktor didalam data kita, ini dinamakan dengan multicolinearity yang dimana sebenarnya harus dihindari agar hasil pemodelannya dapat optimal

Dalam proses ini saya juga mengeluarkan kolom-kolom yang tidak diperlukan untuk pemodelan

Agar range antar data numerik sama untuk tiap data numerik, maka dilakukanlah scaling kepada semua data numeric.

# separate numeric and categoric data
df_cat <- df_clean %>% select_if(is.factor)
df_num <- df_clean %>% select_if(is.numeric)

# scaling
df_num_scal <- scale(df_num)

# bind numeric and categoric data
df_clean_scal <-df_cat %>% cbind(df_num_scal)

Metode scaling yang digunaka adalah Z-score Standarization

Tahap akhir persiapa data adalah membuat dummy variabel untuk prediktor kategorik yang akan kita gunakan

library(fastDummies)
df_model_dummy <- dummy_cols(df_clean_scal, remove_first_dummy = T)

#run a function to pinpoint factors(we need to remove them)
isfactor <- sapply(df_model_dummy,is.factor)

#final dataset for modelling
df2 <- df_model_dummy[,!isfactor]

Hal ini menjadi penting karena kalau kita mengeliminasi variabel categorical padahal variabel tersebut cukup berpengaruh, kita akan kehilangan banyak informasi sehingga harus dibuat dummy variabelnya

6.2. Split data set

Sebelum kita membuat model, kita perlu membagi data menjadi data train dan test. Data train akan digunakan untuk melatih model regresi linier. Data test akan digunakan sebagai pembanding dan melihat apakah model mengalami overfit atau model tidak dapat memprediksi data baru yang belum terlihat selama fase traning. Kami membagi datanya sebanyak 70% sebagai data train dan sisanya sebagai data test.

RNGkind(sample.kind = "Rounding") 
set.seed(123)

indeks <- sample(nrow(df2), 0.7*nrow(df2))

df_train <- df2[indeks,]

df_test <- df2[-indeks,]

6.3. Modelling

Modelling dengan model Regresi Linear

model_df <- lm(price ~ ., data = df_train)
summary(model_df)
## 
## Call:
## lm(formula = price ~ ., data = df_train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.6354 -0.1663 -0.0157  0.1312  1.0431 
## 
## Coefficients: (1 not defined because of singularities)
##                       Estimate Std. Error t value Pr(>|t|)    
## (Intercept)           1.727380   1.011197   1.708 0.090601 .  
## wheelbase             0.028070   0.082041   0.342 0.732933    
## carlength            -0.084237   0.106823  -0.789 0.432178    
## carwidth              0.263843   0.083681   3.153 0.002118 ** 
## carheight            -0.008327   0.052070  -0.160 0.873254    
## curbweight            0.223033   0.168749   1.322 0.189202    
## enginesize            0.584534   0.146748   3.983 0.000127 ***
## boreratio             0.019351   0.072457   0.267 0.789944    
## stroke               -0.192599   0.046099  -4.178 6.18e-05 ***
## compressionratio     -0.590647   0.322138  -1.834 0.069613 .  
## horsepower           -0.069577   0.127866  -0.544 0.587520    
## peakrpm               0.181793   0.047087   3.861 0.000198 ***
## citympg              -0.009294   0.153962  -0.060 0.951982    
## highwaympg            0.054314   0.155111   0.350 0.726930    
## fueltype_gas         -2.102081   1.064480  -1.975 0.050973 .  
## aspiration_turbo      0.194165   0.134593   1.443 0.152165    
## doornumber_two        0.038292   0.087696   0.437 0.663285    
## carbody_hardtop      -0.319818   0.237727  -1.345 0.181478    
## carbody_hatchback    -0.357537   0.212520  -1.682 0.095527 .  
## carbody_sedan        -0.191708   0.228986  -0.837 0.404416    
## carbody_wagon        -0.290100   0.255052  -1.137 0.258003    
## drivewheel_fwd       -0.116880   0.190127  -0.615 0.540076    
## drivewheel_rwd       -0.091597   0.222894  -0.411 0.681967    
## enginelocation_rear   1.261666   0.422143   2.989 0.003503 ** 
## enginetype_ohcv      -0.877169   0.206757  -4.243 4.84e-05 ***
## enginetype_ohc        0.529266   0.155495   3.404 0.000948 ***
## enginetype_l         -0.038821   0.247467  -0.157 0.875651    
## enginetype_ohcf       0.028628   0.286687   0.100 0.920652    
## cylindernumber_six    0.722539   0.235007   3.075 0.002699 ** 
## cylindernumber_five  -0.149074   0.179452  -0.831 0.408053    
## cylindernumber_eight  1.556897   0.456385   3.411 0.000925 ***
## fuelsystem_2bbl       0.014251   0.098283   0.145 0.884993    
## fuelsystem_1bbl      -0.022114   0.174880  -0.126 0.899619    
## fuelsystem_idi              NA         NA      NA       NA    
## fuelsystem_spdi      -0.367933   0.170054  -2.164 0.032805 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2916 on 103 degrees of freedom
## Multiple R-squared:  0.9405, Adjusted R-squared:  0.9214 
## F-statistic: 49.32 on 33 and 103 DF,  p-value: < 2.2e-16

Meskipun nilai adjusted R-squared yang dihasilkan tergolong baik, model yang terbentuk masih memiliki kesalahan. Ini karena masih ada fitur yang multicolinearity bahkan sampai terjadi singularity, ditandai dengan adanya NA disummary model

Singularitas adalah bentuk ekstrim dari multikolinearitas - ketika ada hubungan linier yang sempurna antara variabel atau, dalam istilah lain, ketika koefisien korelasi sama dengan 1,0 atau -1.0.

Exclude prediktor

model_df2 <- lm(price ~.-fuelsystem_idi,data = df_train)
summary(model_df2)
## 
## Call:
## lm(formula = price ~ . - fuelsystem_idi, data = df_train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.6354 -0.1663 -0.0157  0.1312  1.0431 
## 
## Coefficients:
##                       Estimate Std. Error t value Pr(>|t|)    
## (Intercept)           1.727380   1.011197   1.708 0.090601 .  
## wheelbase             0.028070   0.082041   0.342 0.732933    
## carlength            -0.084237   0.106823  -0.789 0.432178    
## carwidth              0.263843   0.083681   3.153 0.002118 ** 
## carheight            -0.008327   0.052070  -0.160 0.873254    
## curbweight            0.223033   0.168749   1.322 0.189202    
## enginesize            0.584534   0.146748   3.983 0.000127 ***
## boreratio             0.019351   0.072457   0.267 0.789944    
## stroke               -0.192599   0.046099  -4.178 6.18e-05 ***
## compressionratio     -0.590647   0.322138  -1.834 0.069613 .  
## horsepower           -0.069577   0.127866  -0.544 0.587520    
## peakrpm               0.181793   0.047087   3.861 0.000198 ***
## citympg              -0.009294   0.153962  -0.060 0.951982    
## highwaympg            0.054314   0.155111   0.350 0.726930    
## fueltype_gas         -2.102081   1.064480  -1.975 0.050973 .  
## aspiration_turbo      0.194165   0.134593   1.443 0.152165    
## doornumber_two        0.038292   0.087696   0.437 0.663285    
## carbody_hardtop      -0.319818   0.237727  -1.345 0.181478    
## carbody_hatchback    -0.357537   0.212520  -1.682 0.095527 .  
## carbody_sedan        -0.191708   0.228986  -0.837 0.404416    
## carbody_wagon        -0.290100   0.255052  -1.137 0.258003    
## drivewheel_fwd       -0.116880   0.190127  -0.615 0.540076    
## drivewheel_rwd       -0.091597   0.222894  -0.411 0.681967    
## enginelocation_rear   1.261666   0.422143   2.989 0.003503 ** 
## enginetype_ohcv      -0.877169   0.206757  -4.243 4.84e-05 ***
## enginetype_ohc        0.529266   0.155495   3.404 0.000948 ***
## enginetype_l         -0.038821   0.247467  -0.157 0.875651    
## enginetype_ohcf       0.028628   0.286687   0.100 0.920652    
## cylindernumber_six    0.722539   0.235007   3.075 0.002699 ** 
## cylindernumber_five  -0.149074   0.179452  -0.831 0.408053    
## cylindernumber_eight  1.556897   0.456385   3.411 0.000925 ***
## fuelsystem_2bbl       0.014251   0.098283   0.145 0.884993    
## fuelsystem_1bbl      -0.022114   0.174880  -0.126 0.899619    
## fuelsystem_spdi      -0.367933   0.170054  -2.164 0.032805 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2916 on 103 degrees of freedom
## Multiple R-squared:  0.9405, Adjusted R-squared:  0.9214 
## F-statistic: 49.32 on 33 and 103 DF,  p-value: < 2.2e-16

Interpretasi Model

  • Model pertama menghasilkan nilai Adj R-squared 0.9214 artinya model tersebut dapat menjelaskan 92,14% varians pada variabel target (price).

  • Variabel prediktor yang siginifikan memiliki nilai p-value < 0.05 yaitu yang diberi tanda “*”

  • Variabel yang berbanding lurus dengan price adalah cylindernumber_eight,cylindernumber_six,enginetype_ohcf,enginetype_ohc,enginelocation_rear,doornumber_two,aspiration_turbo,highwaympg,stroke,boreratio,enginesize,curbweight,carwidth, dan wheelbase

  • Sedangkan variabel yang berbanding terbalik dengan price variabel yang bertanda “-”

7. Predict

model_df2_pred <- predict(model_df2,newdata = df_test %>% select(-price))

Hasil prediksi di assign ke objek baru bernama model_df2_pred

8. Evaluation

Tujuan melakukan pemodelan yang bersifat prediktif adalah memprediksi data yang belum dimiliki. Untuk mengetahui model machine learning yang telah dibuat sudah bagus atau tidak dapat melihat dari error yang dihasilkan, diharapkan error yang dihasilkan sekecil mungkin.

# Train
RMSE(model_df2$fitted.values * sd(df_num$price) + mean(df_num$price), df_train$price * sd(df_num$price) + mean(df_num$price))
## [1] 1990.793
# Test
RMSE(model_df2_pred * sd(df_num$price) + mean(df_num$price), df_test$price * sd(df_num$price) + mean(df_num$price))
## [1] 2423.668

RMSE adalah bentuk akar kuadrat dari MSE. Karena sudah diakarkan, maka interpretasinya kurang lebih sama dengan MAE. RMSE dapat digunakan jika kita lebih concern dengan error yang sangat besar.

Pada kedua hasil train dan test, nilai RMSE untuk data train lebih rendah daripada data set, menunjukkan bahwa model yang dihasilkan mungkin overfit.

9. Assumptions

9.1. Linearity

linear <- data.frame(residual = model_df2$residuals, fitted = model_df2$fitted.values)

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

Berdasarkan pola yang ditampilkan menunjukkan bahwa model mungkin belum cukup linier.

9.2. Normality

shapiro.test(x = model_df2$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  model_df2$residuals
## W = 0.95053, p-value = 8.023e-05

Karena nilai p-value < 0.05 maka asumsi normalitas tidak terpenuhi, maka hasil uji signifikansi dan nilai standar error intercept dan slop masing-masing prediktor yang dihasilkan bias atau tidak mencerminkan nilai sebenarnya.

9.3. Homoscedasticity

library(lmtest)
bptest(model_df2)
## 
##  studentized Breusch-Pagan test
## 
## data:  model_df2
## BP = 44.501, df = 33, p-value = 0.08719

Karena p-value > 0.05 itu berarti eror varians tersebar secara acak atau konstan

9.4. Multicolinearity

library(car)
vif(model_df2)
##            wheelbase            carlength             carwidth 
##            11.617964            19.596824            11.818125 
##            carheight           curbweight           enginesize 
##             4.057035            47.844451            40.169246 
##            boreratio               stroke     compressionratio 
##             8.108016             3.618340           146.048414 
##           horsepower              peakrpm              citympg 
##            27.579552             3.380173            40.824701 
##           highwaympg         fueltype_gas     aspiration_turbo 
##            41.523585           145.869348             4.353111 
##       doornumber_two      carbody_hardtop    carbody_hatchback 
##             3.037412             3.201098            15.465764 
##        carbody_sedan        carbody_wagon       drivewheel_fwd 
##            21.087203            10.216570            13.904571 
##       drivewheel_rwd  enginelocation_rear      enginetype_ohcv 
##            18.547338             4.129335             5.084875 
##       enginetype_ohc         enginetype_l      enginetype_ohcf 
##             7.806349             6.674764             8.125780 
##   cylindernumber_six  cylindernumber_five cylindernumber_eight 
##            10.152588             2.514978             9.509804 
##      fuelsystem_2bbl      fuelsystem_1bbl      fuelsystem_spdi 
##             3.262970             2.388473             2.258455

Masih banyak prediktor yang berkolerasi tinggi dengan prediktor lainnya, ditandai dengan nilai VIF > 10. Sehingga dilakukan pemodelan lanjutan dengan mengubah prediktor agar tidak terjadi multicolinearity

10. Tunning

10.1. Modelling

model_df3 <- lm(price ~.-fuelsystem_idi-fueltype_gas-carwidth-drivewheel_rwd-carbody_sedan-enginesize-cylindernumber_six-drivewheel_rwd-horsepower-highwaympg-curbweight-carlength,data = df_train)
summary(model_df3)
## 
## Call:
## lm(formula = price ~ . - fuelsystem_idi - fueltype_gas - carwidth - 
##     drivewheel_rwd - carbody_sedan - enginesize - cylindernumber_six - 
##     drivewheel_rwd - horsepower - highwaympg - curbweight - carlength, 
##     data = df_train)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.7508 -0.2490 -0.0344  0.1987  2.4595 
## 
## Coefficients:
##                      Estimate Std. Error t value Pr(>|t|)    
## (Intercept)           0.18765    0.20140   0.932  0.35347    
## wheelbase             0.47003    0.08785   5.350 4.65e-07 ***
## carheight            -0.14662    0.06911  -2.122  0.03606 *  
## boreratio             0.04214    0.07759   0.543  0.58810    
## stroke                0.01878    0.05698   0.330  0.74237    
## compressionratio      0.08859    0.07399   1.197  0.23370    
## peakrpm              -0.02820    0.05961  -0.473  0.63708    
## citympg              -0.31409    0.09347  -3.360  0.00106 ** 
## aspiration_turbo      0.06333    0.13352   0.474  0.63620    
## doornumber_two        0.18234    0.12614   1.446  0.15106    
## carbody_hardtop      -0.39821    0.24391  -1.633  0.10533    
## carbody_hatchback    -0.23647    0.13038  -1.814  0.07238 .  
## carbody_wagon        -0.17694    0.14345  -1.234  0.21995    
## drivewheel_fwd       -0.21591    0.13154  -1.641  0.10350    
## enginelocation_rear   3.11031    0.45024   6.908 3.06e-10 ***
## enginetype_ohcv       0.01717    0.25172   0.068  0.94573    
## enginetype_ohc       -0.07627    0.19857  -0.384  0.70162    
## enginetype_l         -0.77577    0.25730  -3.015  0.00317 ** 
## enginetype_ohcf      -0.25401    0.34325  -0.740  0.46083    
## cylindernumber_five   0.11882    0.21707   0.547  0.58520    
## cylindernumber_eight  1.62910    0.33653   4.841 4.13e-06 ***
## fuelsystem_2bbl      -0.03307    0.13602  -0.243  0.80834    
## fuelsystem_1bbl       0.28732    0.24861   1.156  0.25025    
## fuelsystem_spdi      -0.29573    0.23764  -1.244  0.21589    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4541 on 113 degrees of freedom
## Multiple R-squared:  0.8417, Adjusted R-squared:  0.8095 
## F-statistic: 26.12 on 23 and 113 DF,  p-value: < 2.2e-16

10.2. Predict

model_df3_pred <- predict(model_df3,newdata = df_test %>% select(-price))

10.3. Evaluation

# Train
RMSE(model_df3$fitted.values * sd(df_num$price) + mean(df_num$price), df_train$price * sd(df_num$price) + mean(df_num$price))
## [1] 3246.904
# Test
RMSE(model_df3_pred * sd(df_num$price) + mean(df_num$price), df_test$price * sd(df_num$price) + mean(df_num$price))
## [1] 2939.855

Berdasarkan hasil RMSE didapat bahwa tidak terjadi over fitting karena nilai RMSE data test lebih kecil dibandingkan RMSE data train

10.4. Assumption

Linearity

linear2 <- data.frame(residual = model_df3$residuals, fitted = model_df3$fitted.values)

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

Berdasarkan pola yang ditampilkan menunjukkan bahwa model mungkin belum linier.

Normality

shapiro.test(x = model_df3$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  model_df3$residuals
## W = 0.85817, p-value = 3.857e-10

Karena nilai p-value < 0.05 maka asumsi normalitas tidak terpenuhi, maka hasil uji signifikansi dan nilai standar error intercept dan slop masing-masing prediktor yang dihasilkan bias atau tidak mencerminkan nilai sebenarnya.

Homoscedasticity

bptest(model_df3)
## 
##  studentized Breusch-Pagan test
## 
## data:  model_df3
## BP = 25.377, df = 23, p-value = 0.3311

Karena p-value > 0.05 itu berarti eror varians tersebar secara acak atau konstan

Multicolinearity

vif(model_df3)
##            wheelbase            carheight            boreratio 
##             5.494894             2.947375             3.834740 
##               stroke     compressionratio              peakrpm 
##             2.280374             3.177617             2.234081 
##              citympg     aspiration_turbo       doornumber_two 
##             6.205558             1.766769             2.591686 
##      carbody_hardtop    carbody_hatchback        carbody_wagon 
##             1.389837             2.400871             1.332890 
##       drivewheel_fwd  enginelocation_rear      enginetype_ohcv 
##             2.745154             1.937326             3.108549 
##       enginetype_ohc         enginetype_l      enginetype_ohcf 
##             5.250234             2.975992             4.804175 
##  cylindernumber_five cylindernumber_eight      fuelsystem_2bbl 
##             1.517782             2.132650             2.577629 
##      fuelsystem_1bbl      fuelsystem_spdi 
##             1.990854             1.818927

Tidak ada multicolinearity

11. Conclusion

Untuk melakukan evaluasi pada regression model dapat dilakukan dengan beberapa cara yaitu:

  • menggunakan nilai R-Squared dan Adj R-Squared
    • untuk menentukan seberapa baik model dalam menjelaskan variansi dari target variabel
  • menggunakan nilai error
    • untuk melihat apakah prediksi yang dibuat menghasilkan nilai error terkecil

Pada kasus ini dipilih model dengan pertama karena nilai RMSE yang lebih kecil dibandingkan dengan model hasi tunning. Pada model pertama prediktor yang paling berpengaruh terhadap target (price) adalah carheigh, enginesize, stroke, peakrpm, enginelocation_rear, enginetype_ohcv, enginetype_ohc, cylindernumber_six, cylindernumber_eight, dan fuelsystem_spdi

Nilai adjusted R-squared juga tinggi yang dimana 92.14% prediktor dapat menjelaskan varians harga mobil. Akurasi model untuk memprediksi diukur dengan nilai RMSE yang dihasilkan pada data test yaitu sebesar 2423.668.