ویرگول
ورودثبت نام
Mahdi Pakravan | مهدی پاکروان
Mahdi Pakravan | مهدی پاکروانهمون پسره که تو کلاس نمیفهمید ، روش نمیشد بگه میرفت به زبون خودش یاد میگرفت و به زبون خودش مینوشت تو ویرگول :)
Mahdi Pakravan | مهدی پاکروان
Mahdi Pakravan | مهدی پاکروان
خواندن ۵ دقیقه·۶ ماه پیش

یادگیری ماشین به زبان من ( مرحله 14 - داده نامتوازن ImBalanced Data)

به این تصویر دقت کنید:

داده های ناتوازن
داده های ناتوازن

خیلی وقت ها داده اولیه ما ممکنه نامتوازن باشه . این توضیح با Outlier متفاوته ما در Outlier داده هایی داشتیم که از رنج عادی خارج بودن , مثلا درآمد همه بین ۱ میلیون تا ۱۰۰ میلیون بود ولی یهو یک نفر ۱۰۰ میلیارد درآمد داشت .

ولی در Imbalanced Data ما با مقدار غیرعادی طرف نیستیم؛
بلکه با تعداد غیرمتعادل در بین کلاس‌ها مواجهیم.

خلاصه:

  • Outlier → مقدارش غیرعادیه.

  • Imbalanced Data → تعدادش غیرمتعادل بین کلاس‌هاست.

مشکلش چیه ؟

وقتی با داده‌های نامتوازن (Imbalanced) طرفیم، داریم با مدلی کار می‌کنیم که خیلی به داده اکثریت اتکا می‌کنه و ممکنه تو پیش‌بینی دسته‌ی اقلیت (مهم!) اشتباه‌های جدی بکنه.

به زبان ساده : داده ما اون‌قدر مطمئن و منصفانه نیست که بشه به پیش‌بینی‌هاش اعتماد کامل کرد.

مثلا اگر ما یک دیتاست داشته باشیم که نصف تارگت مثبت و نصف اون منفی باشن اون موقع ما دیتاست Balance داریم در غیر این صورت ImBalance

یک نکته مهم :

ممکنه نتیجه Accuracy مدل شما خیلی عالی باشه و کار کنه ولی متوجه نشید که داده های ناتراز چه بلایی سر نتیجه مدل اورده , پس حواستون باشه که این مقاله بسیار بسیار مهمه !

در رگرسیون هم قبل از اینکه وارد مدل بشیم باید داده هامون رو Balance کنیم؟

مسئله‌ی نامتوازن بودن داده‌ها (Imbalanced Data) بیشتر توی Classification خودش رو نشون می‌ده، ولی در رگرسیون هم داده‌هایی داریم که مشکل‌ساز می‌شن. البته توی رگرسیون دیگه اسمش Imbalanced نیست، بلکه بیشتر به شکل Skewed Distribution (توزیع کج‌شده)، یا وجود Outlierهای پراثر مطرح می‌شه.

حالا در ادامه یاد میگیریم که داده های نامتوازن رو هم در رگرسیون و هم در Classification هندل کنیم .


مدیریت داده های نامتوازن (Imbalanced) در رگرسیون :

همانطور که گفتم داده نامتوازن در رگرسیون شکل متفاوتی با کلسیفیکیشن داره . ابتدا با مفهوم چولگی یا Skewed آشنا بشید :

توزیع چولگی یا غیرنورمال Skewed
توزیع چولگی یا غیرنورمال Skewed

در رگرسیون، ممکن است مقادیر هدف در بازه‌های خاصی تمرکز داشته باشند و نمونه‌های پرت (outliers) یا داده‌های نادر در بعضی بازه‌ها وجود داشته باشد.

داده های ما اگر به صورت توزیع نورمال نباشند قطعا به مشکل میخوریم و یک داده اشتباه در نهایت بدست میاریم :

چطوری در داده رگرسیون بفهمیم چولگی داریم ؟

stats.skew(data['Target'])

که اگر مثبت باشه چولگی به راست و منفی باشه چولگی به چپ و ۰ باشه یعنی نرمال

