الوحدة 8 — التحقّق المتقاطع والتقسيم الزمني وتسرّب البيانات
سبع وحداتٍ من النماذج؛ وحان وقت الانضباط الذي يجعل نتائجها جديرة بالثقة. لا قيمة لنموذجٍ بلا قياسٍ نزيه — والقياسات غير النزيهة سهلة الإنتاج على نحوٍ مُرعِب. تُحكِم هذه الوحدة منهج التقييم: التحقّق المتقاطع، تقسيماتٌ تحترم الزمن، ومطاردة العدوّ الأوّل، تسرّب البيانات.
لماذا لا يكفي تقسيم تحقّقٍ واحد
حجزت الوحدة 1 مجموعة اختبارٍ مختومة. ولضبط النماذج في الطريق يمكن اقتطاع مجموعة تحقّقٍ واحدة م ن بيانات التدريب — لكن مع بياناتٍ متوسّطة الحجم، هذا الاقتطاع الواحد حسّاسٌ للحظّ: مجموعة تحقّقٍ «سهلة» تُجمّل النموذج، و«صعبة» تدفنه. فيكون للتقدير تباينٌ عالٍ، وتصبح مقارنة نموذجين عليه متزعزعة.
التحقّق المتقاطع k-fold: القياس مرّاتٍ عدّة
يُثبّت التحقّق المتقاطع k-fold القياسَ بتدوير الأدوار. اقسم بيانات التدريب إلى كتلة (طيّات)، 5 عادةً. ثمّ مرّةً: درّب على طيّة وتحقّق على الباقية. تُستعمل كلّ نقطةٍ للتحقّق مرّةً واحدة بالضبط.
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 — واختيار ما يناسب مسألة العمل.