1 Background:

Asuransi mobil menjadi salah satu jenis asuransi yang populer dan penting dalam industri asuransi di Indonesia. Kebanyakan orang yang memiliki kendaraan bermotor mengambil asuransi mobil untuk melindungi diri dari risiko finansial akibat kerusakan atau kehilangan kendaraan mereka. Namun, industri asuransi mobil dihadapkan pada tantangan meningkatnya angka kecelakaan lalu lintas di Indonesia dalam beberapa tahun terakhir.

Gambar1
Gambar1

Data yang dihimpun tim JEO Kompas.com dari Direktorat Penegakan Hukum pada Korps Lalu Lintas Polri menunjukkan tren yang memprihatinkan dalam angka kecelakaan lalu lintas di Indonesia. Dari tahun 2017 hingga 2019, angka kecelakaan lalu lintas mengalami peningkatan, dengan jumlah korban meninggal dunia dan kerugian materil yang signifikan. Meskipun terjadi penurunan angka kecelakaan pada tahun 2020, namun jumlah korban meninggal dunia tetap tinggi, yang kemungkinan dipengaruhi oleh pembatasan mobilitas akibat wabah Covid-19.

Menariknya, pada tahun 2021, angka kecelakaan lalu lintas kembali meningkat, meskipun terjadi penurunan pada tahun sebelumnya. Angka kecelakaan yang terus meningkat ini menjadi perhatian serius bagi perusahaan asuransi untuk mengoptimalkan proses klaim asuransi mobil dan mengelola risiko dengan lebih baik.

Gambar2
Gambar2

Pada tahun 2017, 2018, 2020, dan 2021, perilaku pengemudi yang ceroboh saat menghadapi lalu lintas dari depan menjadi penyebab utama kecelakaan lalu lintas. Sedangkan pada tahun 2019, faktor kelelahan pengemudi menjadi penyebab utama kecelakaan. Informasi ini memberikan wawasan yang penting bagi perusahaan asuransi dalam mengidentifikasi potensi risiko klaim asuransi mobil yang berkaitan dengan perilaku pengemudi.

Selain itu, data visualisasi juga menunjukkan bahwa sepanjang tahun 2017 hingga 2021, faktor utama kecelakaan berdasarkan klasifikasi awal kendaraan adalah rusaknya sistem rem, diikuti oleh kurang baiknya kemudi, kerusakan roda, kerusakan lampu, dan buatan yang berlebihan. Hal ini menunjukkan bahwa kondisi teknis dan mekanis kendaraan memiliki peran yang signifikan dalam menyebabkan kecelakaan lalu lintas.

Dengan informasi ini, pengembangan model prediksi klaim asuransi mobil menggunakan metode Machine Learning menjadi semakin relevan dan penting. Model ini akan memanfaatkan data mengenai pemegang polis, karakteristik kendaraan, masa polis, usia kendaraan, dan faktor-faktor lainnya sebagai fitur-fitur untuk melakukan prediksi apakah pemegang polis akan mengajukan klaim asuransi mobil atau tidak.

Melalui implementasi model prediksi yang akurat, perusahaan asuransi akan dapat mengidentifikasi potensi risiko klaim yang berkaitan dengan perilaku pengemudi dan kondisi kendaraan. Dengan demikian, perusahaan asuransi dapat mengambil langkah pencegahan yang tepat untuk mengurangi risiko kecelakaan dan klaim asuransi yang tinggi.

Selain itu, informasi dari data visualisasi juga memberikan peluang bagi perusahaan asuransi untuk memberikan edukasi dan program pelatihan kepada pemegang polis mengenai keselamatan berkendara dan pentingnya pemeliharaan kendaraan secara berkala. Langkah ini dapat membantu mengurangi risiko kecelakaan dan meningkatkan kesadaran pemegang polis tentang pentingnya memiliki asuransi mobil yang tepat.

Dengan mengintegrasikan data visualisasi ini ke dalam model prediksi klaim asuransi mobil menggunakan metode Machine Learning seperti Logistic Regression dan Decision Tree serta GridSearchCV untuk mencari parameter terbaik, perusahaan asuransi dapat meningkatkan kemampuan dalam mengelola risiko, menentukan premi yang tepat, dan memberikan layanan yang lebih baik kepada pemegang polis. Model ini juga akan membantu menciptakan lingkungan berkendara yang lebih aman dan membantu mengurangi angka kecelakaan lalu lintas di Indonesia secara keseluruhan.

2 Problem Statement:

Peningkatan angka kecelakaan lalu lintas di Indonesia dalam beberapa tahun terakhir telah menjadi perhatian serius bagi industri asuransi mobil. Dalam rangka mengoptimalkan proses klaim asuransi dan meningkatkan manajemen risiko, perusahaan asuransi perlu memiliki kemampuan prediksi yang akurat terkait potensi klaim dari pemegang polis mereka. Namun, dengan volume data yang besar dan beragam dari pemegang polis yang berbeda, metode analisis manual dan berfikir kritis menjadi kurang efisien.

3 Project Idea:

Proyek ini bertujuan untuk menjalankan analisis mendalam terhadap klaim asuransi mobil dengan memanfaatkan pendekatan Machine Learning, khususnya Logistic Regression dan Decision Tree, serta mengoptimalkan model-model tersebut dengan menggunakan GridSearchCV. Tujuan utama adalah untuk mengidentifikasi faktor-faktor yang memiliki dampak signifikan terhadap kemungkinan seorang pemegang polis mengajukan klaim asuransi mobil. Data yang digunakan akan mencakup beragam informasi, seperti karakteristik kendaraan, masa polis, usia kendaraan, dan sejarah klaim sebelumnya. Kami juga akan menggali faktor-faktor lain yang relevan yang memengaruhi keputusan pengajuan klaim. Dengan menerapkan teknik-teknik Machine Learning yang canggih, model yang dikembangkan akan memiliki kapasitas untuk melakukan prediksi dengan akurasi tinggi, memungkinkan perusahaan asuransi untuk memahami dan mengelola risiko lebih baik, serta memberikan layanan yang lebih baik kepada pemegang polis.

Hasil dari proyek ini diharapkan akan memberikan pemahaman yang lebih mendalam tentang faktor-faktor apa yang paling memengaruhi klaim asuransi mobil, sehingga perusahaan asuransi dapat mengambil langkah-langkah preventif yang lebih tepat dan mengoptimalkan penentuan premi secara lebih akurat. Selain itu, kami akan memperkenalkan elemen tambahan pada proyek ini dengan melakukan klastering pada pemegang polis. Ini akan memungkinkan kita untuk mengelompokkan pemegang polis ke dalam segmen-segmen yang berbeda berdasarkan perilaku dan karakteristik mereka. Dengan melakukan ini, perusahaan asuransi akan dapat memberikan layanan yang lebih spesifik dan disesuaikan dengan kebutuhan masing-masing kelompok pemegang polis, meningkatkan kepuasan pelanggan, dan pada gilirannya, menciptakan lingkungan berkendara yang lebih aman.

4 Problem Scope:

Proyek ini bertujuan untuk menganalisis dan melakukan prediksi klaim asuransi mobil dengan menggunakan metode Logistic Regression dan Decision Tree. Teknik GridSearchCV akan diterapkan untuk mengoptimalkan parameter-parameter model. Dataset yang digunakan berasal dari sumber Kaggle dengan judul “Car Insurance Claim Prediction - Classification”. Dataset ini mengandung informasi yang relevan mengenai pemegang polis asuransi mobil, seperti masa polis, usia mobil, usia pemilik mobil, merek dan model mobil, tenaga dan jenis mesin, serta variabel target yang menunjukkan apakah pemegang polis akan mengajukan klaim dalam 6 bulan mendatang.

Data dalam dataset mencakup atribut seperti policy_id (identifikasi polis), policy_tenure (masa polis), age_of_car (usia mobil), age_of_policyholder (usia pemilik mobil), area_cluster (kelompok wilayah), population_density (kepadatan penduduk kota), make (merek mobil), segment (segmen mobil), model (model mobil), fuel_type (jenis bahan bakar), max_torque (tenaga maksimum), max_power (daya maksimum), engine_type (jenis mesin), airbags (jumlah airbag), serta berbagai atribut lainnya yang terkait dengan spesifikasi teknis mobil. Car Insurance Claim Prediction | Kaggle

5 Output

Hasil dari proyek ini akan mencakup pengembangan model prediksi yang canggih untuk analisis dan prediksi klaim asuransi mobil yang akurat. Model ini akan memiliki kemampuan untuk mengidentifikasi potensi risiko klaim dengan tingkat akurasi yang tinggi berdasarkan data pemegang polis dan karakteristik kendaraan. Selain itu, proyek ini akan melibatkan penggunaan teknik klastering dan klasifikasi untuk mengelompokkan pemegang polis ke dalam segmen-segmen yang relevan berdasarkan perilaku klaim mereka.

Melalui penerapan Logistic Regression, Decision Tree, GridSearchCV, serta teknik klastering dan klasifikasi, proyek ini akan memberikan pemahaman mendalam tentang faktor-faktor apa yang memengaruhi kecenderungan pengajuan klaim asuransi. Model yang dihasilkan akan memungkinkan perusahaan asuransi untuk mengelola risiko dengan lebih efektif dan memberikan wawasan strategis tentang segmen pemegang polis.

6 Business Impact

Penerapan analisis dan prediksi klaim asuransi mobil dengan metode Logistic Regression dan Decision Tree, bersama dengan GridSearchCV dan teknik klastering dan klasifikasi, akan memiliki dampak positif yang substansial pada industri asuransi mobil. Perusahaan asuransi akan mampu mengidentifikasi dengan lebih baik potensi risiko klaim yang tinggi, memungkinkan pengambilan tindakan pencegahan yang lebih tepat waktu.

Selain itu, model ini akan memungkinkan perusahaan asuransi untuk menentukan premi dengan lebih akurat berdasarkan karakteristik pemegang polis dan kendaraan, meningkatkan keadilan dalam penilaian premi. Penggunaan teknik klastering dan klasifikasi juga akan membantu perusahaan asuransi dalam memahami profil pemegang polis mereka dengan lebih baik, sehingga dapat memberikan layanan yang lebih personal.

7 Read Library

Library yang digunakan adalah

library(dplyr)
library(ggplot2)
library(dplyr)
library(corrplot)
library(car)