در رگرسیون شما به ۳ روش میتونید داده ها رو متوازن کنید که هر ۳ در کد زیر نوشته شده :

  • ۱-تبدیل لگاریتمی (اضافه کردن ۱ برای مثبت کردن داده ها)

  • ۲-تبدیل ریشه دوم

  • ۳-تبدیل BoxCox

بریم کد بزنیم (هندل کردن Imbalanced در رگرسیون) :

import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from scipy import stats np.random.seed(42) n_samples = 1000 X = np.random.exponential(scale=2, size=n_samples) y = 3 * X + np.random.normal(0, 1, n_samples) data = pd.DataFrame({'Feature': X, 'Target': y})
print(stats.skew(data['Target']))

در قسمت بالا کد دیتاست تستی خودمون رو میبینید , و نتیجه چولگی : 1.830

حالا میام به هر ۳ روش چولگی رو هندل میکنم :

#z تبدیل به روش لگاریتمی data['Target_log'] = np.log1p(data['Target'] - data['Target'].min() + 1) # تبدیل ریشه دوم data['Target_sqrt'] = np.sqrt(data['Target'] - data['Target'].min() + 1) # تبدیل Box-Cox data['Target_boxcox'], _ = stats.boxcox(data['Target'] - data['Target'].min() + 1)
با این کد میتونید نتیجه و حالت اولیه رو به صورت تصویری رسم کنید :
plt.figure(figsize=(12, 8)) plt.subplot(2, 2, 1) sns.histplot(data['Target'], kde=True) plt.title('Before Balancing') plt.subplot(2, 2, 2) sns.histplot(data['Target_log'], kde=True) plt.title('Balancing in Log Scale') plt.subplot(2, 2, 3) sns.histplot(data['Target_sqrt'], kde=True) plt.title('Balancing in Sqrt Scale') plt.subplot(2, 2, 4) sns.histplot(data['Target_boxcox'], kde=True) plt.title('Balancing in Box-Cox Scale') plt.tight_layout() plt.show()

بعد از انجام Balancing میتونیم نتیجه رو به شکل زیر ببینیم :

بعد از انجام BoxCox
بعد از انجام BoxCox

مدیریت داده های نامتوازن در کلسیفیکیشن (Classification) :

توی این مقاله به نظرم خیلی عالی تونسته این مبحث رو توضیح بده .

برای هندل کردن داده های نامتوازن در کلسیفیکیشن ۳ روش اصلی داریم :

روش اول : Over Sampling (نمونه‌برداری از اکثریت ها): تعداد نمونه‌های کلاس اقلیت رو افزایش می‌دیم.
یه روش معروف برای این کار SMOTE هست که داده‌های مصنوعی برای کلاس اقلیت تولید می‌کنه.

روش دوم : Under Sampling (نمونه‌برداری از اقلیت ها): تعداد نمونه‌های کلاس اکثریت رو کاهش می‌دیم تا تعادل برقرار بشه.

روش سوم : Class Weighting (وزن‌دهی به کلاس‌ها): به کلاس اقلیت وزن بیشتری می‌دیم تا مدل بهش توجه بیشتری کنه، بدون اینکه داده‌ها رو تغییر بدیم.

تفاوت Over Sampling و Under Sampling
تفاوت Over Sampling و Under Sampling


چطوری بفهمیم داده های ما برای Classification نامتوازن هستند ؟

dataframe['Target'].value_counts()

بریم کد بزنیم (هندل کردن Imbalanced در Classification) :

خب اول یک دیتاست آماده میکنیم :

import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report, confusion_matrix from imblearn.over_sampling import SMOTE from imblearn.under_sampling import RandomUnderSampler np.random.seed(42) X, y = make_classification(n_classes=2, class_sep=2, weights=[0.9, 0.1], n_informative=2, n_redundant=0, n_samples=1000, n_features=2, n_clusters_per_class=1, random_state=42 ) data = pd.DataFrame({'Feature1': X[:, 0], 'Feature2': X[:, 1], 'Target': y}) data['Target'].value_counts()

نتیجه :

نتیجه بررسی ImBalanced
نتیجه بررسی ImBalanced

895 تا ۰ داریم

105 تا ۱ داریم .

یعنی رسما داده نامتوازن داریم و تقریبا ۹۰ درصد تفاوت بینشون وجود داره (تصویر اول صفحه) .

