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

الوحدة 6 — التمهيد الأسّي وProphet

بعد الحائط الإحصائيّ الكلاسيكيّ (SARIMA)، ننتقل إلى عائلتين شائعتين جدًّا في المصانع والشركات: التمهيد الأسّي بصيغته Holt-Winters، وProphet الذي طرحه فيسبوك في 2017 وأصبح خيارًا صناعيًا واسعًا. هذه الوحدة تشرح الاثنين، وتُثبّت المقارنة، وتُضيء بصراحة على حدود Prophet التي كثيرًا ما تُخفى في العروض التسويقيّة.

Holt-Winters: التمهيد الأسّي الثلاثيّ

فكرة التمهيد الأسّي بسيطة وأنيقة: كلّ تنبّؤ هو متوسّط موزون للماضي، مع أوزان تتناقص أسّيًّا كلّما ابتعدنا في الزمن. النسخة الأولى (Simple Exponential Smoothing) تُتابع مستوى ثابتًا. Holt يُضيف مكوّنة اتّجاه. أمّا Holt-Winters فيُضيف موسميّة، ويأتي في نسختين جمعيّة وضربيّة تُذكّرنا بتفكيك الوحدة 2.

الصيغ الثلاث (نسخة جمعيّة):

t=α(ytstm)+(1α)(t1+bt1)\ell_t = \alpha (y_t - s_{t-m}) + (1-\alpha)(\ell_{t-1} + b_{t-1}) bt=β(tt1)+(1β)bt1b_t = \beta (\ell_t - \ell_{t-1}) + (1-\beta) b_{t-1} st=γ(ytt1bt1)+(1γ)stms_t = \gamma (y_t - \ell_{t-1} - b_{t-1}) + (1-\gamma) s_{t-m}

المستوى \ell يتتبّع القيمة الحاليّة، والاتّجاه bb يتتبّع الميل، والموسميّة ss تتتبّع النمط الدوريّ. المعاملات α,β,γ[0,1]\alpha, \beta, \gamma \in [0, 1] تُقدَّر تلقائيًا بتقليل مجموع مربّعات الأخطاء.

from statsmodels.tsa.holtwinters import ExponentialSmoothing

modele_hw = ExponentialSmoothing(
train,
trend="add",
seasonal="add",
seasonal_periods=7,
initialization_method="estimated",
).fit()

prev_hw = modele_hw.forecast(steps=28)
mae_hw = (prev_hw - test).abs().mean()
print(f"MAE Holt-Winters (7) = {mae_hw:.1f}")

ملاحظات عمليّة. أوّلًا، اختيار seasonal="add" أو "mul" يعكس نفس القرار من الوحدة 2 (جمعيّ إن كانت التذبذبات ثابتة الحجم، ضربيّ إن كانت تتضخّم مع الاتّجاه). ثانيًا، Holt-Winters يُدير موسميّة واحدة؛ للأسبوعيّة + السنويّة نحتاج إلى امتداد ETSModel أو Prophet. ثالثًا، أداء Holt-Winters كثيرًا ما يقارب SARIMA على السلاسل الأسبوعيّة البسيطة، بميزة سرعة تدريب مذهلة.

Prophet: التفكيك المعمَّم لأغراض الأعمال

Prophet ليس نموذجًا إحصائيًا كلاسيكيًا بل نموذج انحدار توليديّ مضاف يفكّك السلسلة إلى أربع مكوّنات صريحة:

y(t)=g(t)+s(t)+h(t)+εty(t) = g(t) + s(t) + h(t) + \varepsilon_t

حيث g(t)g(t) اتّجاه (قابل للانحناء عند نقاط كسر تُكتشف تلقائيًا)، وs(t)s(t) موسميّات دوريّة تُمثَّل بمتسلسلات فورييه (لذا يمكن الجمع بين أسبوعيّة وسنويّة بلا صعوبة)، وh(t)h(t) أثر الأعياد المُصرَّح بها، وεt\varepsilon_t ضجيج.

import pandas as pd
from prophet import Prophet

# Prophet يتوقّع أعمدة "ds" و"y".
d = train.reset_index().rename(columns={"date": "ds", "ventes_totales": "y"})

# نُصرّح الأعياد الوطنيّة التي أُثبت أثرها على المبيعات.
feries = pd.DataFrame({
"holiday": "aid",
"ds": pd.to_datetime(["2024-04-10", "2025-03-31", "2026-03-20", "2027-03-09"]),
"lower_window": -1,
"upper_window": 2,
})

