Penambangan Data

Penerapan Teknik Pengambilan Sampel Minoritas Sintetis (SMOTe) untuk Kumpulan Data yang Tidak Seimbang

Dalam Ilmu Data, kumpulan data yang tidak seimbang bukanlah hal yang mengejutkan. Jika kumpulan data yang ditujukan untuk masalah klasifikasi seperti Analisis Sentimen, Pencitraan Medis, atau masalah lain yang terkait dengan Analisis Prediktif Diskrit (misalnya-Prediksi Keterlambatan Penerbangan) memiliki jumlah kejadian (sampel atau titik data) yang tidak sama untuk kelas yang berbeda, maka kumpulan data tersebut dikatakan menjadi tidak seimbang. Artinya terdapat ketidakseimbangan antar kelas dalam dataset karena adanya perbedaan besar antara jumlah instance yang dimiliki masing-masing kelas. Kelas yang memiliki instance yang relatif lebih sedikit dibandingkan kelas lainnya dikenal sebagai minoritas dibandingkan dengan kelas yang memiliki jumlah sampel yang relatif lebih besar (dikenal sebagai mayoritas). Contoh kumpulan data yang tidak seimbang diberikan di bawah ini:

Melatih Model Machine Learning dengan kumpulan data yang tidak seimbang ini, sering kali menyebabkan model tersebut mengembangkan bias tertentu terhadap kelas mayoritas.

Untuk mengatasi masalah ketidakseimbangan kelas, Synthetic Minority Over-sampling Technique (SMOTe) diperkenalkan oleh Chawla et al. [3] pada tahun 2002.

Deskripsi singkat tentang SMOTe

  1. SMOTe adalah teknik berdasarkan tetangga terdekat yang dinilai dengan Jarak Euclidean antar titik data dalam ruang fitur.
  2. Terdapat persentase Over-Sampling yang menunjukkan jumlah sampel sintetik yang akan dibuat dan parameter persentase Over-sampling ini selalu kelipatan 100. Jika persentase Over-sampling adalah 100, maka untuk setiap instance, dibuat sampel baru. sampel akan dibuat. Oleh karena itu, jumlah instance kelas minoritas akan berlipat ganda. Begitu pula jika persentase Over-sampling adalah 200, maka jumlah sampel kelas minoritas akan bertambah tiga kali lipat.

Di SMOTe,

  • Untuk setiap instance minoritas, sejumlah k tetangga terdekat ditemukan sedemikian rupa sehingga mereka juga termasuk dalam kelas yang sama dimana,

  • Perbedaan antara vektor fitur dari instance yang dipertimbangkan dan vektor fitur dari k tetangga terdekat ditemukan. Jadi, diperoleh sejumlah k vektor selisih.
  • K vektor selisih masing-masing dikalikan dengan bilangan acak antara 0 dan 1 (tidak termasuk 0 dan 1).
  • Sekarang, vektor selisih, setelah dikalikan dengan bilangan acak, ditambahkan ke vektor fitur dari instance yang dipertimbangkan (instance minoritas asli) pada setiap iterasi.

Implementasi SMOTe dengan Python dari awal mengikuti di bawah ini —

import numpy as np
def nearest_neighbour(X, x, K):
    euclidean = np.ones(X.shape[0]-1)
    k = 0
    for j in range(0,X.shape[0]):
        if np.array_equal(X[j], x) == False:
            euclidean[k] = sqrt(sum((X[j]-x)**2))
            k = k + 1
    indices=list(sorted(range(len(euclidean)), key=lambda j: euclidean[j]))
    difference = []
    for j in range(0, K):
        difference.append((abs(x-X[indices[j]])))
    weight = random.random()
    while(weight == 0):
        weight = random.random()
    additive = np.multiply(difference,weight)
    return additive
def SMOTE(X, K):
    K = int(K/100)
    new = [None]*(K*X.shape[0]*X.shape[1])
    new = np.array(new).reshape(K*X.shape[0],X.shape[1])
    k = 0
    for i in range(0,X.shape[0]):
        additive = nearest_neighbour(X, X[i], K)
        for j in range(0, K):
            new[k] = X[i] + additive[j]
            k = k + 1
    return new

Penerapan SMOTe dalam praktek

Mari kita pertimbangkan Kumpulan Data Prediksi Pendapatan Sensus Dewasa dari UCI yang berisi 48.842 contoh dan 14 atribut/fitur.