حالا میریم اوکیشون کنیم :

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # Base Model model_base = LogisticRegression(random_state=42) model_base.fit(X_train, y_train) y_pred_base = model_base.predict(X_test) print(classification_report(y_test, y_pred_base)) # Over Sampling (SMOTE) smote = SMOTE(random_state=42) X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train) model_smote = LogisticRegression(random_state=42) model_smote.fit(X_train_smote, y_train_smote) y_pred_smote = model_smote.predict(X_test) print("\nSMOTE (Over Sampling):") print(classification_report(y_test, y_pred_smote)) # Under Sampling undersampler = RandomUnderSampler(random_state=42) X_train_under, y_train_under = undersampler.fit_resample(X_train, y_train) model_under = LogisticRegression(random_state=42) model_under.fit(X_train_under, y_train_under) y_pred_under = model_under.predict(X_test) print("\nUnder Sampling:") print(classification_report(y_test, y_pred_under))
# Class Weighting model_weighted = LogisticRegression(class_weight='balanced', random_state=42) model_weighted.fit(X_train, y_train) y_pred_weighted = model_weighted.predict(X_test) print("\nClass Weighting:") print(classification_report(y_test, y_pred_weighted)) plt.figure(figsize=(15, 10)) plt.subplot(2, 2, 1) cm_base = confusion_matrix(y_test, y_pred_base) sns.heatmap(cm_base, annot=True, fmt='d', cmap='Blues', cbar=False) plt.title('Confusion Matrix') plt.xlabel('Predicted') plt.ylabel('Data') plt.subplot(2, 2, 2) cm_smote = confusion_matrix(y_test, y_pred_smote) sns.heatmap(cm_smote, annot=True, fmt='d', cmap='Blues', cbar=False) plt.title('Confusion Matrix (SMOTE)') plt.xlabel('Predicted') plt.ylabel('Data') plt.subplot(2, 2, 3) cm_under = confusion_matrix(y_test, y_pred_under) sns.heatmap(cm_under, annot=True, fmt='d', cmap='Blues', cbar=False)
plt.title('Confusion Matrix (Under Sampling)') plt.xlabel('Predicted') plt.ylabel('Data') plt.subplot(2, 2, 4) cm_weighted = confusion_matrix(y_test, y_pred_weighted) sns.heatmap(cm_weighted, annot=True, fmt='d', cmap='Blues', cbar=False) plt.title('Confusion Matrix (Class Weighting)') plt.xlabel('Predicted') plt.ylabel('Data') plt.tight_layout() plt.show()

در نهایت :

ما در نتیجه معیار های Precission , Recall , f1-score , support , Confusion matrix رو داریم که در این پست بهشون اشاره شده .

  • Precision (دقت): درصد پیش‌بینی‌های درست برای یک کلاس از کل پیش‌بینی‌هایی که برای اون کلاس انجام شده

  • Recall (بازخوانی یا Sensitivity): درصد نمونه‌های واقعی یک کلاس که درست پیش‌بینی شدن. یعنی:

  • F1-Score: میانگین هارمونیک Precision و Recall. این معیار وقتی مهمه که بخوای تعادل بین دقت و بازخوانی رو بررسی کنی

  • Support: تعداد نمونه‌های واقعی هر کلاس در مجموعه تست.


نتیجه :

نتیحه Classification از مدیریت داده های ناتراز
نتیحه Classification از مدیریت داده های ناتراز

همانطور که میبینید زیاد تفاوت خاصی بین UnderSampling , OverSampling و حالت اولیه نداشت .

چرا ؟ چون این یک دیتای تسته و زیاد نتونسته IMBalanced های خوبی رو برامون طراحی کنه
به همین خاطر زیاد تفاوتی نداره .

در قسمت های بعدی و پروژه های بعدی با داده های واقعی سر و کار داریم و اونجاست که بیشتر متوجه لزوم مبحث Sampling میشیم .

این هم تصویر Confusion Matrix تارگت که در این پست کامل بهش اشاره شده :











۲
۰
Mahdi Pakravan | مهدی پاکروان
Mahdi Pakravan | مهدی پاکروان
همون پسره که تو کلاس نمیفهمید ، روش نمیشد بگه میرفت به زبون خودش یاد میگرفت و به زبون خودش مینوشت تو ویرگول :)
شاید از این پست‌ها خوشتان بیاید