# wrangling and EDA
library(tidyverse)
library(tidyquant)
library(lubridate)

# Visualization
library(ggthemes)
library(scales)

#clustering
library(factoextra)
library(FactoMineR)
library(dbscan) # DBSCAN
library(cluster) #K-Medoid

8 Import Data

Kita akan membaca dan menampilkan data yang akan kita analisis.

train <- read.csv("data_input/train.csv")
head(train)

9 Data Dictionary

Deskripsi Data :

Berikut adalah penjelasan tiap variabel dalam bahasa Indonesia:

  1. policy_id: Pengidentifikasi unik pemegang polis.
  2. policy_tenure: Masa kebijakan, yaitu jangka waktu polis.
  3. age_of_car: Usia mobil yang dinormalisasi dalam beberapa tahun.
  4. age_of_policyholder: Usia pemegang polis yang dinormalisasi dalam beberapa tahun.
  5. area_cluster: Klaster wilayah pemegang polis.
  6. population_density: Kepadatan penduduk kota (tempat tinggal pemegang polis).
  7. make: Produsen / perusahaan mobil yang disandikan.
  8. segment: Segmen mobil (A/B1/B2/C1/C2).
  9. model: Nama mobil yang dikodekan.
  10. fuel_type: Jenis bahan bakar yang digunakan oleh mobil.
  11. max_torque: Torsi Maksimum yang dihasilkan mobil ().
  12. max_power: Tenaga Maksimum yang dihasilkan mobil ().
  13. engine_type: Jenis mesin yang digunakan pada mobil.
  14. airbags: Jumlah airbag yang dipasang di mobil.
  15. is_esc: Bendera Boolean yang menunjukkan apakah Electronic Stability Control (ESC) ada di dalam mobil atau tidak.
  16. is_adjustable_steering: Bendera Boolean yang menunjukkan apakah setir mobil dapat disetel atau tidak.
  17. is_tpms: Bendera Boolean yang menunjukkan apakah Sistem Pemantauan Tekanan Ban (TPMS) ada di dalam mobil atau tidak.
  18. is_parking_sensors: Bendera Boolean yang menunjukkan apakah sensor parkir ada di dalam mobil atau tidak.
  19. is_parking_camera: Bendera Boolean yang menunjukkan apakah kamera parkir ada di dalam mobil atau tidak.
  20. rear_brakes_type: Jenis rem yang digunakan di bagian belakang mobil.
  21. displacement: Perpindahan mesin mobil (cc).
  22. cylinder: Jumlah silinder yang ada di mesin mobil.
  23. transmission_type: Jenis transmisi mobil.
  24. gear_box: Jumlah persneling di dalam mobil.
  25. steering_type: Jenis sistem kemudi mobil.
  26. turning_radius: Radius putar mobil.
  27. length: Panjang mobil.
  28. width: Lebar mobil.
  29. height: Tinggi mobil.
  30. gross_weight: Berat kotor mobil.
  31. is_front_fog_lights: Bendera Boolean yang menunjukkan apakah lampu kabut depan ada di mobil atau tidak.
  32. is_rear_window_wiper: Bendera Boolean yang menunjukkan apakah penghapus kaca belakang ada di mobil atau tidak.
  33. is_rear_window_washer: Bendera Boolean yang menunjukkan apakah penyiram kaca belakang ada di mobil atau tidak.
  34. is_rear_window_defogger: Bendera Boolean yang menunjukkan apakah penghangat kaca belakang ada di mobil atau tidak.
  35. is_brake_assist: Bendera Boolean yang menunjukkan apakah Brake Assist ada di mobil atau tidak.
  36. is_power_door_locks: Bendera Boolean yang menunjukkan apakah kunci pintu otomatis ada di mobil atau tidak.
  37. is_central_locking: Bendera Boolean yang menunjukkan apakah kunci sentral ada di mobil atau tidak.
  38. is_power_steering: Bendera Boolean yang menunjukkan apakah sistem kemudi daya ada di mobil atau tidak.
  39. is_driver_seat_height_adjustable: Bendera Boolean yang menunjukkan apakah ketinggian kursi pengemudi dapat diatur atau tidak.
  40. is_day_night_rear_view_mirror: Bendera Boolean yang menunjukkan apakah cermin pandang belakang dapat diatur sebagai day-night atau tidak.
  41. is_ecw: Bendera Boolean yang menunjukkan apakah Power Windows ada di mobil atau tidak.
  42. is_speed_alert: Bendera Boolean yang menunjukkan apakah fitur peringatan kecepatan ada di mobil atau tidak.
  43. ncap_rating: Rating NCAP (New Car Assessment Program) mobil.
  44. is_claim: Indikator apakah ada klaim (claim) asuransi yang diajukan atau tidak.
dim(train)
## [1] 58592    44

Sebelum melakukan pemodelan pada data Concrete kita, langkah pertama yang harus dilakukan adalah melakukan data preprocessing. Data preprocessing adalah proses untuk membersihkan dan menyiapkan data agar sesuai dengan persyaratan dan kebutuhan analisis atau pemodelan yang akan dilakukan. # Data Preprocessing

9.1 Check Data Type

Hal pertama yang kita lakukan adalah mengecek tipe data. APakah sudah sesuai atau tidak.

glimpse(train)
## Rows: 58,592
## Columns: 44
## $ policy_id                        <chr> "ID00001", "ID00002", "ID00003", "ID0…
## $ policy_tenure                    <dbl> 0.51587359, 0.67261851, 0.84111026, 0…
## $ age_of_car                       <dbl> 0.05, 0.02, 0.02, 0.11, 0.11, 0.07, 0…
## $ age_of_policyholder              <dbl> 0.6442308, 0.3750000, 0.3846154, 0.43…
## $ area_cluster                     <chr> "C1", "C2", "C3", "C4", "C5", "C6", "…
## $ population_density               <int> 4990, 27003, 4076, 21622, 34738, 1305…
## $ make                             <int> 1, 1, 1, 1, 2, 3, 4, 1, 3, 1, 1, 1, 1…
## $ segment                          <chr> "A", "A", "A", "C1", "A", "C2", "B2",…
## $ model                            <chr> "M1", "M1", "M1", "M2", "M3", "M4", "…
## $ fuel_type                        <chr> "CNG", "CNG", "CNG", "Petrol", "Petro…
## $ max_torque                       <chr> "60Nm@3500rpm", "60Nm@3500rpm", "60Nm…
## $ max_power                        <chr> "40.36bhp@6000rpm", "40.36bhp@6000rpm…
## $ engine_type                      <chr> "F8D Petrol Engine", "F8D Petrol Engi…
## $ airbags                          <int> 2, 2, 2, 2, 2, 6, 2, 2, 6, 6, 2, 2, 2…
## $ is_esc                           <chr> "No", "No", "No", "Yes", "No", "Yes",…
## $ is_adjustable_steering           <chr> "No", "No", "No", "Yes", "No", "Yes",…
## $ is_tpms                          <chr> "No", "No", "No", "No", "No", "Yes", …
## $ is_parking_sensors               <chr> "Yes", "Yes", "Yes", "Yes", "No", "Ye…
## $ is_parking_camera                <chr> "No", "No", "No", "Yes", "Yes", "Yes"…
## $ rear_brakes_type                 <chr> "Drum", "Drum", "Drum", "Drum", "Drum…
## $ displacement                     <int> 796, 796, 796, 1197, 999, 1493, 1497,…
## $ cylinder                         <int> 3, 3, 3, 4, 3, 4, 4, 4, 4, 4, 3, 3, 4…
## $ transmission_type                <chr> "Manual", "Manual", "Manual", "Automa…
## $ gear_box                         <int> 5, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 5, 5…
## $ steering_type                    <chr> "Power", "Power", "Power", "Electric"…
## $ turning_radius                   <dbl> 4.60, 4.60, 4.60, 4.80, 5.00, 5.20, 5…
## $ length                           <int> 3445, 3445, 3445, 3995, 3731, 4300, 3…
## $ width                            <int> 1515, 1515, 1515, 1735, 1579, 1790, 1…
## $ height                           <int> 1475, 1475, 1475, 1515, 1490, 1635, 1…
## $ gross_weight                     <int> 1185, 1185, 1185, 1335, 1155, 1720, 1…
## $ is_front_fog_lights              <chr> "No", "No", "No", "Yes", "No", "Yes",…
## $ is_rear_window_wiper             <chr> "No", "No", "No", "No", "No", "Yes", …
## $ is_rear_window_washer            <chr> "No", "No", "No", "No", "No", "Yes", …
## $ is_rear_window_defogger          <chr> "No", "No", "No", "Yes", "No", "Yes",…
## $ is_brake_assist                  <chr> "No", "No", "No", "Yes", "No", "Yes",…
## $ is_power_door_locks              <chr> "No", "No", "No", "Yes", "Yes", "Yes"…
## $ is_central_locking               <chr> "No", "No", "No", "Yes", "Yes", "Yes"…
## $ is_power_steering                <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Y…
## $ is_driver_seat_height_adjustable <chr> "No", "No", "No", "Yes", "No", "Yes",…
## $ is_day_night_rear_view_mirror    <chr> "No", "No", "No", "Yes", "Yes", "No",…
## $ is_ecw                           <chr> "No", "No", "No", "Yes", "Yes", "Yes"…
## $ is_speed_alert                   <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Y…
## $ ncap_rating                      <int> 0, 0, 0, 2, 2, 3, 5, 2, 3, 0, 0, 2, 2…
## $ is_claim                         <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1…

Dari hasil diatas dapat diketahui ada beberapa kolom yang belum sesuai tipe datanya sehingga kita akan mengubahnya.

