مقابله با داده‌ های نامتوازن با روش‌های SMOTE و Near Miss در پایتون

بفرست برای دوستت
Telegram
WhatsApp

فهرست مطالب

در درس چهاردهم از نیچ کورس آموزش رایگان یادگیری ماشین با پایتون می خواهیم در مورد مقابله با داده‌ های نامتوازن صحبت کنیم و با دو الگوریتم اصلی برای رفع مشکل داده های نامتوازن آشنا شویم.

در دنیای یادگیری ماشین و علم داده، گاهی با مشکل توزیع نامتوازن داده‌ها روبه‌رو می‌شویم. این موضوع زمانی پیش می‌آید که تعداد نمونه‌های یک کلاس خیلی بیشتر یا کمتر از دیگری است. الگوریتم‌ های یادگیری ماشین برای افزایش دقت خود، معمولاً به توزیع کلاس‌ها توجهی ندارند. این چالش در مواردی مثل تشخیص تقلب یا شناسایی چهره، معمول است.

روش‌های معمول یادگیری ماشین مثل درخت تصمیم یا رگرسیون لجستیک، میل بیشتری به پیش‌بینی کلاس‌های با تعداد نمونه بیشتر دارند و ممکن است کلاس‌های با تعداد نمونه کمتر را نادیده بگیرند. به عبارت ساده‌تر، اگر داده‌هایمان نامتوازن باشد، مدل ما ممکن است در تشخیص کلاس‌های با نمونه کم عملکرد خوبی نداشته باشد.

 

روش‌های مدیریت داده‌های نامتوازن

دو الگوریتم اصلی وجود دارد که به وفور برای رفع مشکل نامتوازن بودن داده‌ها استفاده می‌شوند.

1- SMOTE

2- Near Miss

 

تکنیک SMOTE (Synthetic Minority Oversampling Technique) – نمونه‌گیری Oversampling 

تکنیک SMOTE یکی از روش‌های محبوب نمونه‌گیری Oversampling (افزایشی) است که برای مقابله با مشکل داده‌های نامتوازن استفاده می‌شود. این روش با تولید نمونه‌های تصادفی از کلاس کمترین نمونه، به هدف تعادل بین کلاس‌ها می‌پردازد.

SMOTE نمونه‌های جدید را میان نمونه‌های کلاس اقلیت موجود می‌سازد. با استفاده از یک رویکرد خطی، نمونه‌های مصنوعی جدید از کلاس اقلیت ایجاد می‌کند، و این امر با انتخاب تصادفی همسایه‌های نزدیک به هر نمونه انجام می‌پذیرد. پس از این فرآیند، داده‌ها دوباره سازی می‌شوند و سپس می‌توان از مدل‌های طبقه‌بندی مختلف بر روی آن‌ها استفاده کرد.

 

فهم عمیق‌تر از چگونگی کارکرد الگوریتم SMOTE

گام 1: تعیین مجموعه کلاس اقلیت به نام A، برای هر نمونه x:

x ɛ A

همسایه‌های نزدیک k به x با محاسبه فاصله اقلیدسی بین x و سایر نمونه‌های موجود در مجموعه A به دست می‌آید.

گام 2: نرخ نمونه‌برداری N بر اساس نسبت عدم توازن تنظیم می‌شود. برای هر نمونه:

x ɛ A

N نمونه (یعنی x1، x2، … xn) به طور تصادفی از همسایه‌های نزدیک k انتخاب شده و مجموعه‌ای را تشکیل می‌دهند.

A1

گام 3: برای هر نمونه:

xk ɛ A1

– (برای k=1، 2، 3 … N)، فرمول زیر برای تولید یک نمونه جدید استفاده می‌شود:

  • که در آن rand(0، 1) نمایانگر یک عدد تصادفی بین 0 و 1 است.

 

الگوریتم NearMiss – نمونه‌گیری Undersampling