Pemrosesan awal data dengan Implementasi Python:

  1. Pengkodean Labeldilakukan untuk fitur kategorikal (non-numerik) yang disebutkan dalam Tabel 1 (diberikan di bawah) dan label, pendapatan.
  2. Pemilihan Fitur dilakukan berdasarkan Skor Pentingnya Fitur yang diberikan oleh Pengklasifikasi Pohon Ekstra pada keseluruhan kumpulan data (ditunjukkan pada Tabel 1). Karena ras dan negara asalmemberikan Skor Pentingnya Fitur terendah, 2 fitur ini dikecualikan dalam Pengembangan Model.
  3. Encoding One-Hotdilakukan untuk Fitur Kategorikal yang memiliki lebih dari 2 kategori. Dalam One-Hot Encoding, fitur kategorikal dibagi menjadi sub-fitur yang masing-masing sesuai dengan salah satu kategorinya (dari fitur kategorikal utama) dengan asumsi nilai biner 0/1. Di sini, fitur kategorikal, kelas kerja, pendidikan, status perkawinan, pekerjaan,danhubungan dikodekan One-Hot. Karena seksadalah fitur yang hanya memiliki 2 sub-kategori (pria dan wanita), maka fitur tersebut tidak dikodekan lagi dalam One-Hot Encoded untuk menghindari kutukan dimensi.

Menerapkan One-Hot Encoding dengan Python setelah Pemilihan Fitur….

import numpy as np
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
# Label Encoding and Feature Selection is over ....
# 1. Loading the modified dataset after Label Encoding
df = pd.read_csv('adult.csv') 
# Loading of Selected Features into X
X = df.iloc[:,[0,1,2,3,4,5,6,7,9,10,11,12]].values
# Loading of the Label into y
y = df.iloc[:,14].values
# 2. One Hot Encoding ....
onehotencoder = OneHotEncoder(categorical_features = [1,3,5,6,7])
X = onehotencoder.fit_transform(X).toarray()

Sekarang, label kelas dalam soal ini adalah biner. Artinya label kelas mengasumsikan 2 nilai yaitu ada 2 kelas. Jadi, ini adalah Masalah Klasifikasi Biner.

Visualisasi Distribusi Kelas

# Getting the no. of instances with Label 0
n_class_0 = df[df['income']==0].shape[0]
# Getting the no. of instances with label 1
n_class_1 = df[df['income']==1].shape[0]
# Bar Visualization of Class Distribution
import matplotlib.pyplot as plt # required library
x = ['0', '1']
y = np.array([n_class_0, n_class_1])
plt.bar(x, y)
plt.xlabel('Labels/Classes')
plt.ylabel('Number of Instances')
plt.title('Distribution of Labels/Classes in the Dataset')

Jadi pada dataset yang diberikan terdapat Ketidakseimbangan Bruto antara 2 kelas dengan Label Kelas, '1' sebagai Minoritas dan Label Kelas, '0' sebagai Mayoritas.

Sekarang, ada 2 pendekatan yang mungkin:

  1. Mengocok dan Memisahkan Dataset menjadi Training dan Validation Set serta menerapkan SMOTe pada Training Dataset. (Pendekatan Pertama)
  2. Menerapkan SMOTe pada dataset tertentu secara keseluruhan dan kemudian Mengacak Dataset menjadi Set Pelatihan dan Validasi. (Pendekatan ke-2)

Di banyak sumber web seperti Stack Overflow dan di banyak Blog Pribadi, Pendekatan ke-2 telah dinyatakan sebagai metode pengambilan sampel berlebihan yang salah. Terutama, saya pernah melihat Blog Pribadi Nick Becker [1], di mana dia menyebut Pendekatan ke-2 sebagai pendekatan yang salah dengan memberikan alasan berikut:

Penerapan SMOTe pada seluruh kumpulan data menciptakan kejadian serupa karena algoritme didasarkan pada teori k-nearest neighbour. Karena alasan ini, Pemisahan setelah menerapkan SMOTe pada kumpulan data tertentu, mengakibatkan kebocoran informasi dari Set Validasi ke Set Pelatihan, sehingga mengakibatkan pengklasifikasi atau Model Pembelajaran Mesin memperkirakan secara berlebihan akurasi dan ukuran kinerja lainnya

Dia juga telah membuktikannya dengan bantuan contoh praktis di kehidupan nyata dengan mempertimbangkan kumpulan data. Dia telah menggunakan kotak peralatan pembelajaran yang tidak seimbang [2] untuk menerapkan SMOTe. Sebenarnya, saya sendiri tidak pernah bisa memahami dokumentasi kotak peralatan dengan benar. Jadi, saya lebih suka mengimplementasikan Algoritma SMOTe dari awal seperti yang ditunjukkan di atas. Dalam artikel ini, saya akan menunjukkan bahwa Pendekatan ke-2 TIDAK salah!!!

Mari kita ikuti Pendekatan Pertama karena pendekatan ini telah diterima secara luas.