unique(train$population_density)
##  [1]  4990 27003  4076 21622 34738 13051  6112  8794 17804 73430  6108 34791
## [13]  5410  7788   290 16206 65567 35036 27742 20905  3264 16733
train <- train %>% 
  mutate(area_cluster = as.factor(area_cluster),
         make = as.factor(make), 
         segment = as.factor(segment),
         model = as.factor(model),
         fuel_type = as.factor(fuel_type),
         max_torque = as.factor(max_torque),
         max_power = as.factor(max_power),
         engine_type = as.factor(engine_type),
         airbags = as.factor(airbags),
         is_esc = as.factor(is_esc),
         is_adjustable_steering = as.factor(is_adjustable_steering),
         is_tpms = as.factor(is_tpms),
         is_parking_sensors = as.factor(is_parking_sensors),
         is_parking_camera = as.factor(is_parking_camera),
         rear_brakes_type = as.factor(rear_brakes_type),
         displacement = as.factor(displacement),
         cylinder = as.factor(cylinder),
         transmission_type = as.factor(transmission_type),
         gear_box = as.factor(gear_box),
         steering_type = as.factor(steering_type),
         turning_radius = as.factor(turning_radius), # bisa dikelompokkan
         is_front_fog_lights = as.factor(is_front_fog_lights),
         is_rear_window_wiper = as.factor(is_rear_window_wiper),
         is_rear_window_washer = as.factor(is_rear_window_washer),
         is_rear_window_defogger = as.factor(is_rear_window_defogger),
         is_brake_assist = as.factor(is_brake_assist),
         is_power_door_locks = as.factor(is_power_door_locks),
         is_central_locking = as.factor(is_central_locking),
         is_power_steering = as.factor(is_power_steering),
         is_driver_seat_height_adjustable = as.factor(is_driver_seat_height_adjustable),
         is_day_night_rear_view_mirror = as.factor(is_day_night_rear_view_mirror),
         is_ecw = as.factor(is_ecw),
         is_speed_alert = as.factor(is_speed_alert),
         ncap_rating = as.factor(ncap_rating),
         is_claim = as.factor(is_claim)
)

9.2 Feature Selection

Lalu kita melakukan Feature Selection, pemahaman yang kuat tentang domain masalah dan tujuan analisis bisnis menjadi kunci untuk mengidentifikasi variabel yang relevan dan penting dalam memprediksi atau menjelaskan fenomena tertentu.Variabel yang tidak digunakan adalah policy_id, karena merupakan identifier.

# menghapus policy_id
data <-  train %>% 
  select(-policy_id,)

9.3 Outlier Detection

Kita harus ingat bahwa penting untuk memeriksa adanya outlier dalam data. Outlier adalah nilai yang secara signifikan berbeda dari sebagian besar data dan dapat mempengaruhi hasil analisis. Jika ditemukan outlier, langkah-langkah khusus perlu diambil untuk mengatasi masalah ini. Beberapa solusi untuk menangani outlier antara lain menghapus data outlier dari dataset, menggantikan outlier dengan nilai lain seperti median atau mean, atau menggunakan teknik analisis statistik yang lebih tahan terhadap outlier untuk mengurangi dampaknya.

# # Definisikan variabel numerik
# numeric_vars <- c("policy_tenure","age_of_car", "age_of_policyholder" ,"population_density", "width", "height", "gross_weight")
# # Fungsi untuk menampilkan boxplot dan menandai outlier pada variabel numerik
# plot_outliers <- function(data, var) {
#  ggplot(data, aes(x = 1, y = !!sym(var))) +
#  geom_boxplot(color = 'black', fill = 'skyblue', outlier.shape = NA) +
#  geom_jitter(width = 0.1, alpha = 0.7, color = 'red') +
#  labs(title = paste("Boxplot ", var), x = "", y = var) +
#  theme_minimal() +
#  theme(axis.text.x = element_blank())
# }
# # Menampilkan boxplot dan menandai outlier pada setiap variabel numerik
# for (var in numeric_vars) {
#  print(plot_outliers(data, var))
# }

Kita dapat melihat bebrapa kolom memiliki outlier sehingga kita akan mengatasinya dengan cara menghapus baris yang outlier.

9.3.1 Mengatasi outlier pada kolom age_of_car

Kolom age_of_car memiliki nilai outlier yang lebih besar dari 0.25, sehingga kita akan menghapus baris yang mengandung outlier tersebut. Setelah dilakukan penghapusan, kami akan menampilkan boxplot untuk menunjukkan bahwa outlier pada kolom tersebut telah dihilangkan dan tidak ada lagi dalam data.

# Fungsi untuk menemukan dan menampilkan outlier pada kolom tertentu
find_outliers <- function(column_data) {
  Q <- quantile(column_data, probs = c(0.25, 0.75), na.rm = FALSE)
  iqr <- IQR(column_data)
  up <- Q[2] + 1.5 * iqr # Upper Range  
  low <- Q[1] - 1.5 * iqr # Lower Range

  outliers <- column_data[column_data < low | column_data > up]
  return(outliers)
}

# Memanggil fungsi untuk menemukan outlier pada kolom data$age_of_car
outliers_age_of_car <- find_outliers(data$age_of_car)

# Menampilkan nilai outlier pada kolom data$age_of_car
print(outliers_age_of_car)
##   [1] 0.39 0.29 0.38 0.29 0.26 0.27 0.28 0.30 0.25 0.30 0.30 0.27 0.29 0.31 0.33
##  [16] 0.29 0.29 0.35 0.28 0.32 0.31 0.29 0.37 0.31 0.31 0.25 1.00 0.31 0.42 0.29
##  [31] 0.32 0.30 0.29 0.25 0.30 0.32 0.25 0.27 0.26 0.31 0.32 0.27 0.33 0.32 0.25
##  [46] 0.27 0.25 0.28 0.32 0.25 0.39 0.25 0.25 0.27 0.27 0.31 0.27 0.28 0.29 0.30
##  [61] 0.30 0.26 0.25 0.25 0.28 0.36 0.31 0.25 0.37 0.38 0.28 0.31 0.27 0.31 0.26
##  [76] 0.30 0.30 0.27 0.26 0.36 0.33 0.30 0.27 0.31 0.25 0.26 0.30 1.00 0.25 0.38
##  [91] 0.25 0.30 0.29 0.31 0.30 0.29 0.31 0.25 0.32 0.31 0.39 0.28 0.26 0.29 0.26
## [106] 0.30 0.26 0.33 0.26 0.27 0.30 0.25 0.30 0.31 0.30 0.31 0.29 0.25 0.28 0.31
## [121] 0.30 0.27 0.32 0.25 0.30 0.32 0.33 0.25 0.29 0.26 0.27 0.25 0.29 1.00 0.27
## [136] 0.29 0.25 0.25 0.45 0.49 0.26 0.25 0.25 0.28 0.30 0.36 0.46 0.25 0.30 0.27
## [151] 0.33 0.26 0.29 0.34 0.28 0.30 0.34 0.25 0.30 0.28 0.32 0.29 0.31 0.28 0.27
## [166] 0.31 0.25 0.25 0.26 0.46 0.82 0.27 0.44 0.25 0.25 0.31 0.30 0.28 0.26 0.25
## [181] 0.25 0.31 0.28 0.30 0.62 0.25 0.27 0.28 0.25 0.25 0.34 0.28 0.38 0.81 0.27
## [196] 0.34 0.32 0.26 0.30 0.27 0.39 0.28 0.28 0.31 0.33 0.28 0.27 0.29 0.30 0.29
## [211] 0.28 0.25 0.30 0.33 0.26 0.27 0.25 0.36 0.27 0.26 0.26 0.32 0.33 0.34 0.26
## [226] 0.25 0.25 0.33 0.25 0.28 0.27 0.25 0.28 0.27 0.26 0.27 0.37 0.29 0.25 0.31
## [241] 0.30 0.31 0.36 0.34 0.26 0.31 0.27 0.26 0.39 0.36 0.31 0.25 0.49 0.44 0.30
## [256] 0.33 0.25 0.26 0.30 0.27 0.30 0.28 0.33 0.28 0.36 0.25 0.36 0.32 0.28
# Filtering out rows where age_of_car is less than 0.25 (assuming age_of_car is the correct column name)
data <- data %>% filter(!(age_of_car >= 0.25))

# Creating a boxplot for the age_of_car column
boxplot(data$age_of_car)

# Checking the dimensions of the filtered_data
dim(data)
## [1] 58323    43

9.3.2 Mengatasi outlier pada kolom age_of_policyholder

Kolom age_of_policyholder memiliki nilai outlier yang lebih besar dari 0.8269231, sehingga kita akan menghapus baris yang mengandung outlier tersebut. Setelah dilakukan penghapusan, kami akan menampilkan boxplot untuk menunjukkan bahwa outlier pada kolom tersebut telah dihilangkan dan tidak ada lagi dalam data.

outliers_age_of_policyholder <- find_outliers(data$age_of_policyholder)
print(min(outliers_age_of_policyholder))
## [1] 0.8269231
data <- data %>% filter(!(age_of_policyholder >= 0.8269231))
boxplot(data$age_of_car)

dim(data)
## [1] 58158    43

10 Exploratory Data Analysis

Pada tahap Exploratory Data Analysis (EDA), tujuan utamanya adalah untuk mendapatkan wawasan dan pemahaman yang lebih mendalam tentang data yang akan digunakan dalam analisis atau pemodelan. Tujuan akhir dari EDA adalah untuk mempersiapkan data agar siap digunakan dalam analisis lebih lanjut dan pemodelan, serta untuk memastikan bahwa kita memiliki pemahaman yang kuat tentang data yang sedang dihadapi.

Sekarang kita akan melihat perbandingan pada kolom is_claim

library(ggplot2)
ggplot(data, aes(x = is_claim)) +
  geom_bar(fill = "darkblue") +
  geom_text(stat = "count", aes(label = ..count..), vjust = -0.5) +
  labs(x = "is_claim", y = "Count", title = "Countplot for is_claim")

Dari hasil bar di atas, dapat diketahui proporsi pengajuan klaim pada data sebagai berikut:

  • Tidak diajukan klaim (0): 54440 (93.58%)
  • Diajukan klaim (1): 3718 (6.42%)

Grafik Bar ini menggambarkan bahwa sebagian besar data memiliki klaim yang tidak diajukan (93.58%), sedangkan sejumlah kecil data (6.42%) mengajukan klaim.

10.1 Pada Kolom model

Bagaimana persebaran rating NCAP terkait dengan berbagai model mobil? Apakah terdapat kecenderungan bahwa beberapa model mobil lebih sering menggunakan transmisi otomatis daripada transmisi manual?

library(ggplot2)
library(dplyr)

# Data preparation
selected_columns <- c("model", "ncap_rating", "fuel_type", "age_of_car", "transmission_type", "is_brake_assist", "gross_weight", "airbags", "is_parking_camera")
selected_data <- data %>% select(all_of(selected_columns))