NearMiss یک تکنیک نمونه‌برداری Undersampling (کاهشی) است. هدف آن تعادل بین توزیع کلاس‌ها با حذف تصادفی نمونه‌های کلاس اکثریت است. وقتی نمونه‌های دو کلاس مختلف به یکدیگر بسیار نزدیک هستند، ما نمونه‌های کلاس اکثریت را حذف می‌کنیم تا فاصله بین دو کلاس افزایش یابد. این امر کمک می‌کند تا فرآیند طبقه‌بندی بهبود یابد.

  روش کدبندی وان هات (One Hot Encoding) در یادگیری ماشین

برای جلوگیری از مشکل از دست رفتن اطلاعات در بسیاری از تکنیک‌های نمونه‌برداری کاهشی، روش‌های همسایگی نزدیک به طور گسترده‌ای استفاده می‌شوند.

 

شهود اساسی در مورد چگونگی عملکرد روش‌های همسایه‌ی نزدیک به شرح زیر است:

  • گام 1: ابتدا، این روش فواصل بین تمام نمونه‌های کلاس اکثریت و نمونه‌های کلاس اقلیت را پیدا می‌کند. در اینجا، نمونه‌های کلاس اکثریت باید کاهش یابند.
  • گام 2: سپس، n نمونه از کلاس اکثریت که کمترین فاصله را به نمونه‌های کلاس اقلیت دارند انتخاب می‌شوند.
  • گام 3: اگر k نمونه در کلاس اقلیت وجود داشته باشد، روش نزدیک‌ترین همسایه منجر به وجود k*n نمونه از کلاس اکثریت خواهد شد.

 

با استفاده از الگوریتم NearMiss برای پیدا کردن n نمونه نزدیک در کلاس با بیشترین نمونه‌ها، چندین روش وجود دارد:

 نسخه 1: در این روش، نمونه‌هایی از کلاس با بیشترین تعداد انتخاب می‌شوند که فاصله‌ی میانگین آن‌ها تا k نمونه نزدیک کلاس با کمترین تعداد، کم‌تر است.

نسخه 2: در اینجا، نمونه‌هایی از کلاس با بیشترین تعداد انتخاب می‌شوند که فاصله‌ی میانگین آن‌ها تا k نمونه دور از کلاس با کمترین تعداد، کم‌تر است.

نسخه 3: این روش در دو مرحله اجرا می‌شود. در مرحله اول، برای هر نمونه در کلاس با کمترین تعداد، M نزدیک‌ترین همسایه‌ها ذخیره می‌شوند. در مرحله دوم، نمونه‌های کلاس با بیشترین تعداد انتخاب می‌شوند که فاصله‌ی میانگین آن‌ها تا N نزدیک‌ترین همسایه بیشترین است.

این مقاله به درک بهتر و تمرین عملی در مورد چگونگی انتخاب بهترین روش برای مواجهه با داده‌های نامتعادل کمک می‌کند.

 

بارگذاری کتابخانه‌ها و فایل داده‌ها

مجموعه داده‌ ها شامل معاملات انجام شده با کارت‌های اعتباری است. در این بین، 492 معامله کلاهبردارانه وجود دارد که از مجموع 284,807 معامله، تنها 0.172% را شامل می‌شود، که نشان‌دهنده نامتعادل بودن آن است.

برای دسترسی به مجموعه داده، از این لینک استفاده کنید.

# import necessary modules 
import pandas as pd 
import matplotlib.pyplot as plt 
import numpy as np 
from sklearn.linear_model import LogisticRegression 
from sklearn.preprocessing import StandardScaler 
from sklearn.metrics import confusion_matrix, classification_report 

# load the data set 
data = pd.read_csv('creditcard.csv') 

# print info about columns in the dataframe 
print(data.info()) 

 

خروجی:

RangeIndex: 284807 entries, 0 to 284806
Data columns (total 31 columns):
Time      284807 non-null float64
V1        284807 non-null float64
V2        284807 non-null float64
V3        284807 non-null float64
V4        284807 non-null float64
V5        284807 non-null float64
V6        284807 non-null float64
V7        284807 non-null float64
V8        284807 non-null float64
V9        284807 non-null float64
V10       284807 non-null float64
V11       284807 non-null float64
V12       284807 non-null float64
V13       284807 non-null float64
V14       284807 non-null float64
V15       284807 non-null float64
V16       284807 non-null float64
V17       284807 non-null float64
V18       284807 non-null float64
V19       284807 non-null float64
V20       284807 non-null float64
V21       284807 non-null float64
V22       284807 non-null float64
V23       284807 non-null float64
V24       284807 non-null float64
V25       284807 non-null float64
V26       284807 non-null float64
V27       284807 non-null float64
V28       284807 non-null float64
Amount    284807 non-null float64
Class     284807 non-null int64

 

