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

الوحدة 10 — مشروع: التنبّؤ بالطلب مع فواصل

الوحدات التسع السابقة بنَت الأدوات. هذه الوحدة تجمعها في مشروع نهائيّ كامل: تسليم توقّع 28 يومًا للطلب على 250 صيدليّة، مع فواصل قابلة للتحويل إلى قرارات مخزون، وخطّة إعادة تدريب، وتبليغ صريح لعدم اليقين. النموذج سيُنشر في نظام حقيقيّ، ليس تمرينًا.

قراءة جدول المقارنة النهائيّ

بعد تحقّق متدرّج بخمس طيّات (وحدة 9)، الجدول الذي نُقدّمه إلى قسم القرار:

النموذجMAE ± σ (28 يومًا)MASEزمن التدريبزمن الاستدلال
naïf saisonnier145 ± 181.00فوريّفوريّ
SARIMA(1,1,1)(0,1,1)7_7122 ± 150.843 د0.2 ث
Prophet + fêtes115 ± 120.798 د0.5 ث
LightGBM + calendrier101 ± 90.7045 ث0.05 ث
LSTM (64, L=60)98 ± 140.6822 د (GPU)1.2 ث

LightGBM هو الفائز لسلسلتنا. المبرّرات:

  • الدقّة قريبة من LSTM (فارق 3٪) مع استقرار أفضل (انحراف 9 بدلًا من 14).
  • زمن التدريب أقصر بـ30 مرّة، فقابل لإعادة التدريب اليوميّ بلا تكلفة.
  • الاستدلال أسرع بـ24 مرّة، فيقبل الاستعلامات التفاعليّة من واجهة قسم الشراء.
  • الصيانة أخفّ بكثير: لا تكوينات PyTorch، لا بطاقات رسوميّة، لا حاجة إلى ضبط دقيق للوسائط الفائقة.

هذا الخيار مبنيّ على أدلّة، لا على ذوق. غياب هذا الجدول في مشروع تنبّؤ هو غياب المنهجيّة أصلًا.

فواصل بالكمّيّات: الحلّ العمليّ

النقاط وحدها لا تكفي لقسم الشراء. نحتاج «توقّع 200 مع فاصل [155, 260]». الطريقة المفضّلة في 2026: انحدار الكمّيّات مع LightGBM، أي تدريب نموذجين إضافيّين يُنتِجان الحدّ السفليّ والعلويّ:

import lightgbm as lgb

vars_base = dict(
n_estimators=500,
learning_rate=0.05,
num_leaves=31,
min_child_samples=20,
random_state=42,
)

# نموذج الوسط: L2 (متوسّط شرطيّ).
m_moyen = lgb.LGBMRegressor(**vars_base, objective="regression_l2")
m_moyen.fit(X_tr, y_tr)

# نموذج الكمّيّة 0.05 (الحدّ السفليّ).
m_bas = lgb.LGBMRegressor(**vars_base, objective="quantile", alpha=0.05)
m_bas.fit(X_tr, y_tr)

# نموذج الكمّيّة 0.95 (الحدّ العلويّ).
m_haut = lgb.LGBMRegressor(**vars_base, objective="quantile", alpha=0.95)
m_haut.fit(X_tr, y_tr)

# التنبّؤ يعطي ثلاث قيم لكلّ نقطة.
pred_moy = m_moyen.predict(X_te)
pred_bas = m_bas.predict(X_te)
pred_haut = m_haut.predict(X_te)

# فاصل 90٪ (95٪ - 5٪).
largeur_moy = (pred_haut - pred_bas).mean()
print(f"عرض متوسّط للفاصل 90٪ = {largeur_moy:.1f}")

نتحقّق من التغطية الفعليّة (وحدة 9): يجب أن يقع 90٪ من القيم الحقيقيّة داخل الفاصل. إن كانت التغطية 78٪، فالفاصل ثقة زائدة: نُوسّع الكمّيّات (0.03 و0.97). إن كانت 96٪، فالفاصل واسع بلا داعٍ: نُضيّق. ثلاث دورات معايرة عادةً تكفي.

خطّة إعادة التدريب

نموذج مُنشَر يُصبح قديمًا. اتّجاهات المبيعات تتحوّل، تُطرح منتجات جديدة، تتغيّر السياسات. خطّة إعادة تدريب لا تقلّ أهمّيّة عن النموذج الأوّل:

  • تكرار إعادة التدريب: أسبوعيّ لمبيعاتنا. أدنى من ذلك يُخاطر بانحراف. أعلى من ذلك (يوميّ) يُضيف تعقيدًا بلا مكافأة عادة.
  • إطلاق مُحفَّز: مراقبة MAE المتدحرج على النافذة الأخيرة (7 أيّام). إذا تجاوز عتبة (مثلًا 1.5 ضعف MAE المرجعيّ)، أطلق إعادة تدريب استثنائيّة.
  • إعادة معايرة الفواصل: كلّ 30 يومًا. تغطية الفاصل قد تنحرف بلا انحراف واضح للنقطة.
  • مراجعة يدويّة ربع سنويّة: يستعرض المهندس النتائج على أفق الربع، ويقرّر إن كانت المتغيّرات ما زالت ذات صلة أو يجب إضافة جديدة.