#  Distribusi Rating NCAP berdasarkan Model
ggplot(selected_data, aes(x = model, fill = factor(ncap_rating))) +
  geom_bar() +
  labs(title = "Distribusi Rating NCAP berdasarkan Model",
       x = "Model Mobil",
       y = "Jumlah Mobil",
       fill = "Rating NCAP")

# Jenis Transmisi pada Model Mobil
ggplot(selected_data, aes(x = model, fill = transmission_type)) +
  geom_bar() +
  labs(title = "Jenis Transmisi pada Model Mobil",
       x = "Model Mobil",
       y = "Jumlah Mobil",
       fill = "Jenis Transmisi")

Dalam analisis ini, saya memeriksa bagaimana rating NCAP terdistribusi pada berbagai model mobil. Hasil menunjukkan bahwa model mobil M1, M10, dan M7 memiliki rating NCAP 1, model M2, M3, M6, dan M8 memiliki rating NCAP 2, model M4 memiliki rating NCAP 3, model M9 memiliki rating NCAP 4, dan model M11 dan M5 memiliki rating NCAP 5.

Selanjutnya, saya juga mengevaluasi preferensi jenis transmisi pada berbagai model mobil. Temuan menunjukkan bahwa model mobil M2, M3, M4, dan M7 cenderung menggunakan transmisi otomatis, sementara model M1, M10, M11, M5, M6, M8, dan M9 lebih cenderung menggunakan transmisi manual.

10.2 Pada kolom policy_tenure

Berapa rata-rata masa kebijakan asuransi yang dimiliki pemegang polis? Bagaimana distribusi masa kebijakan asuransi dalam dataset ini?

# Visualisasi rata-rata masa kebijakan asuransi
ggplot(data, aes(x = policy_tenure)) +
  geom_histogram(binwidth = 0.1, fill = "skyblue", color = "black") +
  labs(title = "Distribusi Masa Kebijakan Asuransi",
       x = "Masa Kebijakan Asuransi",
       y = "Frekuensi") +
  theme_minimal()

# Visualisasi distribusi masa kebijakan asuransi
ggplot(data, aes(x = policy_tenure)) +
  geom_density(fill = "skyblue", color = "black") +
  labs(title = "Distribusi Masa Kebijakan Asuransi",
       x = "Masa Kebijakan Asuransi",
       y = "Density") +
  theme_minimal()

summary(data$policy_tenure)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## 0.002735 0.208908 0.571731 0.609758 1.037957 1.396641

Rata-rata masa kebijakan asuransi yang dimiliki pemegang polis adalah sekitar 0.609758 tahun (sekitar 7,32 bulan).

Distribusi masa kebijakan asuransi dalam dataset ini memiliki nilai minimum sekitar 0.002735 tahun (kurang dari satu hari), nilai median sekitar 0.571731 tahun (sekitar 6,86 bulan), dan nilai maksimum sekitar 1.396641 tahun (sekitar 16,76 bulan).

Secara keseluruhan, distribusi ini mencakup rentang waktu yang relatif pendek, dengan rata-rata sekitar 7,32 bulan. Poin menariknya adalah nilai median yang lebih rendah dari rata-rata, yang bisa mengindikasikan adanya outlier di sisi lebih tinggi dari distribusi. Dengan kata lain, sejumlah kecil pemegang polis mungkin memiliki masa kebijakan yang jauh lebih lama daripada mayoritas pemegang polis lainnya.

10.3 Pada kolom age_of_car

Bagaimana usia mobil terdistribusi dalam dataset?

# Memasukkan pustaka yang diperlukan
library(ggplot2)

# Menampilkan distribusi usia mobil
ggplot(data, aes(x = age_of_car)) +
  geom_histogram(binwidth = 0.02, fill = "skyblue", color = "black") +
  labs(title = "Distribusi Usia Mobil",
       x = "Usia Mobil",
       y = "Frekuensi") +
  theme_minimal()

summary(data$age_of_car)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## 0.00000 0.02000 0.06000 0.06827 0.11000 0.24000

Dari visualisasi diatas dapat diketahui bahwa sebagian besar mobil dalam dataset memiliki usia yang relatif muda (dalam rentang 0 hingga 0.11 tahun), dengan usia rata-rata sekitar 0.06827 tahun (sekitar 24,9 hari). Nilai median yang lebih rendah dari mean menunjukkan bahwa distribusi mungkin memiliki ekor panjang di sisi yang lebih tinggi.

10.4 Pada kolom age_of_policyholder

Bagaimana distribusi usia pemegang polis dalam dataset?

# Visualisasi distribusi usia pemegang polis
ggplot(data, aes(x = age_of_policyholder)) +
  geom_histogram(binwidth = 0.05, fill = "skyblue", color = "white") +
  labs(title = "Distribusi Usia Pemegang Polis",
       x = "Usia Pemegang Polis",
       y = "Jumlah") +
  theme_minimal()

summary(data$age_of_policyholder)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.2885  0.3654  0.4519  0.4681  0.5481  0.8269

Dari histogram dannilai-nilai ini, kita dapat menggambarkan distribusi usia pemegang polis sebagai berikut:

  • Distribusi memiliki kecenderungan mendekati simetri (bentuk mirip dengan distribusi normal) karena nilai rata-rata (mean) hampir sama dengan nilai median.
  • Sebagian besar usia pemegang polis berada dalam kisaran antara 0.3654 (kuartil pertama) dan 0.5481 (kuartil ketiga).

10.5 Pada kolom area_cluster

Bagaimana jumlah pemegang polis terdistribusi dalam setiap klaster wilayah? Apakah terdapat perbedaan jumlah klaim antara klaster wilayah yang berbeda?

# Load necessary libraries
library(ggplot2)

# Visualisasi distribusi jumlah pemegang polis dalam setiap klaster wilayah
ggplot(data, aes(x = area_cluster)) +
  geom_bar(fill = "dodgerblue", alpha = 0.7) +
  labs(title = "Distribusi Jumlah Pemegang Polis Berdasarkan Klaster Wilayah",
       x = "Klaster Wilayah",
       y = "Jumlah Pemegang Polis")

# Membandingkan jumlah klaim antara klaster wilayah yang berbeda
ggplot(data, aes(x = area_cluster, fill = factor(is_claim))) +
  geom_bar(position = "dodge") +
  labs(title = "Perbandingan Jumlah Klaim Berdasarkan Klaster Wilayah",
       x = "Klaster Wilayah",
       y = "Jumlah",
       fill = "Klaim") +
  scale_fill_manual(values = c("dodgerblue", "tomato"),
                    labels = c("Tidak Ada Klaim", "Ada Klaim"))

table(data$area_cluster)
## 
##    C1   C10   C11   C12   C13   C14   C15   C16   C17   C18   C19    C2   C20 
##  1459  3133  1205  1571  3394  3632   768   401   491   242   949  7310   107 
##   C21   C22    C3    C4    C5    C6    C7    C8    C9 
##   377   205  6079   660  6952   882  2158 13465  2718
table(data$area_cluster, data$is_claim)
##      
##           0     1
##   C1   1385    74
##   C10  2987   146
##   C11  1133    72
##   C12  1484    87
##   C13  3202   192
##   C14  3353   279
##   C15   730    38
##   C16   378    23
##   C17   472    19
##   C18   216    26
##   C19   878    71
##   C2   6793   517
##   C20   102     5
##   C21   348    29
##   C22   188    17
##   C3   5648   431
##   C4    609    51
##   C5   6551   401
##   C6    827    55
##   C7   2051   107
##   C8  12522   943
##   C9   2583   135

Distribusi Jumlah Pemegang Polis Berdasarkan Klaster Wilayah:

Klaster C1 memiliki 1459 pemegang polis. Klaster C10 memiliki 3133 pemegang polis. Klaster C11 memiliki 1205 pemegang polis. dan seterusnya hingga Klaster C9 memiliki 2718 pemegang polis.

Ya,terdapat perbedaan jumlah klaim antara klaster wilayah. Dalam perbandingan jumlah klaim berdasarkan klaster wilayah, kategori C8 menonjol karena memiliki mayoritas pemegang polis yang tidak mengajukan klaim, yaitu sebanyak 12.522 pemegang polis. Meskipun demikian, perlu dicatat bahwa ada sejumlah pemegang polis dalam kategori ini yang tetap mengajukan klaim, sebanyak 943 pemegang polis.

10.6 Pada kolom segment

Bagaimana jumlah mobil terdistribusi dalam setiap segmen mobil?

library(ggplot2)

# Visualisasi distribusi jumlah mobil dalam setiap segmen
ggplot(data, aes(x = segment, fill = segment)) +
  geom_bar() +
  geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.5, size = 3, color = "black") +
  labs(title = "Distribusi Jumlah Mobil Berdasarkan Segmen",
       x = "Segmen Mobil",
       y = "Jumlah Mobil") +
  theme_minimal()

Jumlah kendaraan yang terdistribusi pada masing-masing segmen mobil adalah sebagai berikut:

  • Segmen A: 17,291 kendaraan
  • Segmen B1: 4,149 kendaraan
  • Segmen B2: 18,122 kendaraan
  • Segmen C1: 3,529 kendaraan
  • Segmen C2: 13,863 kendaraan
  • Segmen Utility: 1,204 kendaraan

Data ini menggambarkan sebaran jumlah kendaraan dalam berbagai segmen mobil berdasarkan informasi yang telah di berikan. Hasilnya menunjukkan bahwa segmen B2 memiliki jumlah kendaraan terbanyak dibandingkan segmen lainnya, diikuti oleh segmen A dan C2.

10.7 Pada kolom is_tpms

bagaimana perbandingan mobil dengan Sistem Pemantauan Tekanan Ban (TPMS)?

library(ggplot2)

# Menghitung jumlah klaim untuk mobil dengan dan tanpa TPMS
claim_counts <- data %>%
  group_by(is_tpms, is_claim) %>%
  summarize(count = n())

# Visualisasi perbandingan mobil dengan TPMS terhadap is_claim
ggplot(claim_counts, aes(x = is_tpms, y = count, fill = factor(is_claim))) +
  geom_bar(stat = "identity", position = "stack") +
  labs(x = "TPMS (Tire Pressure Monitoring System)",
       y = "Number of Cars",
       fill = "Claim",
       title = "Comparison of TPMS and Claim") +
  scale_x_discrete(labels = c("No TPMS", "TPMS")) +
  scale_fill_manual(values = c("0" = "darkblue", "1" = "skyblue")) +
  theme_minimal()