# normalise the amount column 
data['normAmount'] = StandardScaler().fit_transform(np.array(data['Amount']).reshape(-1, 1)) 

# drop Time and Amount columns as they are not relevant for prediction purpose 
data = data.drop(['Time', 'Amount'], axis = 1) 

# as you can see there are 492 fraud transactions. 
data['Class'].value_counts() 

 

  انواع تکنیک های رگرسیون در یادگیری ماشین

خروجی:

       0    284315
       1       492

حالا داده‌ها را برای آموزش و آزمون تقسیم کنیم.

from sklearn.model_selection import train_test_split 

# split into 70:30 ration 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 0) 

# describes info about train and test set 
print("Number transactions X_train dataset: ", X_train.shape) 
print("Number transactions y_train dataset: ", y_train.shape) 
print("Number transactions X_test dataset: ", X_test.shape) 
print("Number transactions y_test dataset: ", y_test.shape) 

 

خروجی:

      Number transactions X_train dataset:  (199364, 29)
      Number transactions y_train dataset:  (199364, 1)
      Number transactions X_test dataset:  (85443, 29)
      Number transactions y_test dataset:  (85443, 1)

سپس مدل را بدون توجه به نامتعادل بودن کلاس‌ها آموزش می دهیم.

# logistic regression object 
lr = LogisticRegression() 

# train the model on train set 
lr.fit(X_train, y_train.ravel()) 

predictions = lr.predict(X_test) 

# print classification report 
print(classification_report(y_test, predictions)) 

 

خروجی:

                precision   recall   f1-score  support

           0       1.00      1.00      1.00     85296
           1       0.88      0.62      0.73       147

    accuracy                           1.00     85443
   macro avg       0.94      0.81      0.86     85443
weighted avg       1.00      1.00      1.00     85443

 

دقت مدل به 100% رسیده، اما آیا متوجه تفاوتی شده‌اید؟

بازیابی کلاس کم‌تعداد خیلی کم است. این نشان‌دهنده این است که مدل بیشتر به سمت کلاس با تعداد زیاد گرایش دارد. پس، این مدل لزوماً بهترین گزینه نیست.

حالا قصد داریم روش‌های مختلف برخورد با داده‌های نامتعادل یا نامتوازن را بررسی کنیم و نتایج آن‌ها را مقایسه کنیم.

 

با استفاده از الگوریتم SMOTE

شما می‌توانید جزئیات پارامترها را از لینک مربوطه مشاهده کنید.

print("Before OverSampling, counts of label '1': {}".format(sum(y_train == 1))) 
print("Before OverSampling, counts of label '0': {} \n".format(sum(y_train == 0))) 

# import SMOTE module from imblearn library 
# pip install imblearn (if you don't have imblearn in your system) 
from imblearn.over_sampling import SMOTE 
sm = SMOTE(random_state = 2) 
X_train_res, y_train_res = sm.fit_sample(X_train, y_train.ravel()) 

print('After OverSampling, the shape of train_X: {}'.format(X_train_res.shape)) 
print('After OverSampling, the shape of train_y: {} \n'.format(y_train_res.shape)) 

print("After OverSampling, counts of label '1': {}".format(sum(y_train_res == 1))) 
print("After OverSampling, counts of label '0': {}".format(sum(y_train_res == 0))) 

 

خروجی:

Before OverSampling, counts of label '1': [345]
Before OverSampling, counts of label '0': [199019] 

After OverSampling, the shape of train_X: (398038, 29)
After OverSampling, the shape of train_y: (398038, ) 

After OverSampling, counts of label '1': 199019
After OverSampling, counts of label '0': 199019

