Pada kesempatan kali ini saya akan membahas bagaimana menghadapi imbalance target variable dalam sebuah dataframe. Data tidak seimbang merupakan suatu keadaan dimana distribusi kelas data tidak memiliki proporsi yang sama, jumlah target kelas data (target variable) yang satu lebih sedikit atau lebih banyak dibanding dengan jumlah target kelas data lainnya. Kelompok target kelas data yang lebih sedikit dikenal dengan kelompok minoritas (minority), kelompok target kelas data yang lainnya disebut dengan kelompok mayoritas (mayority).
Jumlah target kelas data yang tidak seimbang pada dataframe yang kita miliki memang sudah menjadi sebuah masalah yang sering ditemui. Kondisi tersebut menyulitkan metode klasifikasi dalam melakukan fungsi generalisasi pada proses machine learning. Hampir semua algoritma klasifikasi seperti Naive Bayes, Decision Tree, KNearest Neighbor dan yang lainnya menunjukkan performa yang sangat buruk ketika bekerja pada data dengan target kelas yang sangat tidak seimbang. Metode-metode klasifikasi yang telah disebutkan di atas tidak delengkapi dengan kemampuan untuk menangani masalah ketidak seimbangan target kelas.
Klasifikasi pada data dengan target kelas tidak seimbang merupakan masalah utama pada bidang machine learning dan data mining, misalnya pada masalah medis, masalah klasifikasi teks, sosial media. Jika bekerja pada data tidak seimbang, hampir semua algoritma klasifikasi akan menghasilkan akurasi yang jauh lebih tinggi untuk kelas mayoritas daripada kelas minoritasPerbedaan ini merupakan suatu indikator performa klasifikasi yang buruk. Pada beberapa kasus, kelas minoritas justru lebih penting untuk diidentifikasi daripada kelas mayoritas. Misalnya pada kasus transaksi dengan kartu kredit, kebanyakan status transaksi adalah transaksi yang normal, hanya sedikit kasus yang dapat ditemukan dimana terjadi transaksi yang fraud. Meskipun demikian, keberadaan transaksi yang fraud jauh lebih penting untuk di identifikasi daripada transaksi yang normal meskipun jumlah kasusnya jauh lebih sedikit.
Itulah mengapa ada metode yang dapat digunakan untuk mengatasi masalah imbalance target variable yaitu Metode Undersampling dan Metode Oversampling.
- Metode Undersampling adalah sebuah metode dimana jumlah proporsi data yang kelas yang mayoritas akan dikurangin sehingga sama dengan kelas minoritas.
- Metode Oversampling adalah sebuah metode dimana jumlah proposi data yang kelas mintoritas akan ditambah sehingga sama dengan kelas mayoritas.
Akan tetapi jika kita hanya memanfaatkan fungsi downSample() dari library(caret) untuk melakukan metode undersampling kita akan membuang banyak sekali data dan membuang data berarti kita menghilangkan informasi-informasi yang bisa jadi sangat krusial oleh karena itu metode undersampling cukup jarang digunakan. Bagaimana dengan metode oversampling yang dapat kita implementasikan dengan fungsi upSample() dari library(caret) juga, fungsi upSample() memang dapat membantu dengan menambahkankan jumlah observasi untuk kelas yang minoritas akan tetapi penambahan datanya hanya melakukan duplikasi dari data yang sama sehingga data baru yang dihasilkan kurang memiliki keberagaman.
Nah apakah ada metode lain yang bisa kita manfaatkan sehingga kita dapat mempersiapkan sebuah dataframe yang memiliki jumlah kelas data yang tidak seimbang? Disini kita bisa memanfaatkan metode yang bernama SMOTE atau Synthetic Minority Oversampling Technique, metode itu adalah sebuah metode yang kurang lebih sama dengan metode oversampling yang menjadi perbedaanya dengan metode oversampling biasanya adalah metode SMOTE tidak hanya menduplikasi data yang sama akan tetapi SMOTE akan membuat sampel baru dari yang menyerupai data asli dari kelas minoritas untuk menyeimbangkan dataset, sehingga data baru dari kelas minoritas jauh lebih beragam.
SMOTE bisa membuat sampel data baru yang menyerupai data asli dengan menerapkan metode k nearest neigbours untuk setiap data di kelas minoritas, setelah itu dibuat data sintetis sebanyak duplikasi yang diinginkan antara data minor dan k nearest neighbors yang dipilih secara acak. Untuk memberikan gambaran bagaimana SMOTE bekerja dalam membuat data sintetis bisa dilihat dari gambar dibawah ini.
Untuk menggunakan metode SMOTE ada satu library yang perlu dipersiapkan yaitu library(UBL). Nantinya didalam tersebut akan ada sebuah fungsi yang bernama SmoteClassif(), dengan fungsi itulah yang akan digunakan untuk membuat distribusi target variabel kelas target dalam dataframe kita seimbang.
Sebgai contoh cara penggunaan fungsi SmoteClassif() beserta parameter pendukungnya, saya akan memberikan contoh dengan menggunakan data asuransi dari kagle. Data tersebut berisikan informasi mengenai apakah existing customer yang sudah memiliki asuransi kesehatan akan tertarik jika ditawarkan asuransi mobil bedaraskan informasi pribadi dari masing-masing customer.
insurance <- read.csv("insur.csv")
str(insurance)
## 'data.frame': 6868 obs. of 12 variables:
## $ id : int 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 ...
## $ Gender : chr "Female" "Male" "Female" "Female" ...
## $ Age : int 21 64 44 23 50 42 60 38 69 21 ...
## $ Driving_License : int 1 1 1 1 1 1 1 1 1 1 ...
## $ Region_Code : int 40 33 29 6 28 28 28 18 15 30 ...
## $ Previously_Insured : int 0 1 0 1 0 0 1 1 1 0 ...
## $ Vehicle_Age : chr "< 1 Year" "1-2 Year" "1-2 Year" "< 1 Year" ...
## $ Vehicle_Damage : chr "No" "No" "Yes" "No" ...
## $ Annual_Premium : int 2630 28046 28932 32819 25200 2630 2630 37367 38023 29497 ...
## $ Policy_Sales_Channel: int 160 124 26 152 26 124 125 26 122 160 ...
## $ Vintage : int 20 220 61 75 53 158 246 125 218 243 ...
## $ Response : int 0 0 0 0 0 0 0 0 0 0 ...
Kolom yang memberitahu apakah customer tersebut tertarik atau tidak adalah kolom Response, jika pada kolom tersebut valuenya adalah 0 berarti customer tersebut tidak tertarik dan jika valuenya adalah 1 berarti customer tersebut tertarik. Mari kita coba lihat proporsi antara customer yang tertarik dan tidak tertarik.
table(insurance$Response)
##
## 0 1
## 5240 1628
prop.table(table(insurance$Response))
##
## 0 1
## 0.7629586 0.2370414
Dari sini kita mengetahui bahwa persentase customer yang tidak tertarik sebanyak 5.240 customer atau sekitar 76,3% dan yang tertarik sebanyak 1.628 customer atau sekitar 23,7%. Perbedaan antara customer yang tertarik dan tidak cukup signifikan, dari observasi itu kita bisa menarik kesimpulan bahwa target variabel dari dataframe yang kita miliki tidaklah seimbang.
Mari kita coba implementasikan fungsi SmoteClassif(), tapi sebelum itu mari kita coab berkenalan lebih dalam ke beberapa paramter yang bisa digunakan. Pada fungsi SmoteClassif() ada 4 parameter yang perlu diperhatikan dalam proses penggunaanya:
- Parameter form: Parameter ini digunakan untuk memberitahu fungsi SmoteClassif kolom apa yang menjadi target variabel dan kolom apa saja yang menjadi kolom prediktor. Contoh penulisan untuk mengisi parameter form, form = nama kolom target variabel ~ nama kolom prediktor(jika semua kolom lain dipilih bisa diwakili dengan simbol titik/dot).
- Parameter dat: Parameter ini digunakan untuk memberitahu kolom apa saja yang ingin dibuat data sintesis dari dataframe yang digunakan. Contoh penulisan untuk mengisi parameter dat dat = nama_object_dataframe[, range_kolom].
- Parameter C.perc: Parameter ini adalah parameter yang akan berisikan list untuk mengatur persentase under- atau/dan over-sampling untuk diterapkan ke setiap kelas. Persentase over-sampling adalah angka di atas 1 sedangkan persentase under-sampling harus angka di bawah 1. Jika angka 1 diberikan untuk kelas tertentu maka kelas itu tetap tidak berubah. Atau mungkin bisa langsung mengisikan “balanced” untuk membuat proporsinya menjadi seimbang.
- Parameter dist: Parameter ini memungkinkan pengguna untuk menentukan metrik jarak yang akan digunakan dalam k nearest neighbors. Meskipun defaultnya adalah jarak Euclidean akan tetapi ada beberapa opsi lagi yang dapat digunakan untuk menghitung selain data numeric yaitu untuk data kategorikal Berikut adalah opsi yang bisa digunakan:
* Untuk data dengan fitur numerik saja: “Euclidean”
* Untuk data dengan fitur kategorikal saja: “Overlap”.
* Untuk menangani fitur kategorikal dan numerik: “HVDM”
library(UBL)
library(dplyr)
# Mengubah tipe data yang masih character menjadi factor
insurance <- insurance %>%
mutate(Response = as.factor(Response)) %>%
mutate_if(is.character, as.factor)
# Memilih kolom apa saja yang ingin dibuat data sintetisnya untuk paramter data
dat <- insurance[, c(2:12)]
insurance_smote <- SmoteClassif(form = Response ~ .,
dat = dat,
C.perc = "balance",
dist = "HVDM")
Setelah berhasil mengimplementasikan fungsi SmoteClassif() mari kita coba lihat proporsi datanya dengan menggunakan fungsi dibawah ini.
prop.table(table(insurance_smote$Response))
##
## 0 1
## 0.5 0.5
Dari fungsi diatas kita dapat mengetahui bahwa dengan target variabel untuk kelas yang minoritas telah berhasil disamakan atau dibuat balance dengan menggunakan fungsi SmoteClassif, nah setelah itu marilah kita coba lihat apakah data sintetis yang dibuat itu bervariasi atau tidak. Hal itu dapat diketahui dengan menggunakan memvisualkan dengan scatter plot untuk kolom Vintage & Age. Disini saya akan membuat 2 visualisasi yaitu sebelum dan sesuadah.
Visualisasi sebelum menambahkan data
library(dplyr)
library(ggplot2)
insurance %>%
mutate(Response = as.factor(Response)) %>%
ggplot(mapping = aes(x = Vintage , y = Age, color = Response)) +
geom_point() +
theme_classic()
Visualisasi sesudah menambahkan data
insurance_smote %>%
mutate(Response = as.factor(Response)) %>%
ggplot(mapping = aes(x = Vintage , y = Age, color = Response)) +
geom_point() +
theme_classic()
Hasil dari visualisasi scatter plot setelah menggunakan data yang sudah ditambahkan data sintetis sangatlah berbeda jika dibandingkan dengan hasil scatter plot sebelum ditambahkan data sintetis. Dari plot baru ini titik-titk yang berwarna hijau yang menandakan Response = 1 jauh lebih banyak, itu berarti bahwa data sintetis yang dibuat tidak hanya menduplikasi data yang sudah ada melainkan membuat sebuah data baru.
Selain membuat datanya seimbang dengan menggunakan parameter C.perc = "balance", kelas minoritas juga bisa dibuat sedikit lebih banyak dengan membuat sebuah list seperti dibawah ini.
# Memilih kolom apa saja yang ingin dibuat data sintetisnya untuk paramter data
dat <- insurance[, c(2:12)]
# Membuat list untuk memberitahu fungsi SmoteClassif kelas minoritas mau dibuah berapa kali lebih banyak jumlah datanya
almost_balanced <- list("0" = 1, "1" = 3)
insurance_smote2 <- SmoteClassif(form = Response ~ .,
dat = dat,
C.perc = almost_balanced,
dist = "HVDM")
table(insurance_smote2$Response)
##
## 0 1
## 5240 4884
prop.table(table(insurance_smote2$Response))
##
## 0 1
## 0.517582 0.482418
Object almost_balanced yang dibuat terlebih dahulu memiliki tugas untuk memberi tahu fungsi SmoteClassif() bahwa kelas mayoritas dan minoritas ingin dibuah berapa kali lebih banyak atau lebih sedikit. Dikarenakan kelas mayoritas atau response = 0 sudah cukup banyak maka hanya perlu diisi 1 atau jumlah datanya akan dibuat sama tanpa adanya penambahan atau pengurangan, sedangkan untuk kelas minoritas atau response = 1 perlu diperbanyak setidaknya 3 kali dari jumlah datanya yang sekarang. Disini saya bisa mengetahui bahwa data untuk kelas mayoritas memiliki jumlah observasi sebanyak 5.240 dan untuk kelas minoritas sebanyak 1.628, untuk membuat kelas minoritas hampir seimbang setidaknya kita perlu menambahkan jumlah datanya 3 kali dari jumlah data yang sekarang.
Dan jika dilihat dari hasil perhitungan jumlah data diatas, kita sudah berhasil untuk membuat jumlah data untuk kelas minoritas 3 kali lebih banyak dari data aslinnya. Sehingga data diatas juga sudah bisa digunakan untuk membuat sebuah model machine learning karena proporsi datanya bisa dibilang sudah seimbang.
Target kelas data yang tidak seimbang menjadi masalah saat membuat model machine learning klasifikasi. Salah satu cara untuk mengatasi masalah ini adalah dengan melakukan oversampling pada data minoritas. Alih-alih melakukan oversampling dengan mereplikasi data, kita dapat melakukan oversampling data dengan membuat data sintetis menggunakan teknik SMOTE dari library(UBL) dengan fungsi yang bernama SmoteClassif(). Semoga apa yang bagikan mengenai bagaimana menggunakan fungsi SMOTE untuk dapat berguna untuk kalian semua. Terimakasih dan selamat mencoba!