table(data$is_tpms, data$is_claim)
##      
##           0     1
##   No  41469  2826
##   Yes 12971   892

Terlihat bahwa jumlah mobil tanpa TPMS yang mengajukan klaim (2,826) lebih tinggi daripada jumlah mobil dengan TPMS yang mengajukan klaim (892). Hal ini mungkin menunjukkan bahwa mobil tanpa TPMS cenderung memiliki risiko klaim yang lebih tinggi.

Mobil dengan TPMS memiliki jumlah klaim yang lebih rendah dibandingkan dengan mobil tanpa TPMS. Ini bisa mengindikasikan bahwa keberadaan TPMS dapat membantu dalam mencegah situasi yang dapat menyebabkan klaim, seperti kegagalan ban yang tidak terdeteksi.

10.8 Pada kolom fuel_type

Bagaimana pola distribusi jenis bahan bakar yang digunakan oleh mobil dalam dataset ini? Apakah terdapat hubungan antara jenis bahan bakar yang digunakan dengan adanya klaim asuransi?

library(ggplot2)

# Visualisasi distribusi jenis bahan bakar
ggplot(data, aes(x = fuel_type)) +
  geom_bar(fill = "skyblue") +
  labs(title = "Distribusi Jenis Bahan Bakar",
       x = "Jenis Bahan Bakar",
       y = "Jumlah Mobil")

# Visualisasi perbandingan jenis bahan bakar terhadap klaim
ggplot(data, aes(x = fuel_type, fill = factor(is_claim))) +
  geom_bar(position = "dodge") +
  labs(title = "Perbandingan Jenis Bahan Bakar terhadap Klaim",
       x = "Jenis Bahan Bakar",
       y = "Jumlah Mobil",
       fill = "Klaim") +
  scale_fill_manual(values = c("No" = "skyblue", "Yes" = "salmon")) +
  geom_text(stat = "count", aes(label = ..count..), position = position_dodge(width = 0.9), vjust = -0.5)

Dari hasil grafik batang yang menggambarkan “Distribusi Jenis Bahan Bakar”, terlihat bahwa jenis bahan bakar yang paling umum digunakan adalah petrol, diikuti oleh CNG (dalam jumlah yang hampir sama), dan diesel menjadi yang paling jarang digunakan.

Dalam konteks visualisasi “Perbandingan Jenis Bahan Bakar terhadap Klaim Asuransi”, diperoleh wawasan bahwa jumlah klaim asuransi pada mobil berbahan bakar petrol lebih tinggi daripada jenis bahan bakar lainnya, dengan jumlah klaim sebanyak 1346. Namun, jenis bahan bakar CNG memiliki jumlah tidak klaim yang lebih tinggi, yaitu sebanyak 19054, sedangkan jumlah klaimnya lebih rendah yaitu 1232.

11 Data Transformation

Selanjutnya kita masuk ke tahap preprocessing, dilakukan pengecekan apakah data sudah memiliki distribusi normal atau mengalami condong (skewness). Jika ditemukan bahwa data cenderung condong, maka akan diterapkan transformasi data untuk mengubahnya menjadi distribusi yang lebih mendekati normal. Transformasi ini bertujuan untuk mengatasi masalah ketidaksimetrisan data sehingga dapat mendukung analisis statistik yang lebih akurat dan andal.

library(moments)
# Periksa distribusi dari masing-masing variabel numerik
numeric_vars <- c("policy_tenure","age_of_car", "age_of_policyholder" ,"population_density", "width", "height", "gross_weight")

# Menampilkan histogram dan skewness dari masing-masing variabel numerik
for (var in numeric_vars) {
 print(paste("Skewness ", var, ":", round(skewness(data[[var]]), 2)))
}
## [1] "Skewness  policy_tenure : 0.06"
## [1] "Skewness  age_of_car : 0.59"
## [1] "Skewness  age_of_policyholder : 0.59"
## [1] "Skewness  population_density : 1.67"
## [1] "Skewness  width : -0.48"
## [1] "Skewness  height : 1.04"
## [1] "Skewness  gross_weight : 0.55"

Hasil di atas menunjukkan nilai skewness dari masing-masing variabel numerik pada dataset. Skewness mengukur tingkat ketidaksimetrisan distribusi data. Jika nilai skewness mendekati 0, maka distribusi data cenderung simetris. Jika nilai skewness positif, maka distribusi data cenderung condong ke kanan (ekor panjang di sebelah kanan). Sebaliknya, jika nilai skewness negatif, distribusi data cenderung condong ke kiri (ekor panjang di sebelah kiri).

11.1 Transformation using the sqrt function:

Dengan menggunakan fungsi sqrt pada proses transformasi, nilai-nilai pada variabel akan diakar kuadratkan, sehingga mengubah distribusi data menjadi lebih simetris dan dapat memperbaiki ketidaknormalan dalam data. Hasil dari transformasi ini akan membuat data lebih sesuai dengan asumsi yang diperlukan untuk beberapa analisis statistik atau algoritma machine learning.

# Identifikasi kolom-kolom numerik
numeric_cols <- sapply(data, is.numeric)

# Melakukan transformasi akar kuadrat (sqrt) untuk kolom-kolom numerik di train_x
for (col in names(data)[numeric_cols]) {
  data[[col]] <- sqrt(data[[col]])
}

summary(data)
##  policy_tenure      age_of_car     age_of_policyholder  area_cluster  
##  Min.   :0.0523   Min.   :0.0000   Min.   :0.5371      C8     :13465  
##  1st Qu.:0.4571   1st Qu.:0.1414   1st Qu.:0.6045      C2     : 7310  
##  Median :0.7561   Median :0.2449   Median :0.6723      C5     : 6952  
##  Mean   :0.7181   Mean   :0.2321   Mean   :0.6786      C3     : 6079  
##  3rd Qu.:1.0188   3rd Qu.:0.3317   3rd Qu.:0.7403      C14    : 3632  
##  Max.   :1.1818   Max.   :0.4899   Max.   :0.9094      C13    : 3394  
##                                                        (Other):17326  
##  population_density make         segment          model        fuel_type    
##  Min.   : 17.03     1:37896   A      :17291   M1     :14933   CNG   :20286  
##  1st Qu.: 78.18     2: 2358   B1     : 4149   M4     :13863   Diesel:17546  
##  Median : 93.78     3:13863   B2     :18122   M6     :13629   Petrol:20326  
##  Mean   :124.54     4: 1932   C1     : 3529   M8     : 4149                 
##  3rd Qu.:164.33     5: 2109   C2     :13863   M7     : 2919                 
##  Max.   :270.98               Utility: 1204   M3     : 2358                 
##                                               (Other): 6307                 
##           max_torque                max_power                    engine_type   
##  113Nm@4400rpm :17610   88.50bhp@6000rpm :17610   F8D Petrol Engine    :14933  
##  60Nm@3500rpm  :14933   40.36bhp@6000rpm :14933   1.5 L U2 CRDi        :13863  
##  250Nm@2750rpm :13863   113.45bhp@4000rpm:13863   K Series Dual jet    :13629  
##  82.1Nm@3400rpm: 4149   55.92bhp@5300rpm : 4149   K10C                 : 4149  
##  91Nm@4250rpm  : 2358   67.06bhp@5500rpm : 2358   1.2 L K Series Engine: 2919  
##  200Nm@1750rpm : 2109   97.89bhp@3600rpm : 2109   1.0 SCe              : 2358  
##  (Other)       : 3136   (Other)          : 3136   (Other)              : 6307  
##  airbags   is_esc      is_adjustable_steering is_tpms     is_parking_sensors
##  1: 1204   No :39956   No :23002              No :44295   No : 2358         
##  2:40172   Yes:18202   Yes:35156              Yes:13863   Yes:55800         
##  6:16782                                                                    
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  is_parking_camera rear_brakes_type  displacement   cylinder  transmission_type
##  No :35489         Disc:13863       1197   :17610   3:21798   Automatic:20202  
##  Yes:22669         Drum:44295       796    :14933   4:36360   Manual   :37956  
##                                     1493   :13863                              
##                                     998    : 4149                              
##                                     999    : 2358                              
##                                     1498   : 2109                              
##                                     (Other): 3136                              
##  gear_box   steering_type   turning_radius      length          width      
##  5:43937   Electric:23651   4.6    :14933   Min.   :58.69   Min.   :38.41  
##  6:14221   Manual  : 1204   4.8    :14691   1st Qu.:58.69   1st Qu.:38.92  
##            Power   :33303   5.2    :13863   Median :62.01   Median :41.65  
##                             4.7    : 4149   Mean   :61.99   Mean   :40.86  
##                             5      : 3932   3rd Qu.:63.21   3rd Qu.:41.89  
##                             4.85   : 2919   Max.   :65.57   Max.   :42.56  
##                             (Other): 3671                                  
##      height       gross_weight   is_front_fog_lights is_rear_window_wiper
##  Min.   :38.41   Min.   :32.42   No :24576           No :41376           
##  1st Qu.:38.41   1st Qu.:34.42   Yes:33582           Yes:16782           
##  Median :39.12   Median :36.54                                           
##  Mean   :39.40   Mean   :37.10                                           
##  3rd Qu.:40.44   3rd Qu.:38.86                                           
##  Max.   :42.72   Max.   :41.47                                           
##                                                                          
##  is_rear_window_washer is_rear_window_defogger is_brake_assist
##  No :41376             No :37847               No :26327      
##  Yes:16782             Yes:20311               Yes:31831      
##                                                               
##                                                               
##                                                               
##                                                               
##                                                               
##  is_power_door_locks is_central_locking is_power_steering
##  No :16137           No :16137          No : 1204        
##  Yes:42021           Yes:42021          Yes:56954        
##                                                          
##                                                          
##                                                          
##                                                          
##                                                          
##  is_driver_seat_height_adjustable is_day_night_rear_view_mirror is_ecw     
##  No :24218                        No :36081                     No :16137  
##  Yes:33940                        Yes:22077                     Yes:42021  
##                                                                            
##                                                                            
##                                                                            
##                                                                            
##                                                                            
##  is_speed_alert ncap_rating is_claim 
##  No :  358      0:19056     0:54440  
##  Yes:57800      2:21198     1: 3718  
##                 3:13863              
##                 4: 2109              
##                 5: 1932              
##                                      
## 

