الوحدة 9 — التحقّق المتدرّج والمقاييس الملائمة
بنيت النماذج، ومُلئت الأعمدة الأولى من جدول المقارنة، والسؤال الجوهريّ الآن: كيف نُقارن؟ التحقّق المتقاطع التقليديّ ممنوع (يخلط الزمن)، ونقطة اختبار واحدة على 28 يومًا لا تكفي (الحظّ يلعب). هذه الوحدة تُقدّم المنهجيّة المهنيّة: تحقّق بأصول متدرّجة مع مقاييس ملائمة للسلاسل الزمنية.
لماذا نقطة اختبار واحدة لا تكفي
اختبرنا في الوحدات السابقة على مقطع 28 يومًا واحد (سبتمبر 2027). فمن ذا الذي يضمن أنّ هذا المقطع ليس شهرًا خاصًّا، أو أنّ SARIMA لم يست فد من صدفة موسميّة؟ الجواب الأمين: لا أحد. لهذا نحتاج إلى تكرار الاختبار على أصول متعدّدة.
الفكرة هي التالية. نُحدّد أفقًا ونُختار عدّة تواريخ فصل ()؛ لكلّ منها نُدرّب على ونتوقّع على ونحسب MAE. ثمّ نُبلّغ عن متوسّط وانحراف MAE عبر الأصول. النموذج الأفضل هو الذي يجمع بين متوسّط منخفض واستقرار (انحراف صغير).
بديل جاهز: TimeSeriesSplit من scikit-learn
import numpy as np
from sklearn.model_selection import TimeSeriesSplit
from sklearn.metrics import mean_absolute_error
serie = df["ventes_totales"].values
n = len(serie)
H = 28
# 5 أصول متتالية، اختبار كلٍّ منها 28 يومًا.
tscv = TimeSeriesSplit(n_splits=5, test_size=H)
resultats = []
for i, (idx_tr, idx_te) in enumerate(tscv.split(serie)):
train = serie[idx_tr]
test = serie[idx_te]
# مثال: تنبّؤ ساذج موسميّ (7 أيّام).
dernier_cycle = train[-7:]
pred = np.tile(dernier_cycle, int(np.ceil(H / 7)))[:H]
mae = mean_absolute_error(test, pred)
resultats.append(mae)
print(f"طيّة {i+1}: MAE = {mae:.1f}")
print(f"\nمتوسّط MAE = {np.mean(resultats):.1f} ± {np.std(resultats):.1f}")
نافذة تدريب متزايدة (expanding) هي الافتراض: تدريب من البداية إلى . البديل: نافذة منزلقة (sliding) بعرض ثابت، مفيدة إذا كانت السلسلة تعاني من انحراف بطيء (تغيّر توزيع) ونريد النموذج ألّا يتأثّر ببيانات قديمة جدًّا.