Untuk menunjukkan bahwa Pendekatan ke-2 tidak salah, saya akan membagi seluruh kumpulan data menjadi Kumpulan Validasi-Pelatihan dan Pengujian. Set Tes akan disimpan terpisah sebagai kumpulan instance yang tidak diketahui. Penerapan hal yang sama adalah sebagai berikut —

from sklearn.model_selection import train_test_split 
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                   test_size=0.2, random_state=1234)
# X_train and y_train is the Train-Validation Set
# X_test and y_test is the Test Set separated out
  1. Sekarang, di Set Validasi Pelatihan, Pendekatan ke-1 dan ke-2 akan diterapkan berdasarkan kasus.
  2. Kemudian, Analisis Kinerja akan dilakukan pada kumpulan contoh yang tidak diketahui (Test Set) yang sama dan terpisah untuk kedua model (dikembangkan mengikuti Pendekatan ke-1 dan Pendekatan ke-2)

Mengikuti Pendekatan Pertama menggunakan SMOTe setelah Pemisahan

=› Membagi Set Validasi Pelatihan menjadi Set Pelatihan dan Validasi. Penerapan hal yang sama adalah sebagai berikut —

X_train, X_v, y_train, y_v = train_test_split(X_train, y_train,
                             test_size=0.2, random_state=2341)
# X_train and y_train is the Training Set
# X_v and y_v is the Validation Set

=› Menerapkan SMOTe hanya pada Training Set

# 1. Getting the number of Minority Class Instances in Training Set
import numpy as np # required library
unique, counts = np.unique(y_train, return_counts=True)
minority_shape = dict(zip(unique, counts))[1]
# 2. Storing the minority class instances separately
x1 = np.ones((minority_shape, X_train.shape[1]))
k=0
for i in range(0,X_train.shape[0]):
    if y_train[i] == 1.0:
        x1[k] = X_train[i]
        k = k + 1
# 3. Applying 100% SMOTe
sampled_instances = SMOTE(x1, 100)
# Keeping the artificial instances and original instances together
X_f = np.concatenate((X_train,sampled_instances), axis = 0)
y_sampled_instances = np.ones(minority_shape)
y_f = np.concatenate((y_train,y_sampled_instances), axis=0)
# X_f and y_f are the Training Set Features and Labels respectively 

Pelatihan Model menggunakan Pengklasifikasi Peningkatan Gradien

Gradient Boosting Classifier digunakan untuk Melatih Model Pembelajaran Mesin. Grid-Search digunakan pada Gradient Boosting Classifier untuk mendapatkan kumpulan hyper-parameter terbaik yaitu jumlah estimator dan kedalaman_maks.

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import GridSearchCV
parameters = {'n_estimators':[100,150,200,250,300,350,400,450,500],
              'max_depth':[3,4,5]}
clf= GradientBoostingClassifier()
grid_search = GridSearchCV(param_grid = parameters, estimator = clf,
                           verbose = 3)
grid_search_1 = grid_search.fit(X_f,y_f)

Mengikuti Pendekatan ke-2 menggunakan SMOTe sebelum Pemisahan

=› Menerapkan SMOTe di seluruh Validasi KeretaSet:

# 1. Getting the number of Minority Class Instances in Training Set
unique, counts = np.unique(y_train, return_counts=True)
minority_shape = dict(zip(unique, counts))[1]
# 2. Storing the minority class instances separately
x1 = np.ones((minority_shape, X_train.shape[1]))
k=0
for i in range(0,X_train.shape[0]):
    if y_train[i] == 1.0:
        x1[k] = X_train[i]
        k = k + 1
# 3. Applying 100% SMOTe
sampled_instances = SMOTE(x1, 100)
# Keeping the artificial instances and original instances together
X_f = np.concatenate((X_train,sampled_instances), axis = 0)
y_sampled_instances = np.ones(minority_shape)
y_f = np.concatenate((y_train,y_sampled_instances), axis=0)
# X_f and y_f are the Train-Validation Set Features and Labels respectively

=› Membagi Set Validasi Pelatihan menjadi Set Pelatihan dan Validasi. Penerapan hal yang sama adalah sebagai berikut —

X_train, X_v, y_train, y_v = train_test_split(X_f, y_f,
                             test_size=0.2, random_state=9876)
# X_train and y_train is the Training Set
# X_v and y_v is the Validation Set

Pelatihan Model menggunakan Pengklasifikasi Peningkatan Gradien

Demikian pula, Pencarian Grid diterapkan pada Gradient Boosting Classifier

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import GridSearchCV
parameters = {'n_estimators':[100,150,200,250,300,350,400,450,500],
              'max_depth':[3,4,5]}
