ML Learning Hub
تطبيقيمتوسط

التنبؤ بالسلاسل الزمنية

عندما يهم ترتيب الملاحظات — التعلم من الماضي للتنبؤ بالمستقبل

تحليل الاتجاه والموسمية والبواقي وميزات التأخر والإحصاءات المتدحرجة وTimeSeriesSplit وحدس ARIMA والتعزيز التدريجي للتنبؤ الجدولي.

50 min
11 مخططات
7 المفاهيم المغطاة

المتطلبات الأساسية

Probability & Statistics
Gradient Boosting

المفاهيم المغطاة

DecompositionLag FeaturesRolling StatisticsTimeSeriesSplitACF/PACFARIMAFourier Features

الصيغ الرئيسية

التحليل

إضافي: اتجاه + موسمية + بواقي. تضاعفي: T × S × R عند نمو السعات مع الاتجاه

نموذج AR(p)

الانحدار الذاتي: القيمة الحالية مزيج خطي من p قيم سابقة

دالة الارتباط الذاتي (ACF)

ACF — مدى ارتباط السلسلة مع تأخرها بمقدار k خطوة؟

MAPE

متوسط الخطأ المطلق النسبي — مقياس توقع مستقل عن المقياس

محاكاة تفاعلية

Loading visualization…
🎯

السلاسل الزمنية في كل مكان

motivation

أسعار الأسهم، الطلب على الكهرباء، حمل CPU للخوادم، حركة المرور على الويب، حالات COVID، الطقس، المبيعات — كلها سلاسل زمنية. الاختلاف الجوهري عن التعلم الآلي القياسي: الملاحظات مرتبة ومترابطة. استخدام بيانات الغد للتنبؤ بالأمس ينتهك السببية. التقسيم العشوائي للتدريب/الاختبار يُلوِّث تقييمك لأن بيانات الاختبار تظهر في فترة التدريب. تتطلب السلاسل الزمنية تحققاً متقاطعاً زمنياً وهندسة ميزات زمنية.

Prophet (Meta) وARIMA معايير صناعية للتنبؤ. لكن gradient boosting مع ميزات التأخر الدقيقة وتحقق متقاطع TimeSeriesSplit غالباً يتفوق على كليهما في السلاسل الزمنية الجدولية.

💡

التحليل: فصل الإشارة عن الضوضاء

intuition

معظم السلاسل الزمنية الحقيقية لها ثلاثة مكونات: الاتجاه (الاتجاه طويل الأمد — ارتفاع المبيعات على مر السنين)، الموسمية (الأنماط المتكررة — مبيعات أعلى في ديسمبر)، والبواقي (ضوضاء عشوائية بعد إزالة الاتجاه والموسمية). التحليل الإضافي يعمل عند ثبات سعة الموسمية؛ التضاعفي عندما تنمو مع الاتجاه. يُعدّ STL (التحليل الموسمي-الاتجاهي باستخدام LOESS) النهج الحديث المتين — يتعامل مع فترات موسمية متعددة والشذوذات.

🔬

إنشاء ميزات من الزمن

deepdive

يمكن التعامل مع السلاسل الزمنية كتعلم آلي خاضع للإشراف بإنشاء ميزات التأخر والإحصائيات المتدحرجة. ميزات التأخر: y_{t-1}، y_{t-2}، ...، y_{t-p} تلتقط الارتباط الذاتي. الإحصائيات المتدحرجة: rolling_mean(window=7)، rolling_std، rolling_max تلتقط الاتجاه الأخير والتذبذب. ميزات التقويم: ساعة_اليوم، يوم_الأسبوع، الشهر، هل_عطلة تلتقط الموسمية. ميزات فورييه: sin(2πt/الفترة)، cos(2πt/الفترة) تُرمِّز الأنماط الموسمية السلسة.

1

إنشاء التأخرات: df['lag_1'] = df['y'].shift(1)

2

الإحصائيات المتدحرجة: df['roll_mean_7'] = df['y'].rolling(7).mean()

3

ميزات التقويم: df['يوم_الأسبوع'] = df.index.dayofweek

4

الموسمية بفورييه: أزواج sin/cos لكل فترة موسمية

5

دائماً استخدم TimeSeriesSplit — لا تخلط السلاسل الزمنية للتحقق المتقاطع أبداً

6

فجوة بين التدريب/التحقق: أضف gap= لتجنب التسريب بالارتباط الذاتي

⚙️

TimeSeriesSplit: التحقق المتقاطع الصحيح

algorithm
1

الطوق 1: تدريب=[t₁…t₃₀₀]، تحقق=[t₃₀₁…t₄₀₀]

2

الطوق 2: تدريب=[t₁…t₄₀₀]، تحقق=[t₄₀₁…t₅₀₀]

3

الطوق 3: تدريب=[t₁…t₅₀₀]، تحقق=[t₅₀₁…t₆₀₀]

4

نافذة التدريب تنتهي دائماً قبل التحقق — لا تسريب من المستقبل

5

خيار: gap=k بين نهاية التدريب وبداية التحقق (يتجنب التسريب بالارتباط الذاتي)

6

خيار: max_train_size=N لنافذة متدحرجة (فقط آخر N نقطة في التدريب)

</>

التنبؤ مع sklearn + LightGBM