modele_p = Prophet(
yearly_seasonality=True,
weekly_seasonality=True,
daily_seasonality=False,
seasonality_mode="multiplicative",
holidays=feries,
changepoint_prior_scale=0.05, # مرونة الاتّجاه: 0.05 افتراضيّ محافظ
)
modele_p.fit(d)

futur = modele_p.make_future_dataframe(periods=28, freq="D")
prev_p = modele_p.predict(futur).tail(28)

mae_p = (prev_p["yhat"].values - test.values).mean()
print(f"MAE Prophet = {abs(mae_p):.1f}")

يُنتج predict عمودًا yhat (التنبّؤ) وعمودَي yhat_lower وyhat_upper (فاصلا ثقة افتراضيّان 80%، قابلان للضبط). قوّة Prophet الحقيقيّة تكمن في سهولة إدماج الأعياد، وفي الرسوم التشخيصيّة الجاهزة التي تعرض المكوّنات (modele_p.plot_components(prev_p)).

نقاط الكسر: قوّة وخطر

Prophet يحدّد تلقائيًا نقاطًا في السلسلة يتغيّر عندها ميل الاتّجاه. الوسيط changepoint_prior_scale (افتراضيّ 0.05) يتحكّم في مدى حرّيّة هذه النقاط: كلّما كبر، اتّبعت السلسلة تغيّرات حادّة، وكلّما صغر، بقي الاتّجاه محافظًا. على سلسلة صيدليّاتنا، رفع القيمة إلى 0.5 يُنتج إفراطًا في التخصيص على تذبذبات ماضية غير قابلة للتكرار؛ خفضها إلى 0.01 يُبطئ الاستجابة لتغيير حقيقيّ (فتح فروع جديدة). قيمة افتراضيّة معتدلة، ثمّ ضبط على تحقّق متدرّج (وحدة 9)، هو المسار الصحيح.

حدود Prophet الحقيقيّة

Prophet سهل الاستخدام إلى درجة تجعله الخيار الأوّل في كثير من المشاريع. لكنّه بعيد عن أن يكون الأفضل دائمًا، وثلاثة قيود يجب أن تظهر في تقييم أيّ فريق:

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

سمعة Prophet سمعتان: أحد أفضل الأدوات لبدء مشروع، وأحد أسوأ الأدوات إن تُرك على القيم الافتراضيّة في مسألة معقّدة. القيم الافتراضيّة تفترض بيانات نظيفة، وموسميّة لطيفة، ومنحنى عام. على مبيعات صيدليّات بأعياد شديدة الأثر وحملات ترويجيّة نادرة، القيم الافتراضيّة تُفوّت البنية الأهمّ، ويُترجَم ذلك إلى MAE أسوأ من Holt-Winters البسيط.

تحديث جدول المقارنة

بعد هذه الوحدة نضيف صفّين:

النموذجMAE (28 يومًا)MASE
naïf saisonnier1451.00
SARIMA(1,1,1)(0,1,1)7_71180.81
Holt-Winters (7)1250.86
Prophet (default + fêtes)1120.77

Prophet مع الأعياد يتفوّق قليلًا على SARIMA على مبيعاتنا، ويُشكّل الآن السقف الجديد. الوحدة 7 ستحاول كسره عبر إعادة صياغة المسألة انحدارًا مع تعزيز تدرّجي.

الخلاصة

  • Holt-Winters بديل بسيط وسريع لـSARIMA على السلاسل ذات موسميّة واحدة؛ نختار جمعيّ أو ضربيّ بنفس منطق الوحدة 2.
  • Prophet يُفكّك اتّجاهًا مرنًا (نقاط كسر) + موسميّات فورييه (متعدّدة) + أثر أعياد صريح؛ يبرع في مسائل الأعمال بكثرة أحداث تقويميّة.
  • changepoint_prior_scale يوازن بين الاستجابة والإفراط في التخصيص؛ يُضبط على تحقّق متدرّج، ليس على النظر.
  • Prophet ليس دائمًا الأفضل: يخسر أمام SARIMA على السلاسل النظيفة، وأمام تعزيز تدرّجي حين كثرت المتفاعلات؛ فواصله يجب أن تُعاير قبل الاعتماد عليها.

الوحدة التالية: تحويل المسألة إلى انحدار مع تأخّرات، ونوافذ، ومتغيّرات تقويم، وتعزيز تدرّجي.