Dengan melakukan transformasi menggunakan sqrt, kita berharap mendapatkan hasil analisis atau pemodelan yang lebih akurat dan dapat dipercaya, serta memastikan bahwa data telah memenuhi asumsi yang diperlukan sebelum digunakan dalam analisis lebih lanjut.

11.2 Standarization

Setelah mengubah data, langkah berikutnya adalah melakukan standarisasi. Tujuan dari standarisasi adalah mengubah distribusi data agar memiliki rata-rata (mean) 0 dan deviasi standar (standard deviation) 1. Alasan utama untuk melakukan standarisasi setelah transformasi data adalah untuk mengatasi ketidakseimbangan variabel. Setelah transformasi, beberapa variabel mungkin memiliki rentang nilai yang sangat berbeda. Tanpa penyesuaian, variabel dengan rentang nilai yang besar dapat memiliki pengaruh yang dominan pada model atau analisis daripada variabel dengan rentang nilai yang lebih kecil. Dengan melakukan standarisasi, semua variabel akan memiliki rentang nilai yang serupa, sehingga kontribusi masing-masing variabel dalam analisis menjadi seimbang.

# Identifikasi kolom-kolom numerik pada train_x
numeric_cols_data <- sapply(data, is.numeric)

# Melakukan standarisasi untuk kolom-kolom numerik di train_x
for (col in names(data)[numeric_cols_data]) {
  data[[col]] <- (data[[col]] - mean(data[[col]])) / sd(data[[col]])
}

Setelah kita melakukan transformasi dan standarisasi, kita kembali melihat rangkuman data kita.

summary(data)
##  policy_tenure       age_of_car      age_of_policyholder  area_cluster  
##  Min.   :-2.1712   Min.   :-1.9334   Min.   :-1.62741    C8     :13465  
##  1st Qu.:-0.8513   1st Qu.:-0.7552   1st Qu.:-0.85266    C2     : 7310  
##  Median : 0.1239   Median : 0.1073   Median :-0.07333    C5     : 6952  
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.00000    C3     : 6079  
##  3rd Qu.: 0.9804   3rd Qu.: 0.8297   3rd Qu.: 0.70930    C14    : 3632  
##  Max.   : 1.5119   Max.   : 2.1479   Max.   : 2.65274    C13    : 3394  
##                                                          (Other):17326  
##  population_density make         segment          model        fuel_type    
##  Min.   :-1.8615    1:37896   A      :17291   M1     :14933   CNG   :20286  
##  1st Qu.:-0.8027    2: 2358   B1     : 4149   M4     :13863   Diesel:17546  
##  Median :-0.5327    3:13863   B2     :18122   M6     :13629   Petrol:20326  
##  Mean   : 0.0000    4: 1932   C1     : 3529   M8     : 4149                 
##  3rd Qu.: 0.6888    5: 2109   C2     :13863   M7     : 2919                 
##  Max.   : 2.5355              Utility: 1204   M3     : 2358                 
##                                               (Other): 6307                 
##           max_torque                max_power                    engine_type   
##  113Nm@4400rpm :17610   88.50bhp@6000rpm :17610   F8D Petrol Engine    :14933  
##  60Nm@3500rpm  :14933   40.36bhp@6000rpm :14933   1.5 L U2 CRDi        :13863  
##  250Nm@2750rpm :13863   113.45bhp@4000rpm:13863   K Series Dual jet    :13629  
##  82.1Nm@3400rpm: 4149   55.92bhp@5300rpm : 4149   K10C                 : 4149  
##  91Nm@4250rpm  : 2358   67.06bhp@5500rpm : 2358   1.2 L K Series Engine: 2919  
##  200Nm@1750rpm : 2109   97.89bhp@3600rpm : 2109   1.0 SCe              : 2358  
##  (Other)       : 3136   (Other)          : 3136   (Other)              : 6307  
##  airbags   is_esc      is_adjustable_steering is_tpms     is_parking_sensors
##  1: 1204   No :39956   No :23002              No :44295   No : 2358         
##  2:40172   Yes:18202   Yes:35156              Yes:13863   Yes:55800         
##  6:16782                                                                    
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  is_parking_camera rear_brakes_type  displacement   cylinder  transmission_type
##  No :35489         Disc:13863       1197   :17610   3:21798   Automatic:20202  
##  Yes:22669         Drum:44295       796    :14933   4:36360   Manual   :37956  
##                                     1493   :13863                              
##                                     998    : 4149                              
##                                     999    : 2358                              
##                                     1498   : 2109                              
##                                     (Other): 3136                              
##  gear_box   steering_type   turning_radius      length         
##  5:43937   Electric:23651   4.6    :14933   Min.   :-1.315296  
##  6:14221   Manual  : 1204   4.8    :14691   1st Qu.:-1.315296  
##            Power   :33303   5.2    :13863   Median : 0.006244  
##                             4.7    : 4149   Mean   : 0.000000  
##                             5      : 3932   3rd Qu.: 0.483965  
##                             4.85   : 2919   Max.   : 1.428429  
##                             (Other): 3671                      
##      width             height         gross_weight     is_front_fog_lights
##  Min.   :-1.7755   Min.   :-0.9932   Min.   :-1.6669   No :24576          
##  1st Qu.:-1.4018   1st Qu.:-0.9932   1st Qu.:-0.9536   Yes:33582          
##  Median : 0.5702   Median :-0.2829   Median :-0.2015                      
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000                      
##  3rd Qu.: 0.7431   3rd Qu.: 1.0386   3rd Qu.: 0.6244                      
##  Max.   : 1.2221   Max.   : 3.3262   Max.   : 1.5545                      
##                                                                           
##  is_rear_window_wiper is_rear_window_washer is_rear_window_defogger
##  No :41376            No :41376             No :37847              
##  Yes:16782            Yes:16782             Yes:20311              
##                                                                    
##                                                                    
##                                                                    
##                                                                    
##                                                                    
##  is_brake_assist is_power_door_locks is_central_locking is_power_steering
##  No :26327       No :16137           No :16137          No : 1204        
##  Yes:31831       Yes:42021           Yes:42021          Yes:56954        
##                                                                          
##                                                                          
##                                                                          
##                                                                          
##                                                                          
##  is_driver_seat_height_adjustable is_day_night_rear_view_mirror is_ecw     
##  No :24218                        No :36081                     No :16137  
##  Yes:33940                        Yes:22077                     Yes:42021  
##                                                                            
##                                                                            
##                                                                            
##                                                                            
##                                                                            
##  is_speed_alert ncap_rating is_claim 
##  No :  358      0:19056     0:54440  
##  Yes:57800      2:21198     1: 3718  
##                 3:13863              
##                 4: 2109              
##                 5: 1932              
##                                      
## 

12 Clustering

Clustering adalah proses pengelompokan data berdasarkan karakteristik atau atributnya yang mirip. Tujuan utama dari clustering adalah untuk membentuk kelompok atau cluster yang terdiri dari observasi atau data yang memiliki kesamaan atau kedekatan dalam karakteristik tertentu. Dalam proses clustering, observasi yang termasuk dalam satu cluster diharapkan memiliki kemiripan yang tinggi antara satu sama lain, sedangkan observasi yang termasuk dalam cluster yang berbeda seharusnya memiliki perbedaan karakteristik yang signifikan.

Sebelum melanjutkan dengan analisis clustering, langkah pertama adalah melakukan filter pada dataset untuk hanya menyertakan observasi yang memiliki nilai target (is_claim) sama dengan 1. Setelah itu, kita akan memilih hanya fitur-fitur yang memiliki tipe data numerik dari dataset ini. Ini dilakukan agar kita fokus pada data yang terkait dengan klaim (claim) saja. Setelah proses filtering selesai, kita akan melakukan pemeriksaan awal terhadap dataset yang telah difilter, termasuk melihat tipe data dan ringkasan statistiknya.

data_num <- data %>% 
  filter(is_claim == 1 ) %>% 
  select_if(is.numeric)
glimpse(data_num)
## Rows: 3,718
## Columns: 8
## $ policy_tenure       <dbl> -1.643600155, 0.498443430, 0.025677753, 0.91821753…
## $ age_of_car          <dbl> -0.4904312, 0.5658859, -1.9333872, 0.4229500, -1.1…
## $ age_of_policyholder <dbl> 0.16952914, -0.58352834, 1.21683219, 0.93042823, 0…
## $ population_density  <dbl> -1.0509405, 1.0707109, 0.3896176, 0.6888373, -0.53…
## $ length              <dbl> 0.006244311, 0.006244311, -1.315296299, 1.42842939…
## $ width               <dbl> 0.5702345, 0.5702345, -1.4018405, 1.0433744, -1.40…
## $ height              <dbl> -0.2829101, -0.2829101, -0.9932410, 1.0385812, -0.…
## $ gross_weight        <dbl> -0.2014773, -0.2014773, -0.9535817, 1.5544926, -0.…
summary(data_num)
##  policy_tenure       age_of_car       age_of_policyholder population_density
##  Min.   :-2.1676   Min.   :-1.93339   Min.   :-1.62741    Min.   :-1.86149  
##  1st Qu.:-0.2853   1st Qu.:-0.75522   1st Qu.:-0.67211    1st Qu.:-0.80273  
##  Median : 0.6298   Median :-0.07054   Median : 0.00846    Median :-0.53268  
##  Mean   : 0.3042   Mean   :-0.12840   Mean   : 0.07931    Mean   :-0.05654  
##  3rd Qu.: 1.0522   3rd Qu.: 0.70108   3rd Qu.: 0.70930    3rd Qu.: 0.68884  
##  Max.   : 1.4273   Max.   : 2.06198   Max.   : 2.65274    Max.   : 2.53547  
##      length              width              height          gross_weight     
##  Min.   :-1.315296   Min.   :-1.77546   Min.   :-0.99324   Min.   :-1.66686  
##  1st Qu.:-0.612453   1st Qu.:-1.40184   1st Qu.:-0.79822   1st Qu.:-0.95358  
##  Median : 0.006244   Median : 0.57023   Median :-0.28291   Median :-0.20148  
##  Mean   : 0.026119   Mean   : 0.03871   Mean   :-0.00676   Mean   : 0.01677  
##  3rd Qu.: 0.483965   3rd Qu.: 0.74314   3rd Qu.: 1.03858   3rd Qu.: 0.62437  
##  Max.   : 1.428429   Max.   : 1.22211   Max.   : 3.32619   Max.   : 1.55449