code
python52 lines
import pandas as pd
import numpy as np
import lightgbm as lgb
from sklearn.model_selection import TimeSeriesSplit
from sklearn.metrics import mean_absolute_error

class="tok-comment"># ── Sample daily time-series DataFrame ────────────────────────────────
dates = pd.date_range(class="tok-str">'class="tok-num">2022-class="tok-num">01-class="tok-num">01', periods=class="tok-num">365, freq=class="tok-str">'D')
np.random.seed(class="tok-num">42)
trend = np.linspace(class="tok-num">100, class="tok-num">200, class="tok-num">365)
seasonal = class="tok-num">20 * np.sin(class="tok-num">2 * np.pi * np.arange(class="tok-num">365) / class="tok-num">7)  class="tok-comment"># weekly pattern
noise = np.random.randn(class="tok-num">365) * class="tok-num">5
df = pd.DataFrame({class="tok-str">'sales': trend + seasonal + noise}, index=dates)

def create_features(df, target_col, lags, rolling_windows):
    class="tok-str">"""Create lag and rolling features for supervised time series forecasting."""
    df = df.copy()
    for lag in lags:
        df[fclass="tok-str">'lag_{lag}'] = df[target_col].shift(lag)
    for w in rolling_windows:
        df[fclass="tok-str">'roll_mean_{w}'] = df[target_col].shift(class="tok-num">1).rolling(w).mean()
        df[fclass="tok-str">'roll_std_{w}']  = df[target_col].shift(class="tok-num">1).rolling(w).std()
    class="tok-comment"># Calendar features
    df[class="tok-str">'dayofweek']  = df.index.dayofweek
    df[class="tok-str">'month']      = df.index.month
    df[class="tok-str">'is_weekend'] = df[class="tok-str">'dayofweek'] >= class="tok-num">5
    class="tok-comment"># Fourier seasonality (weekly=class="tok-num">7, yearly=class="tok-num">365)
    for k in range(class="tok-num">1, class="tok-num">3):
        df[fclass="tok-str">'sin_week_{k}'] = np.sin(class="tok-num">2*np.pi*k * df.index.dayofyear / class="tok-num">7)
        df[fclass="tok-str">'cos_week_{k}'] = np.cos(class="tok-num">2*np.pi*k * df.index.dayofyear / class="tok-num">7)
    return df.dropna()

df_feat = create_features(df, class="tok-str">'sales', lags=[class="tok-num">1,class="tok-num">2,class="tok-num">3,class="tok-num">7,class="tok-num">14,class="tok-num">28], rolling_windows=[class="tok-num">7,class="tok-num">14,class="tok-num">28])
X = df_feat.drop(class="tok-str">'sales', axis=class="tok-num">1)
y = df_feat[class="tok-str">'sales']

class="tok-comment"># ── TimeSeriesSplit cross-validation ──────────────────────────────
tscv = TimeSeriesSplit(n_splits=class="tok-num">5, gap=class="tok-num">7)  class="tok-comment"># class="tok-num">7-day gap prevents autocorrelation leakage
maes = []

for train_idx, val_idx in tscv.split(X):
    X_tr, X_val = X.iloc[train_idx], X.iloc[val_idx]
    y_tr, y_val = y.iloc[train_idx], y.iloc[val_idx]

    model = lgb.LGBMRegressor(n_estimators=class="tok-num">500, learning_rate=class="tok-num">0.05,
                               num_leaves=class="tok-num">31, min_child_samples=class="tok-num">20)
    model.fit(X_tr, y_tr,
              eval_set=[(X_val, y_val)],
              callbacks=[lgb.early_stopping(class="tok-num">50, verbose=False)])
    maes.append(mean_absolute_error(y_val, model.predict(X_val)))

print(fclass="tok-str">"CV MAE: {np.mean(maes):.2f} ± {np.std(maes):.2f}")
⚠️

مزالق السلاسل الزمنية

pitfall

استخدام تقسيم عشوائي للتدريب/الاختبار على بيانات السلاسل الزمنية هو الخطأ رقم 1 — يتدرب نموذجك على البيانات المستقبلية مما يُنتج تقييماً متفائلاً للغاية. دائماً استخدم TimeSeriesSplit أو تقسيماً زمنياً وحيداً. الثاني: عدم إضافة فجوة بين نوافذ التدريب والتحقق — الارتباط الذاتي يجعل آخر نقطة تدريب وأول نقطة تحقق مترابطتين بشدة. الثالث: تسريب الميزات — استخدام متوسط متدحرج لـy بلا إزاحة مناسبة يعني أن القيم المستقبلية تُلوِّث الميزات الحالية. دائماً shift(1) قبل rolling.

للتنبؤ في الإنتاج، أعِد تدريب نموذجك مع وصول بيانات جديدة. النماذج التي كانت دقيقة قبل 6 أشهر قد تكون انجرفت مع تغيّر توزيع السلسلة الزمنية.

?اختبار المعرفة

يتم حفظ التقدم في متصفحك — لا حاجة لحساب.

تحتاج مهندس ذكاء اصطناعي أو عالم بيانات؟

أبني نماذج تعلم آلي مخصصة، ووكلاء ذكاء اصطناعي، ورؤية حاسوب، وأتمتة — من الفكرة إلى الإنتاج.