مشاهده می‌کنید که الگوریتم SMOTE نمونه‌های کم‌تعداد را افزایش داده و آن‌ها را با کلاس با تعداد زیاد تراز کرده است. حالا، با اعمال این الگوریتم، نتایج دقت و بازیابی را بررسی کنیم.

  الگوریتم ماشین بردار پشتیبان (SVM)

 

 پیش‌بینی و بازیابی

lr1 = LogisticRegression() 
lr1.fit(X_train_res, y_train_res.ravel()) 
predictions = lr1.predict(X_test) 

# print classification report 
print(classification_report(y_test, predictions)) 

 

خروجی:

                precision   recall   f1-score  support

           0       1.00      0.98      0.99     85296
           1       0.06      0.92      0.11       147

    accuracy                           0.98     85443
   macro avg       0.53      0.95      0.55     85443
weighted avg       1.00      0.98      0.99     85443

دقت مدل به 98% کاهش یافته است. اما نسبت به مدل اولیه، بازیابی کلاس کم‌تعداد به 92% افزایش یافته است. این مدل در مقایسه با مدل قبلی بهتر است.

 

در مرحله بعد، قصد داریم با استفاده از تکنیک NearMiss، کلاس با تعداد زیاد را کم کنیم و نتایج را مورد ارزیابی قرار دهیم.

 

با استفاده از الگوریتم NearMiss

برای مشاهده تمام پارامترها، می‌توانید به لینک مرجع مراجعه کنید.

print("Before Undersampling, counts of label '1': {}".format(sum(y_train == 1))) 
print("Before Undersampling, counts of label '0': {} \n".format(sum(y_train == 0))) 

# apply near miss 
from imblearn.under_sampling import NearMiss 
nr = NearMiss() 

X_train_miss, y_train_miss = nr.fit_sample(X_train, y_train.ravel()) 

print('After Undersampling, the shape of train_X: {}'.format(X_train_miss.shape)) 
print('After Undersampling, the shape of train_y: {} \n'.format(y_train_miss.shape)) 

print("After Undersampling, counts of label '1': {}".format(sum(y_train_miss == 1))) 
print("After Undersampling, counts of label '0': {}".format(sum(y_train_miss == 0))) 

 

خروجی:

Before Undersampling, counts of label '1': [345]
Before Undersampling, counts of label '0': [199019] 

After Undersampling, the shape of train_X: (690, 29)
After Undersampling, the shape of train_y: (690, ) 

After Undersampling, counts of label '1': 345
After Undersampling, counts of label '0': 345

با استفاده از الگوریتم NearMiss، تعداد نمونه‌های کلاس با تعداد بیشتر کاهش یافته و با کلاس با تعداد کمتر برابر شده است. یعنی کلاس با تعداد بیشتر به تعداد کلاس با تعداد کمتر رسیده است تا هر دو یک تعداد نمونه داشته باشند.

 

پیش‌بینی و بازیابی

# train the model on train set 
lr2 = LogisticRegression() 
lr2.fit(X_train_miss, y_train_miss.ravel()) 
predictions = lr2.predict(X_test) 

# print classification report 
print(classification_report(y_test, predictions)) 

 

خروجی:

               precision    recall   f1-score   support

           0       1.00      0.56      0.72     85296
           1       0.00      0.95      0.01       147

    accuracy                           0.56     85443
   macro avg       0.50      0.75      0.36     85443
weighted avg       1.00      0.56      0.72     85443

ظاهراً این مدل نسبت به مدل اول بهتر عمل می‌کند و بازیابی کلاس با تعداد کمتر به 95% افزایش یافته است. اما، بازیابی کلاس با تعداد بیشتر به 56% کاهش پیدا کرده است. در این وضعیت، چون SMOTE نتایج بهتری دارد، تصمیم می‌گیرم از آن استفاده کنم!

Rating 4.00 from 4 votes

لیست دروس دوره

آموزش پیشنهادی و مکمل

اگر سوالی در مورد این درس دارید، در کادر زیر بنویسید.

guest
0 نظرات
بازخورد (Feedback) های اینلاین
مشاهده همه دیدگاه ها
سبد خرید

جشنواره دوره جامع متخصص علم داده شروع شد

برای دیدن نوشته هایی که دنبال آن هستید تایپ کنید.
×