12.1 Optimum K Selection

Dalam menentukan k-optimum kita akan menggunakan elbow method. Elbow Plot merupakan plot antara banyak klaster dengan total dari simpangan/variasi per kluster (total WSS).

fviz_nbclust(
  x = data_num, #data untuk clustering
  FUNcluster = kmeans, #algoritma kmeans
  method = "wss" #berdasarkan wss
)

Pada tahap pemilihan nilai k untuk analisis clustering, kita ingin mencari nilai k yang tepat di mana penurunan total within sum of squares tidak lagi menurun secara drastis dan cenderung melandai. Nilai k ini dapat dianggap sebagai nilai k optimum yang paling cocok untuk data kita

Setelah melakukan analisis, nilai k optimum yang dipilih adalah 3.

12.2 K-means

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

# k-means dengan k optimum
data_cluster <- kmeans(data_num,centers = 3)

12.2.1 Hasil k-means

  1. Banyaknya observasi pada tipa cluster
# Jumlah data tiap cluster
data_cluster$size
## [1]  989 1750  979

Didapat bahwa pada cluster 1 = 989 data, cluster 2 = 1750 data, cluster 3 = 979 data

  1. Letak pusat cluster/centroid, biasa digunakan untuk profiling cluster
data_cluster$centers
##   policy_tenure age_of_car age_of_policyholder population_density      length
## 1    -0.2962897 -1.1982929         0.006521476          0.1200334 -1.22836381
## 2     0.5306581  0.2446304         0.104703547         -0.1194804  0.04058008
## 3     0.5059348  0.2856326         0.107458212         -0.1224086  1.26756459
##        width     height gross_weight
## 1 -1.3282397 -0.9524972   -0.9560309
## 2  0.3653425 -0.1496174   -0.2528313
## 3  0.8357416  1.2040015    1.4814236
  1. Label cluster untuk tiap observasi
# hasil clustering (label cluster untuk tiap observasi)
as.data.frame(data_cluster$cluster)
  1. Banyaknya pengulangan (iterasi) algoritma k-means sampai dihasilkan cluster yang stabil
data_cluster$iter
## [1] 3

12.2.2 Goodnes of Fit

Kebaikan hasil clustering dapat dilihat dari 3 nilai:

  1. Within Sum of Squares ($withinss): jumlah jarak kuadrat dari tiap observasi ke centroid tiap cluster.
  2. Between Sum of Squares ($betweenss): jumlah jarak kuadrat terbobot dari tiap centroid ke rata-rata global. Dibobotkan berdasarkan banyaknya observasi pada cluster.
  3. Total Sum of Squares ($totss): jumlah jarak kuadrat dari tiap observasi ke rata-rata global.
# cek nilai wss
data_cluster$withinss
## [1] 4106.206 7062.944 4130.073
data_cluster$tot.withinss
## [1] 15299.22
# cek nilai bss
data_cluster$betweenss
## [1] 13319.76
# cek nilai tss
data_cluster$totss
## [1] 28618.98
# cek rasio bss/tss
data_cluster$betweenss/data_cluster$totss
## [1] 0.4654169

Dari hasil diatas, nilai proporsi sebesar 0.46 (atau 46%) menunjukkan bahwa model K-means telah berhasil menjelaskan sekitar 48% variasi dalam data berdasarkan kluster yang dibentuk. Hal ini menandakan bahwa pengelompokan yang dilakukan oleh algoritma K-means cukup baik dalam menggambarkan pola-pola atau kelompok-kelompok yang ada dalam data kita.

12.2.3 Interpretation: Cluster Profiling

Membuat kolom baru yang berisikan informasi label dari cluster yang terbentuk menggunakan k optimum

data_num$cluster <- as.factor(data_cluster$cluster)
head(data_num)

Grouping data based on cluster label

Melakukan grouping berdasarkan cluster yang terbentuk, untuk mengetahui karakteristik dari masing-masing cluster

as.data.frame(data_cluster$centers)
# melakukan profiling cluster dari data asli (supaya nantinya jika ketemu dengan perlu data yg perlu discaling sebelum kmeans nya , interpretasinya tidak salah)
data_centroid <- data_num %>% 
  group_by(cluster) %>% 
  summarise_all(mean)
data_centroid

Untuk mempermudah profiling: tabel yang menampilkan cluster dengan nilai terendah dan tertinggi untuk masing-masing karakteristik whisky

library(tidyr)

data_centroid %>% 
  pivot_longer(-cluster) %>% 
  group_by(name) %>% 
  summarize(
    kelompok_min = which.min(value),
    kelompok_max = which.max(value))

💡 Profiling tiap cluster :

Berikut adalah label untuk setiap cluster berdasarkan hasil analisis K-means pada data kita:

Cluster 1 (Kelompok 1): - Fitur yang cenderung lebih rendah: age_of_car, age_of_policyholder, gross_weight, height, length, policy_tenure, width - Fitur yang cenderung lebih tinggi: population_density - Label: “Klaim Rendah, Polis Lama, Area Padat”

Cluster 2 (Kelompok 2): - Fitur yang cenderung lebih tinggi: policy_tenure - Label: “Klaim Tinggi, Polis Lama”

Cluster 3 (Kelompok 3): - Fitur yang cenderung lebih rendah: age_of_car, age_of_policyholder, gross_weight, height, length, width - Fitur yang cenderung lebih tinggi: population_density - Label: “Klaim Rendah, Polis Lama, Area Rendah”

Untuk mempermudah profiling: radar plot

Plot radat (radar plot) adalah jenis grafik yang digunakan untuk memvisualisasikan variasi nilai dari beberapa variabel atau atribut pada data dalam bentuk poligon dengan sumbu radial. Setiap sumbu mewakili satu atribut, dan jarak dari pusat poligon ke titik di setiap sumbu mencerminkan nilai atribut tersebut.

data_centroid %>% 
  pivot_longer(-cluster) %>%
  ggplot(aes(x = value, y = tidytext::reorder_within(name, value, cluster), fill = value)) +
  geom_col() +
  scale_fill_gradient(low = "pink", high = "navy") +
  facet_wrap(~cluster, scales = "free_y") +
  theme_minimal() +
  labs(title = "Karakteristik tiap Cluster",
       y = "",
       x = "Skor")

# install.packages("ggiraphExtra")
library(ggiraphExtra)

ggRadar(data=data_num, 
        aes(colour=cluster), 
        interactive=TRUE)

Interpretasi hasil sebelumnya (hasil K-means) berdasarkan plot radat ini dapat memberikan wawasan tentang karakteristik audio dari masing-masing kluster. Pada plot radat ini, kita dapat melihat seberapa tinggi atau rendah nilai atribut pada masing-masing kluster.

Misalnya, jika pada plot radat, kluster 1 menunjukkan karakteristik yang tinggi pada atribut “population_density”, tetapi rendah pada atribut “length” dan “height”.

  • Cluster 1 (Kelompok 1) tampaknya mewakili pelanggan yang memiliki klaim rendah. Ini dapat diindikasikan oleh fakta bahwa hampir semua fitur yang diukur, seperti usia kendaraan (age_of_car), usia pemegang polis (age_of_policyholder), berat kotor (gross_weight), tinggi (height), panjang (length), lebar (width), dan lama polis (policy_tenure) cenderung lebih rendah. Namun, area di mana pelanggan ini tinggal memiliki kepadatan penduduk yang lebih tinggi (population_density). Label yang sesuai untuk kluster ini mungkin adalah “Klaim Rendah, Polis Lama, Area Padat.”

  • Cluster 2 (Kelompok 2) cenderung memiliki nilai tinggi pada atribut “policy_tenure”, yang mengindikasikan bahwa mereka adalah pelanggan dengan polis lama. Namun, atribut lain tidak memiliki perbedaan yang signifikan dengan kelompok lainnya. Label yang sesuai untuk kluster ini mungkin adalah “Klaim Tinggi, Polis Lama.”

  • Cluster 3 (Kelompok 3) memiliki karakteristik yang berbeda dari dua kluster sebelumnya. Mereka cenderung memiliki nilai yang lebih rendah pada fitur usia kendaraan (age_of_car), usia pemegang polis (age_of_policyholder), berat kotor (gross_weight), tinggi (height), panjang (length), dan lebar (width). Namun, mereka juga tinggal di area dengan kepadatan penduduk yang lebih rendah (population_density). Label yang sesuai untuk kluster ini mungkin adalah “Klaim Rendah, Polis Lama, Area Rendah.”

Setelah berhasil melakukan proses clustering untuk mengelompokkan data pelanggan, langkah selanjutnya adalah melakukan klasifikasi pada data yang sudah di-klaim. Ini berarti kita ingin mengetahui keanggotaan kluster dari pelanggan yang telah melakukan klaim. Dengan demikian, kita dapat mengelompokkan pelanggan yang sudah melakukan klaim ke dalam tiga kelas yang telah terbentuk sebelumnya. Hasil dari klustering ini kemudian dapat menjadi masukan atau fitur tambahan dalam model klasifikasi, yang dapat digunakan untuk analisis lebih lanjut atau pengambilan keputusan yang lebih tepat terkait dengan pelanggan yang telah melakukan klaim. Dengan cara ini, kita dapat mengoptimalkan penggunaan informasi klustering dalam proses klasifikasi untuk mendapatkan wawasan yang lebih dalam dan akurat terkait dengan perilaku dan kebutuhan pelanggan.

12.3 Klasifikasi clustering menggunakan Decision Tree

df_claim <- data %>% 
  filter(is_claim == 1) %>% 
  select(- is_claim)

cluster <- data_num$cluster

# Menggabungkan dua data frame, df dan data_num, berdasarkan nama kolom yang sesuai
combined_df <- cbind(df_claim, cluster)  

