كيفية التعامل مع عدم توازن البيانات (Imbalanced Data) في نماذج التصنيف
مقدمة
يُعد عدم توازن البيانات من أكثر التحديات شيوعاً في مشاريع التصنيف الواقعية، لأن النموذج قد يحقق دقة ظاهرية مرتفعة بينما يفشل عملياً في اكتشاف الفئة الأهم. يحدث ذلك عندما تكون إحدى الفئات ممثلة بعدد ضخم من السجلات، مقابل فئة نادرة تمثل الحالات الحرجة مثل الاحتيال، الأمراض، أو انسحاب العملاء.
في هذا السياق، لا يكفي الاعتماد على مقياس Accuracy وحده، لأن النموذج قد يتنبأ دائماً بالفئة الكبرى ويحصل على نتيجة تبدو ممتازة رغم انعدام القيمة التشغيلية. لذلك فإن فهم طبيعة التوزيع، واختيار المقاييس المناسبة، وتطبيق استراتيجيات إعادة التوازن، كلها خطوات أساسية في أي مشروع Machine Learning جاد.
قبل الوصول إلى مرحلة العلاج، يجب أن يكون إعداد البيانات منظماً بدءاً من التنظيف والفهم البنيوي. لهذا يفيد الرجوع إلى تنظيف البيانات (Data Cleaning): اكتشاف ومعالجة القيم المفقودة (Missing Values)، ثم مكتبة Pandas (2): استكشاف هيكل البيانات وفهم DataFrame و Series لفهم شكل البيانات قبل تدريب أي نموذج.
ما المقصود بعدم توازن البيانات؟
يحدث عدم التوازن عندما تكون نسبة الفئات غير متقاربة، مثل 98% من السجلات في الفئة السلبية مقابل 2% فقط في الفئة الإيجابية. في التطبيقات التجارية، تمثل الفئة النادرة غالباً الحدث الأكثر أهمية، مثل معاملة احتيالية أو مريض عالي الخطورة.
المشكلة ليست إحصائية فقط، بل هندسية أيضاً. ففي خطوط ETL قد يؤدي دمج مصادر متعددة أو تطبيق فلترة خاطئة إلى تضخيم الفئة الكبرى بشكل غير مقصود. لذلك من المهم مراجعة مراحل الاستخراج والتحويل، خاصة عند بناء بناء خطوط أنابيب البيانات (ETL – Extract, Transform, Load) باستخدام بايثون.
لماذا تفشل الدقة التقليدية في هذا السيناريو؟
إذا كان لديك 10,000 سجل، منها 9,800 من الفئة 0 و200 فقط من الفئة 1، فإن نموذجاً يتنبأ دائماً بالقيمة 0 سيحقق دقة 98%. لكن هذا النموذج غير قادر على اكتشاف أي حالة مهمة فعلياً.
لذلك نلجأ إلى مقاييس أكثر تعبيراً مثل:
Precision: نسبة التنبؤات الإيجابية الصحيحة.Recall: قدرة النموذج على التقاط الفئة النادرة.F1-Score: التوازن بينPrecisionوRecall.ROC-AUCوPR-AUC، والأخير مهم جداً مع الفئات النادرة.
فهم هذه المقاييس يرتبط مباشرة بمفاهيم التقييم الإحصائي، ويمكن تعزيزه عبر مقالات مثل الإحصاء الوصفي والاستدلالي: مفاهيم لا غنى عنها لكل عالم بيانات ومقدمة في تعلم الآلة (Machine Learning): الفرق بين التعلم الخاضع وغير الخاضع للإشراف.
كيف تكتشف المشكلة مبكراً؟
الخطأ الشائع هو بدء التدريب مباشرة دون فحص توزيع الفئات. يجب أولاً تنفيذ تحليل استكشافي بسيط على المتغير الهدف، مع التحقق من نسب التكرار وتأثير التصفية، والحذف، وعمليات الدمج السابقة.
import pandas as pd
df = pd.read_csv("classification_data.csv")
class_counts = df["target"].value_counts()
class_ratio = df["target"].value_counts(normalize=True) * 100
print(class_counts)
print(class_ratio.round(2))
إذا كنت تعمل على بيانات أكبر من قدرة Pandas، فانتقل إلى PySpark كما في ما هو Apache Spark؟ ولماذا تتوقف مكتبة Pandas عن العمل مع البيانات الضخمة (Big Data)؟، ثم استخدم استعلامات التوزيع على مستوى DataFrame.
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, count
spark = SparkSession.builder.appName("ImbalancedDataCheck").getOrCreate()
df = spark.read.csv("hdfs:///data/classification_data.csv", header=True, inferSchema=True)
df.groupBy("target").agg(count("*").alias("records")).show()
في بيئات البيانات الضخمة، من الأفضل قياس توازن الفئات بعد كل مرحلة
Transformداخل خطPipeline، لأن بعض عمليات التصفية أو إزالة القيم الشاذة قد تُضعف الفئة النادرة أكثر من المتوقع.
أهم استراتيجيات التعامل مع عدم التوازن
1) إعادة أخذ العينات Resampling
الأسلوب الأول هو تعديل توزيع البيانات قبل التدريب. ويمكن ذلك بطريقتين: تقليل حجم الفئة الكبرى Undersampling أو زيادة الفئة الصغرى Oversampling.
Undersampling سريع وفعال مع البيانات الضخمة، لكنه قد يفقد معلومات مهمة. أما Oversampling فيحافظ على معلومات الفئة الكبرى، لكنه قد يرفع خطر Overfitting إذا تم بالتكرار المباشر.
from sklearn.utils import resample
majority = df[df["target"] == 0]
minority = df[df["target"] == 1]
minority_upsampled = resample(
minority,
replace=True,
n_samples=len(majority),
random_state=42
)
balanced_df = pd.concat([majority, minority_upsampled])
2) التوليد الاصطناعي باستخدام SMOTE
بدلاً من تكرار نفس سجلات الفئة الصغرى، يقوم SMOTE بإنشاء عينات صناعية جديدة اعتماداً على أقرب الجيران. هذه الطريقة غالباً أفضل من النسخ المباشر، خصوصاً عندما تكون البيانات رقمية ومهيأة جيداً.
from imblearn.over_sampling import SMOTE
from sklearn.model_selection import train_test_split
X = df.drop(columns=["target"])
y = df["target"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
smote = SMOTE(random_state=42)
X_train_balanced, y_train_balanced = smote.fit_resample(X_train, y_train)
من المهم جداً تطبيق SMOTE على بيانات التدريب فقط، وليس قبل التقسيم، حتى لا يحدث تسرب للمعلومات. راجع أيضاً تقسيم البيانات (Train/Test Split): لماذا يجب أن نختبر النموذج على بيانات لم يرها من قبل؟.
3) استخدام الأوزان الطبقية Class Weights
بدلاً من تغيير البيانات نفسها، يمكن تعديل دالة الخسارة بحيث تُعاقب النموذج أكثر عند الخطأ في الفئة النادرة. هذا النهج ممتاز عندما تريد الحفاظ على التوزيع الأصلي، خاصة في نماذج مثل Logistic Regression وRandom Forest.
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
model = RandomForestClassifier(
n_estimators=200,
class_weight="balanced",
random_state=42
)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
print(classification_report(y_test, predictions))
يمكن تطبيق ذلك أيضاً مع الانحدار اللوجستي (Logistic Regression): التنبؤ بالنتائج الثنائية أو الغابات العشوائية (Random Forest): دمج مئات الأشجار لرفع دقة التوقعات حسب طبيعة المشروع.
التعامل مع عدم التوازن في البيئات الضخمة
عند العمل في أنظمة Big Data، لا تكون المشكلة مجرد تحسين نموذج، بل إدارة الكلفة الحسابية والذاكرة وسرعة التنفيذ. في Spark مثلاً، قد يكون Undersampling المرحلي أكثر عملية من التوليد الاصطناعي الكامل.
minority_df = df.filter(col("target") == 1)
majority_df = df.filter(col("target") == 0)
fraction = minority_df.count() / majority_df.count()
majority_sampled = majority_df.sample(withReplacement=False, fraction=fraction * 2, seed=42)
balanced_spark_df = minority_df.union(majority_sampled)
في الأنظمة الموزعة مثل
Apache Sparkأو مستودعات التحليل مثلBigQuery، من الأفضل تنفيذ فحص التوازن عبر استعلامات تجميع مبكرة قبل نقل البيانات إلى طبقة التدريب، لتقليل كلفة التخزين والمعالجة وإتاحة مراقبة جودة البيانات بشكل مستمر.
أفضل الممارسات العملية
- ابدأ دائماً بتحليل توزيع الفئات قبل التدريب.
- استخدم
Stratified Splitللحفاظ على نسب الفئات. - لا تعتمد على
Accuracyوحدها. - جرّب أكثر من نهج:
SMOTE، الأوزان، وإعادة أخذ العينات. - راقب أثر المعالجة على الأداء التشغيلي وليس فقط على مقاييس الاختبار.
- وثّق أي تغيير في خط البيانات حتى تعرف سبب تغير التوازن بين الإصدارات.
خاتمة
عدم توازن البيانات ليس مشكلة هامشية، بل عامل حاسم قد يحوّل نموذج التصنيف من أداة ذكية إلى نظام مضلل. الحل الفعّال يبدأ بفهم بنية البيانات، ثم قياس الأداء بالمؤشرات الصحيحة، ثم اختيار الاستراتيجية الأنسب بين إعادة التوازن أو تعديل الأوزان أو بناء تدفق معالجة أكثر وعياً بالسياق.
في المشاريع الاحترافية، لا توجد وصفة واحدة تناسب الجميع. فاختيار التقنية يعتمد على حجم البيانات، ونوع النموذج، وكلفة الخطأ التجاري، والبنية التشغيلية المستخدمة سواء كانت Pandas محلياً أو PySpark على نطاق موزع. وكلما كان تصميمك للبيانات أدق، كانت قدرتك على معالجة الانحياز أعلى، وكانت نتائج التصنيف أقرب إلى الواقع العملي.
3 comments