انتقل إلى المحتوى الرئيسي

الوحدة 8 — التحقّق المتقاطع والتقسيم الزمني وتسرّب البيانات

سبع وحداتٍ من النماذج؛ وحان وقت الانضباط الذي يجعل نتائجها جديرة بالثقة. لا قيمة لنموذجٍ بلا قياسٍ نزيه — والقياسات غير النزيهة سهلة الإنتاج على نحوٍ مُرعِب. تُحكِم هذه الوحدة منهج التقييم: التحقّق المتقاطع، تقسيماتٌ تحترم الزمن، ومطاردة العدوّ الأوّل، تسرّب البيانات.

لماذا لا يكفي تقسيم تحقّقٍ واحد

حجزت الوحدة 1 مجموعة اختبارٍ مختومة. ولضبط النماذج في الطريق يمكن اقتطاع مجموعة تحقّقٍ واحدة من بيانات التدريب — لكن مع بياناتٍ متوسّطة الحجم، هذا الاقتطاع الواحد حسّاسٌ للحظّ: مجموعة تحقّقٍ «سهلة» تُجمّل النموذج، و«صعبة» تدفنه. فيكون للتقدير تباينٌ عالٍ، وتصبح مقارنة نموذجين عليه متزعزعة.

التحقّق المتقاطع k-fold: القياس مرّاتٍ عدّة

يُثبّت التحقّق المتقاطع k-fold القياسَ بتدوير الأدوار. اقسم بيانات التدريب إلى kk كتلة (طيّات)، 5 عادةً. ثمّ kk مرّةً: درّب على k1k-1 طيّة وتحقّق على الباقية. تُستعمل كلّ نقطةٍ للتحقّق مرّةً واحدة بالضبط.

from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X_train, y_train, cv=5, scoring="roc_auc")
scores.mean(), scores.std() # الأداء ومدى استقراره

المكسب مزدوج: متوسّطٌ أوثق للأداء، والانحراف المعياري عبر الطيّات، الذي يُكمّم استقرار التقدير. ونموذجان بمتوسّطين متقاربين لكن بانحرافين مختلفين جدّاً ليسا متكافئين — فالأكثر استقراراً يفوز. وفي التصنيف يُفضَّل StratifiedKFold (الافتراضي في scikit-learn) الذي يحفظ نِسَب الأصناف في كلّ طيّة — ردّ فعل الوحدة 1، معمّماً.

البيانات الزمنية: لا تتحقّق أبداً على الماضي

يخلط k-fold القياسي الصفوف عشوائياً. وعلى البيانات الزمنية (المبيعات، الأسعار، السجلّات) هذا خطأ جسيم: فسيتدرّب النموذج على المستقبل ليُتحقَّق منه على الماضي — أداءٌ يستحيل إعادة إنتاجه في الإنتاج. والقاعدة: درّب دوماً على الماضي وتحقّق على المستقبل، كما ستفعل الواقعية. تُطبّق TimeSeriesSplit هذا المخطّط المتوسّع: درّب على الأشهر 1–6 وتحقّق على 7–8؛ درّب على 1–8 وتحقّق على 9–10؛ وهكذا.

تسرّب البيانات: العدوّ الذي يُضخّم كلّ نتيجة

التسرّب هو أيّ معلومةٍ من مجموعة التحقّق أو الاختبار (أو من المستقبل) تتسرّب إلى التدريب. تغدو النتيجة باهرة؛ وينهار النموذج في الإنتاج. أشكالٌ كلاسيكية:

  • معالجة مُسبقة محسوبة على كلّ البيانات: التقييس قبل التقسيم يحقن متوسّط الاختبار وانحرافه في التدريب — خفيٌّ وشائع جدّاً؛
  • متغيّرات لاحقة للهدف (الوحدة 1): معلومات غير متاحة لحظة التنبّؤ؛
  • تكرارات ممتدّة بين التدريب والاختبار؛
  • تسرّب زمني: خلط بياناتٍ زمنية، أو متغيّرات محسوبة على نافذةٍ تشمل المستقبل.

خطّ المعالجة، السلاح البنيوي ضدّ التسرّب

بدل مراقبة الذات يدوياً، اجعل التسرّب مستحيلاً بنيوياً: اربط المعالجة المسبقة والنموذج في Pipeline. عندئذٍ يُعيد التحقّق المتقاطع تركيب المعالجة داخل كلّ طيّة، على بيانات تدريب تلك الطيّة وحدها.

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

pipe = make_pipeline(StandardScaler(), LogisticRegression())
cross_val_score(pipe, X_train, y_train, cv=5) # المُقيِّس يُركَّب لكلّ طيّة: لا تسرّب
نتيجةٌ أفضل من اللازم إنذارٌ لا فرح

95% حيث تحصل أحدث التقنيات على 80%؟ ابحث عن التسرّب قبل الاحتفال. والقفزات المفاجئة في الأداء بعد إضافة متغيّر تستحقّ ردّ الفعل نفسه: ماذا يعرف هذا المتغيّر ممّا لا ينبغي أن يعرفه بعدُ لحظة التنبّؤ؟

الخلاصة

  • تقسيم تحقّقٍ واحد حسّاسٌ للحظّ؛ ويعطي التحقّق المتقاطع k-fold (الطبقي في التصنيف) متوسّطاً وانحرافاً معيارياً — موثوقيةً واستقراراً.
  • تتطلّب البيانات الزمنية تقسيماتٍ تحترم الزمن (TimeSeriesSplit): درّب على الماضي وتحقّق على المستقبل.
  • يُضخّم تسرّب البيانات — معالجةٌ على كلّ البيانات، متغيّرات لاحقة للهدف، تكرارات ممتدّة — النتائجَ بصمت.
  • يُعيد خطّ المعالجة تركيب المعالجة داخل كلّ طيّة: فيغدو التسرّب مستحيلاً بنيوياً.

الوحدة التالية: المقاييس نفسها — الدقّة، الإحكام، الاستدعاء، F1، ROC AUC — واختيار ما يناسب مسألة العمل.