glimpse(combined_df)
## Rows: 3,718
## Columns: 43
## $ policy_tenure                    <dbl> -1.643600155, 0.498443430, 0.02567775…
## $ age_of_car                       <dbl> -0.4904312, 0.5658859, -1.9333872, 0.…
## $ age_of_policyholder              <dbl> 0.16952914, -0.58352834, 1.21683219, …
## $ area_cluster                     <fct> C3, C5, C4, C2, C8, C8, C6, C18, C18,…
## $ population_density               <dbl> -1.0509405, 1.0707109, 0.3896176, 0.6…
## $ make                             <fct> 1, 1, 1, 3, 1, 1, 3, 1, 1, 1, 3, 1, 1…
## $ segment                          <fct> B2, B2, A, C2, A, B2, C2, B1, A, B2, …
## $ model                            <fct> M6, M6, M1, M4, M1, M6, M4, M8, M1, M…
## $ fuel_type                        <fct> Petrol, Petrol, CNG, Diesel, CNG, Pet…
## $ max_torque                       <fct> 113Nm@4400rpm, 113Nm@4400rpm, 60Nm@35…
## $ max_power                        <fct> 88.50bhp@6000rpm, 88.50bhp@6000rpm, 4…
## $ engine_type                      <fct> K Series Dual jet, K Series Dual jet,…
## $ airbags                          <fct> 2, 2, 2, 6, 2, 2, 6, 2, 2, 2, 6, 2, 6…
## $ is_esc                           <fct> No, No, No, Yes, No, No, Yes, No, No,…
## $ is_adjustable_steering           <fct> Yes, Yes, No, Yes, No, Yes, Yes, No, …
## $ is_tpms                          <fct> No, No, No, Yes, No, No, Yes, No, No,…
## $ is_parking_sensors               <fct> Yes, Yes, Yes, Yes, Yes, Yes, Yes, Ye…
## $ is_parking_camera                <fct> No, No, No, Yes, No, No, Yes, No, No,…
## $ rear_brakes_type                 <fct> Drum, Drum, Drum, Disc, Drum, Drum, D…
## $ displacement                     <fct> 1197, 1197, 796, 1493, 796, 1197, 149…
## $ cylinder                         <fct> 4, 4, 3, 4, 3, 4, 4, 3, 3, 4, 4, 3, 4…
## $ transmission_type                <fct> Manual, Manual, Manual, Automatic, Ma…
## $ gear_box                         <fct> 5, 5, 5, 6, 5, 5, 6, 5, 5, 5, 6, 5, 5…
## $ steering_type                    <fct> Electric, Electric, Power, Power, Pow…
## $ turning_radius                   <fct> 4.8, 4.8, 4.6, 5.2, 4.6, 4.8, 5.2, 4.…
## $ length                           <dbl> 0.006244311, 0.006244311, -1.31529629…
## $ width                            <dbl> 0.5702345, 0.5702345, -1.4018405, 1.0…
## $ height                           <dbl> -0.2829101, -0.2829101, -0.9932410, 1…
## $ gross_weight                     <dbl> -0.2014773, -0.2014773, -0.9535817, 1…
## $ is_front_fog_lights              <fct> Yes, Yes, No, Yes, No, Yes, Yes, No, …
## $ is_rear_window_wiper             <fct> No, No, No, Yes, No, No, Yes, No, No,…
## $ is_rear_window_washer            <fct> No, No, No, Yes, No, No, Yes, No, No,…
## $ is_rear_window_defogger          <fct> No, No, No, Yes, No, No, Yes, No, No,…
## $ is_brake_assist                  <fct> Yes, Yes, No, Yes, No, Yes, Yes, No, …
## $ is_power_door_locks              <fct> Yes, Yes, No, Yes, No, Yes, Yes, Yes,…
## $ is_central_locking               <fct> Yes, Yes, No, Yes, No, Yes, Yes, Yes,…
## $ is_power_steering                <fct> Yes, Yes, Yes, Yes, Yes, Yes, Yes, Ye…
## $ is_driver_seat_height_adjustable <fct> Yes, Yes, No, Yes, No, Yes, Yes, No, …
## $ is_day_night_rear_view_mirror    <fct> Yes, Yes, No, No, No, Yes, No, No, No…
## $ is_ecw                           <fct> Yes, Yes, No, Yes, No, Yes, Yes, Yes,…
## $ is_speed_alert                   <fct> Yes, Yes, Yes, Yes, Yes, Yes, Yes, Ye…
## $ ncap_rating                      <fct> 2, 2, 0, 3, 0, 2, 3, 2, 0, 2, 3, 2, 0…
## $ cluster                          <fct> 2, 2, 1, 3, 1, 2, 3, 1, 1, 2, 3, 2, 2…

12.3.1 Cross Validation

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

# index sampling
index <- sample(x = nrow(combined_df), size = nrow(combined_df) * 0.8)

# splitting
data_train <- combined_df[index, ]
data_test <- combined_df[-index, ]

12.3.2 Model Decision Tree

Decision Tree merupakan tree-based model yang cukup sederhana dengan performa yang robust/powerful untuk prediksi. Decision Tree menghasilkan visualisasi berupa pohon keputusan yang dapat diinterpretasi dengan mudah.

12.3.2.1 Membangun Model tanpa Pruning

library(partykit)
model_tree <- ctree(cluster ~ ., combined_df)
plot(model_tree)

plot(model_tree, type="simple")

Setelah kita latih data train maka kita bisa gunakan langsung pada data test. Evaluasi performa model complex

library(caret)

# prediksi kelas di data test
pred_pra_test <- predict(model_tree,data_test,type = "response")

# confusion matrix data test
conf_matrix_tree_pra <- confusionMatrix(pred_pra_test, data_test$cluster)
conf_matrix_tree_pra
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   1   2   3
##          1 176   3   0
##          2   1 366   0
##          3   0   0 198
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9946          
##                  95% CI : (0.9863, 0.9985)
##     No Information Rate : 0.496           
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9914          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.9944   0.9919   1.0000
## Specificity            0.9947   0.9973   1.0000
## Pos Pred Value         0.9832   0.9973   1.0000
## Neg Pred Value         0.9982   0.9920   1.0000
## Prevalence             0.2379   0.4960   0.2661
## Detection Rate         0.2366   0.4919   0.2661
## Detection Prevalence   0.2406   0.4933   0.2661
## Balanced Accuracy      0.9945   0.9946   1.0000
# prediksi kelas di data train
pred_pra_train <- predict(model_tree, data_train, type="response")

# confusion matrix data train
conf_matrix_dt_pra_train <- confusionMatrix(pred_pra_train, data_train$cluster)
conf_matrix_dt_pra_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    1    2    3
##          1  804   17    0
##          2    8 1364    0
##          3    0    0  781
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9916          
##                  95% CI : (0.9876, 0.9946)
##     No Information Rate : 0.4644          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9869          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.9901   0.9877   1.0000
## Specificity            0.9921   0.9950   1.0000
## Pos Pred Value         0.9793   0.9942   1.0000
## Neg Pred Value         0.9963   0.9894   1.0000
## Prevalence             0.2730   0.4644   0.2626
## Detection Rate         0.2703   0.4586   0.2626
## Detection Prevalence   0.2761   0.4613   0.2626
## Balanced Accuracy      0.9911   0.9913   1.0000

Untuk nilai Accuracy pada model_tree : > Data train = 99.16% & Data test = 99.46%

12.3.2.2 Membangun Model dengan Pruning

Dan kita akan coba juga untuk melakukan tuning model dengan mengatur parameter mincriterion = 0.90 dan minsplit = 15.

tree2_model <- ctree(cluster ~ ., combined_df, control = ctree_control(mincriterion=0.9, minsplit=15, minbucket=0))
plot(tree2_model)

plot(tree2_model, type = "simple")

library(caret)

# prediksi kelas di data test
pred_pra_test <- predict(tree2_model,data_test,type = "response")

# confusion matrix data test
conf_matrix_tree_pra <- confusionMatrix(pred_pra_test, data_test$cluster)
conf_matrix_tree_pra
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   1   2   3
##          1 176   2   0
##          2   1 367   0
##          3   0   0 198
## 
## Overall Statistics
##                                           
##                Accuracy : 0.996           
##                  95% CI : (0.9883, 0.9992)
##     No Information Rate : 0.496           
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9936          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.9944   0.9946   1.0000
## Specificity            0.9965   0.9973   1.0000
## Pos Pred Value         0.9888   0.9973   1.0000
## Neg Pred Value         0.9982   0.9947   1.0000
## Prevalence             0.2379   0.4960   0.2661
## Detection Rate         0.2366   0.4933   0.2661
## Detection Prevalence   0.2392   0.4946   0.2661
## Balanced Accuracy      0.9954   0.9960   1.0000
# prediksi kelas di data train
pred_pra_train <- predict(tree2_model, data_train, type="response")

# confusion matrix data train
conf_matrix_dt_pra_train <- confusionMatrix(pred_pra_train, data_train$cluster)
conf_matrix_dt_pra_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    1    2    3
##          1  809   11    0
##          2    3 1370    0
##          3    0    0  781
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9953          
##                  95% CI : (0.9921, 0.9974)
##     No Information Rate : 0.4644          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9927          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.9963   0.9920   1.0000
## Specificity            0.9949   0.9981   1.0000
## Pos Pred Value         0.9866   0.9978   1.0000
## Neg Pred Value         0.9986   0.9931   1.0000
## Prevalence             0.2730   0.4644   0.2626
## Detection Rate         0.2720   0.4607   0.2626
## Detection Prevalence   0.2757   0.4617   0.2626
## Balanced Accuracy      0.9956   0.9951   1.0000

Untuk nilai Accuracy pada tree2_model : > Data train = 99.43% & Data test = 99.6%

12.3.2.3 Kesimpulan

Hasil akurasi menunjukkan bahwa kedua model, baik model_tree maupun tree2_model, memiliki akurasi yang sangat tinggi pada kedua dataset (train dan test). Ini berarti kedua model tersebut mampu dengan sangat baik dalam mengklasifikasikan data ke dalam tiga cluster yang ada (cluster 1, 2, dan 3). Namun, jika kita membandingkan kinerja keduanya, model tree2_model memiliki sedikit keunggulan dalam akurasi dibandingkan dengan model_tree, terutama pada data tes.

Berdasarkan perbandingan ini, model tree2_model tampaknya lebih baik dalam mengklasifikasikan data menjadi tiga cluster (cluster 1, 2, dan 3) dibandingkan dengan model_tree.