clf= GradientBoostingClassifier()
grid_search = GridSearchCV(param_grid = parameters, estimator = clf,
                           verbose = 3)
grid_search_2 = grid_search.fit(X_train,y_train)

ANALISIS DAN PERBANDINGAN KINERJA

Metrik Kinerja yang digunakan untuk Perbandingan dan Analisis adalah:

  1. Akurasi pada Set Tes (Akurasi Tes)
  2. Presisi pada Set Pengujian
  3. Ingat pada Set Tes
  4. Skor F1 pada Set Tes

Selain metrik perbandingan ini, Akurasi Pelatihan (Set Pelatihan) dan Akurasi Validasi (Kumpulan Validasi) juga dihitung.

# MODEL 1 PERFORMANCE ANALYSIS
model1 = GradientBoostingClassifier(n_estimators = 250, max_depth = 5).fit(X_f, y_f) # best hyperparameters obtained from grid_search_1
# 1. Training Accuracy for Model 1 (following Approach 1)
print(grid_search_1.score(X_f, y_f))
# 2. Validation Accuracy on Validation Set for Model 1 
print(grid_search_1.score(X_v, y_v))
# 3. Test Accuracy on Test Set for Model 1
print(grid_search_1.score(X_test, y_test))
# 4. Precision, Recall and F1-Score on the Test Set for Model 1
from sklearn.metrics import classification_report
predictions=grid_search_1.predict(X_test)
print(classification_report(y_test,predictions))
# MODEL 2 PERFORMANCE ANALYSIS
model2 = GradientBoostingClassifier(n_estimators = 300, max_depth = 4).fit(X_train, y_train) # best hyperparameters obtained from grid_search_2
# 5. Training Accuracy for Model 2(following Approach 2)
print(grid_search_2.score(X_train, y_train))
# 6. Validation Accuracy on Validation Set for Model 2
print(grid_search_2.score(X_v, y_v))
# 3. Test Accuracy on Test Set for Model 2
print(grid_search_2.score(X_test, y_test))
# 4. Precision, Recall and F1-Score on the Test Set for Model 2
from sklearn.metrics import classification_report
predictions=grid_search_2.predict(X_test)
print(classification_report(y_test,predictions))

Akurasi Set Pelatihan dan Validasi untuk Model 1 dan Model 2 adalah:

  1. Akurasi Pelatihan (Model 1): 91.65025296412158%
  2. Akurasi Pelatihan (Model 2): ​​92.55866094553327%
  3. Akurasi Validasi (Model 1): 86.73704414587332%
  4. Akurasi Validasi (Model 2): ​​89.5021645021645%

Jadi, dari sini tampaknya Pendekatan ke-2menunjukkan Akurasi Validasi yang lebih tinggi tetapi tanpa pengujian pada Test Set yang sama sekali tidak diketahui dan sama, tidak ada kesimpulan yang dapat diambil. Bagan Perbandingan ditampilkan antara performa 2 model pada Test Set pada Tabel 2.

Jadi, yang jelas, terbukti bahwa sekecil apa pun perbedaannya Pendekatan 2 jelas lebih berhasil daripada Pendekatan 1dan oleh karena itu, tidak dapat dikatakan salah dengan alasan yang disebutkan oleh Nick Becker [1] karena

“ Meskipun SMOTe membuat instance serupa, di sisi lain, properti ini diperlukan tidak hanya untuk Pengurangan Ketidakseimbangan Kelas dan Augmentasi Data tetapi juga untuk menemukan Set Pelatihan terbaik yang cocok untuk Pelatihan Model. Jika Set Pelatihan tidak serbaguna, bagaimana Performa Model dapat ditingkatkan? Sejauh menyangkut pendarahan informasi dari Validasi ke Set Pelatihan, bahkan jika itu terjadi, hal ini berkontribusi untuk membuat Set Pelatihan menjadi lebih baik dan membantu dalam Pengembangan Model Pembelajaran Mesin yang Kuat karena terbukti bahwa untuk contoh yang sama sekali tidak diketahui, Pendekatan 2berkinerja lebih baik daripada Pendekatan 1

REFERENSI

[1] https://beckernick.github.io/oversampling-modeling/

[2] https://imbalanced-learn.readthedocs.io/en/stable/

[3] Chawla, Nitesh V., dkk. “SMOTE: teknik pengambilan sampel berlebihan minoritas sintetik.” Jurnal penelitian kecerdasan buatan16 (2002): 321–357.

Untuk kontak pribadi mengenai artikel atau diskusi tentang Machine Learning/Data Mining atau departemen Ilmu Data mana pun, jangan ragu untuk menghubungi saya di LinkedIn