# مثال إعادة تدريب مبرمج (pseudo-code).
def entrainement_hebdomadaire():
df = charger_donnees_a_jour()
X, y = preparer_matrice(df)

# نُدرّب النماذج الثلاثة (وسط، كمّيّتان).
m_moyen.fit(X, y)
m_bas.fit(X, y)
m_haut.fit(X, y)

# نحفظ الأوزان ونُبلّغ المقاييس.
sauvegarder([m_moyen, m_bas, m_haut])
envoyer_rapport_metriques()

# جدولة عبر cron: chaque lundi 03:00 UTC.

تبليغ عدم اليقين إلى الأعمال

قسم الشراء لا يُريد نموذجًا بل قرارًا مساعدًا. تحويل التنبّؤ إلى قرار يستلزم عرضًا واضحًا لعدم اليقين. ثلاث قواعد للعرض:

  • أظهر الفاصل، لا النقطة وحدها. جدول العرض الأدنى: [توقّع منخفض، توقّع متوسّط، توقّع مرتفع] لكلّ يوم.
  • ترجم النسبة إلى وحدات. لا تقل «فاصل 90٪ بعرض ±\pm15٪»؛ قل «الطلب متوقّع بين 340 و490 وحدة». الأعداد المطلقة تُقرأ فورًا.
  • صنّف الأيّام حسب الثقة. عمود إضافيّ «ثقة عالية / متوسّطة / منخفضة» يُبنى من عرض الفاصل النسبيّ. تسمح للمشتري بتخصيص اهتمامه.

مثال جدول التسليم للأسبوع القادم:

التاريخالتوقّعالفاصل 90٪الثقة
2027-09-01 (أحد)175[148, 210]عالية
2027-09-02 (اثنين)380[325, 445]متوسّطة
2027-09-07 (سبت)190[130, 265]منخفضة (عيد)

قائمة تحقّق قبل الإطلاق

قبل نشر النموذج، مرّ على القائمة كلّها:

  • تحقّق متدرّج بـ5 طيّات على الأقلّ، لا نقطة واحدة (وحدة 9).
  • المقياس الرئيسيّ هو MASE أو MAE، ليس MAPE إن كان يوجد أصفار.
  • المقارنة مع naïf saisonnier صريحة؛ التحسّن ≥ 15٪ يُبرّر النموذج.
  • كلّ متنبّئ خارجيّ مصنَّف معروف أو غير معروف مستقبلًا (وحدة 7).
  • الفواصل معايَرة؛ التغطية الفعليّة قريبة من المُعلنة ±\pm3٪.
  • خطّة إعادة التدريب مبرمجة (تكرار + إطلاق مُحفَّز).
  • نموذج طوارئ (naïf saisonnier) يعمل تلقائيًا عند فشل النموذج الرئيسيّ.
  • لوحة قيادة عرض للفريق التجاريّ (فاصل، ثقة مصنَّفة، حصّة تاريخيّة).
قاعدة الرقم الوحيد

حين يطلب المدير رقمًا واحدًا لتقييم النموذج، قل: «نُخطئ في المتوسّط بـ101 وحدة يوميًا، مقابل 145 وحدة للأداة السابقة، أي تحسّن 30٪». النسبة الأخيرة (تحسّن مقابل الأداة الحاليّة) هي ما يُقنع القرار المؤسّسيّ، لا MAE مطلق ولا MASE مفصَّل. احضِر MAE مباشرة، ولكن اربطها فورًا بالمرجع.

فاصل ضيّق قاتل

فاصل يبدو ضيّقًا يوحي بثقة عالية، لكن إن كانت تغطيته الفعليّة 65٪ حين أعلن 90٪، فأنت تُنتج قرارات مخزون خاطئة بشكل ممنهج. المشترون سيبنون على الحدّ العلويّ، وسيقعون في نفاد مخزون شهريّ. قِس التغطية دائمًا قبل النشر، وأعِد المعايرة كلّ 30 يومًا.

الخلاصة

  • جدول المقارنة النهائيّ بأدلّة تحقّق متدرّج هو أساس اختيار النموذج، لا الرقم الأوّل ولا الذوق.
  • انحدار الكمّيّات مع LightGBM يُنتج فواصل مباشرة (حدّ سفليّ، وسط، حدّ علويّ)؛ نُعاير التغطية على مجموعة اختبار.
  • خطّة إعادة التدريب ضروريّة: تكرار أسبوعيّ، إطلاق مُحفَّز على انحراف MAE، إعادة معايرة فواصل شهريّة.
  • تبليغ عدم اليقين بفاصل مطلق (وحدات، لا نسب مجرّدة) وثقة مصنَّفة يُحوّل التنبّؤ إلى قرار قابل للتنفيذ.

انتهت الوحدات العشر. الوحدة القادمة: خلاصة الدورة كاملة، شجرة قرار اختيار الطريقة، وإعلان الامتحان.