مشروع: تصنيف غير متوازن
درس 8 من 8
8مشروع: تصنيف غير متوازن
الصورة الكبيرةمشروع هذا المسار يجمع كل ما سبق في تسليم واحد: خط أساس ساذج، ونموذج يتفوّق عليه، ومقاييس مناسبة لبيانات غير متوازنة، وعتبة مختارة بتكلفة، وتقرير قصير يقنع بالأرقام لا بالصفات.
ماذا تشاهد في الرسم: على الاختبار، وبعتبة 0.034 مختارة على التحقّق، اكتشف النموذج 66 من 96 حالة احتيال وفاته 30، مقابل 33 إنذارًا كاذبًا. هذا السطر بالأعداد هو ما يفهمه المدير، لا PR-AUC.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
في هذا المشروع تبحث عن حالات نادرة، مثل عملية احتيال واحدة بين آلاف العمليات السليمة. تبدأ بأبسط حل ممكن لتعرف نقطة البداية، ثم تبني نموذجًا يتفوق عليه، وتشرح الفرق بأرقام يفهمها مدير لا يعرف التعلّم الآلي.
خط الأساس DummyClassifier ثم انحدار لوجستي ثم تعزيز، مع أوزان الفئات class_weight أو إعادة العيّنات، واختيار العتبة على منحنى الإحكام والاسترجاع. التقرير يقارن PR-AUC والاسترجاع عند إحكام محدد، ويحسب كلفة الخطأ بالمال.
قبل أن تبدأ
⚖️المقاييس والعتبة
تحسب الدقة الإيجابية والاستدعاء وتختار العتبة على التحقّق، من درس المقاييس.
🌲التعزيز بالميل
تعرف من درس الأشجار لماذا يتفوّق التعزيز غالبًا على البيانات الجدولية.
✂️التقسيم
تقسم إلى تدريب وتحقّق واختبار مع stratify وبذرة ثابتة.
الفكرة الجوهرية
تجمع هنا المسار كله في تسليم واحد. تبدأ بخط الأساس، ثم تقارن نموذجين بالمقياس الصحيح، ثم تختار العتبة على التحقّق، ثم تكتب تقريرًا يقنع بالأرقام.
1خط الأساس أولًا
3% فقط من المعاملات احتيال. انظر إلى الرسم: في مجموعة الاختبار 96 حالة من 3000، شريط رفيع بجانب الأغلبية.
from sklearn.datasets import make_classification
from sklearn.dummy import DummyClassifier
from sklearn.metrics import average_precision_score
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=10000, n_features=12, n_informative=6, weights=[0.97], flip_y=0.005, class_sep=1.2, random_state=7)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=7, stratify=y)
print(f"positives in test: {y_te.sum()} of {len(y_te)}")
baseline = DummyClassifier(strategy="most_frequent").fit(X_tr, y_tr)
print(f"baseline accuracy: {baseline.score(X_te, y_te):.3f}")
print(f"baseline PR-AUC: {average_precision_score(y_te, baseline.predict_proba(X_te)[:, 1]):.3f}")
دقة 96.8% بلا أي ذكاء. ومساحة منحنى الدقة والاستدعاء PR-AUC تساوي 0.032، أي نسبة الإيجابيات بالضبط، وهذا هو خط أساس هذا المقياس دائمًا. من الآن، كل نموذج يُقارن بـ0.032 لا بـ96.8%.
اكتب هذا الرقم في أول سطر من التقرير. PR-AUC يقيس جودة ترتيب الحالات النادرة بغضّ النظر عن العتبة، فيكشف فورًا إن كان النموذج يفعل شيئًا.
2نموذجان بنفس المقاييس
لا تجرّب عشرين نموذجًا، جرّب اثنين جيدًا: انحدار لوجستي مرجعًا قابلًا للتفسير، وتعزيز متدرّج مرشّحًا قويًا.
نفس التقسيم، ونموذجان، ونسخة من الانحدار اللوجستي بأوزان متوازنة للفئات، وهي الحيلة الأشهر للبيانات غير المتوازنة.
from sklearn.datasets import make_classification
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import average_precision_score, precision_score, recall_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X, y = make_classification(n_samples=10000, n_features=12, n_informative=6, weights=[0.97], flip_y=0.005, class_sep=1.2, random_state=7)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=7, stratify=y)
models = {
"logistic": make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000)),
"logistic balanced": make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000, class_weight="balanced")),
"boosting": HistGradientBoostingClassifier(random_state=7),
}
print(f"{'model':18} PR-AUC precision recall")
for name, model in models.items():
model.fit(X_tr, y_tr)
proba = model.predict_proba(X_te)[:, 1]
pred = (proba >= 0.5).astype(int)
print(f"{name:18} {average_precision_score(y_te, proba):.3f} {precision_score(y_te, pred, zero_division=0):.2f} {recall_score(y_te, pred):.2f}")
ثلاث قصص في ثلاثة أسطر. الانحدار اللوجستي العادي دقيق تمامًا حين ينبّه لكنه يلتقط 7% فقط من الحالات. الأوزان المتوازنة رفعت الاستدعاء إلى 57% لكن 94% من تنبيهاتها كاذبة، والأسوأ أن PR-AUC انخفض، فالحيلة لم تحسّن الترتيب بل حرّكت العتبة فقط. التعزيز بالميل PR-AUC عنده 0.729، أي أكثر من ضعف أفضل نموذج خطي، لأن البيانات فيها علاقات غير خطية.
انظر إلى الرسم: الأوزان الموزونة أنزلت PR-AUC، والتعزيز أكثر من ضعف أفضل نموذج خطي.
3العتبة على التحقّق
العتبة إعداد مثل أي إعداد آخر، فتختارها على التحقّق بقيد مكتوب، ثم تطبّقها على الاختبار كما هي. انظر إلى الرسم: الترتيب لا يتغيّر.
القيد التجاري: يجب التقاط 70% على الأقل من حالات الاحتيال. من بين كل العتبات التي تحقّق ذلك على التحقّق، نختار التي تعطي أعلى دقة إيجابية، ثم نطبّقها على الاختبار دون تعديل.
import numpy as np
from sklearn.datasets import make_classification
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.metrics import precision_recall_curve
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=10000, n_features=12, n_informative=6, weights=[0.97], flip_y=0.005, class_sep=1.2, random_state=7)
X_rest, X_te, y_rest, y_te = train_test_split(X, y, test_size=0.3, random_state=7, stratify=y)
X_tr, X_val, y_tr, y_val = train_test_split(X_rest, y_rest, test_size=0.25, random_state=7, stratify=y_rest)
model = HistGradientBoostingClassifier(random_state=7).fit(X_tr, y_tr)
precision, recall, thresholds = precision_recall_curve(y_val, model.predict_proba(X_val)[:, 1])
ok = recall[:-1] >= 0.7
best = np.argmax(np.where(ok, precision[:-1], -1))
t = thresholds[best]
print(f"threshold chosen on validation: {t:.3f}")
pred = (model.predict_proba(X_te)[:, 1] >= t).astype(int)
tp = int(((pred == 1) & (y_te == 1)).sum())
fp = int(((pred == 1) & (y_te == 0)).sum())
fn = int(((pred == 0) & (y_te == 1)).sum())
print(f"test: caught {tp} of {tp + fn} positives, {fp} false alarms")
العتبة المختارة 0.034، بعيدة جدًّا عن 0.5، وهذا طبيعي في البيانات النادرة لأن النموذج نادرًا ما يكون واثقًا من الفئة النادرة. على الاختبار: التقطنا 66 حالة من 96 (69%، قريب من هدف 70%) مقابل 33 إنذارًا كاذبًا من نحو 2900 معاملة سليمة. هذا السطر بالضبط هو ما يُكتب في التقرير، لأن مديرًا يفهم «66 من 96 بـ33 إنذارًا كاذبًا» ولا يفهم «PR-AUC 0.729».
4تقرير الصفحة الواحدة
التقرير المقنع أرقام محدّدة بمقارنة، لا صفات. انظر إلى الرسم: خمسة أجزاء في صفحة واحدة.
اكتب السطر الذي يفهمه المدير: التقطنا 66 من 96 حالة احتيال مع 33 إنذارًا كاذبًا. ثم اذكر مثالين على الأقل فشل فيهما النموذج، مع تفسير محتمل.
كيف يعمل، خطوة بخطوة: كيف تبني تجربة المشروع من البداية إلى التقرير
احسب خط الأساس بـ DummyClassifier: دقة 96.8% وPR-AUC قدره 0.032، واكتبه في أول سطر.
درّب انحدارًا لوجستيًا كمرجع مفهوم وتعزيزًا بالميل كمرشّح قوي، وقارن بينهما بـ PR-AUC.
اختر العتبة على التحقّق تحت قيد مكتوب، مثل استدعاء 70% على الأقل بأفضل دقة إيجابية ممكنة.
طبّق العتبة على الاختبار مرة واحدة، واكتب الأعداد: كم اكتُشف، وكم فات، وكم إنذارًا كاذبًا.
مثال محلول
المسألة: 3% فقط من المعاملات احتيال. التسليم دفتر أو سكربت يشغّل التجربة كاملة من البيانات إلى الجدول النهائي، وتقرير من صفحة واحدة. نبدأ بالخطوة التي يتخطّاها الجميع.
جرّب بلا كود
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| الأوزان المتوازنة تحسّن النموذج على البيانات غير المتوازنة. | في الدرس رفعت الاستدعاء من 7% إلى 57% لكنها خفّضت PR-AUC. حرّكت العتبة فعليًا ولم تحسّن ترتيب الحالات. |
| العتبة الافتراضية 0.5 مناسبة هنا أيضًا. | مع فئة نادرة قلّما يكون النموذج واثقًا، فجاءت العتبة المختارة 0.034. وهذا طبيعي لا خلل. |
| جرّب أكبر عدد من النماذج لتجد الأفضل. | نموذجان مدروسان جيدًا أفضل من عشرين. كل محاولة إضافية على البيانات نفسها تضيف حظًّا إلى الرقم الفائز. |
جرّب بنفسك
class_weight="balanced" رفع الاستدعاء من 7% إلى 57% لكنه خفّض PR-AUC. كيف تفسّر هذا؟
الاستدعاء عند 0.5 تغيّر لأن الاحتمالات كلها صارت أعلى للفئة النادرة، وهذا أثر يشبه خفض العتبة. PR-AUC يقيس الترتيب عبر كل العتبات، ولم يتحسّن. يمكنك الحصول على نفس الأثر بتغيير العتبة على النموذج العادي، وهذا درس مهم: «حيل» عدم التوازن غالبًا تغيّر العتبة لا الجودة.
أي سطر يناسب أعلى التقرير أكثر؟
هذا السطر يقول ما حدث بأعداد يفهمها أي قارئ، ويقارن بمرجع. الدقة 98% مضلّلة هنا، واسم الخوارزمية لا يقول شيئًا عن النتيجة، وPR-AUC صحيح لكنه رقم تقني يأتي في الجدول لا في الجملة الأولى.
بطاقات مراجعة سريعة
تحقق من فهمك
مديرك يسأل: «هل نستبدل القواعد الحالية بالنموذج؟». ماذا تحتاج في التقرير لتجيب؟
نتيجة القواعد الحالية على نفس مجموعة الاختبار وبنفس المقاييس، لأنها خط الأساس الحقيقي لا DummyClassifier. ثم الفرق بالأعداد: كم احتيالًا إضافيًا نلتقط، وكم إنذارًا كاذبًا إضافيًا أو أقل، وتكلفة كل منهما بالريال إن أمكن. وأخيرًا الحدود: على أي نوع من المعاملات يفشل النموذج، وكيف سنراقبه بعد النشر.
لماذا يساوي PR-AUC لخط الأساس 0.032 بالضبط؟
لأن حلًّا لا يرتّب الحالات أبدًا تكون دقته الإيجابية عند أي استدعاء مساوية لنسبة الإيجابيات، وهي 3.2% في مجموعة الاختبار.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
توثيق رسمي1
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.