التنبؤ بالسلاسل الزمنية
“عندما يهم ترتيب الملاحظات — التعلم من الماضي للتنبؤ بالمستقبل”
تحليل الاتجاه والموسمية والبواقي وميزات التأخر والإحصاءات المتدحرجة وTimeSeriesSplit وحدس ARIMA والتعزيز التدريجي للتنبؤ الجدولي.
المتطلبات الأساسية
المفاهيم المغطاة
∑الصيغ الرئيسية
التحليل
إضافي: اتجاه + موسمية + بواقي. تضاعفي: T × S × R عند نمو السعات مع الاتجاه
نموذج AR(p)
الانحدار الذاتي: القيمة الحالية مزيج خطي من p قيم سابقة
دالة الارتباط الذاتي (ACF)
ACF — مدى ارتباط السلسلة مع تأخرها بمقدار k خطوة؟
MAPE
متوسط الخطأ المطلق النسبي — مقياس توقع مستقل عن المقياس
▶محاكاة تفاعلية
السلاسل الزمنية في كل مكان
أسعار الأسهم، الطلب على الكهرباء، حمل CPU للخوادم، حركة المرور على الويب، حالات COVID، الطقس، المبيعات — كلها سلاسل زمنية. الاختلاف الجوهري عن التعلم الآلي القياسي: الملاحظات مرتبة ومترابطة. استخدام بيانات الغد للتنبؤ بالأمس ينتهك السببية. التقسيم العشوائي للتدريب/الاختبار يُلوِّث تقييمك لأن بيانات الاختبار تظهر في فترة التدريب. تتطلب السلاسل الزمنية تحققاً متقاطعاً زمنياً وهندسة ميزات زمنية.
Prophet (Meta) وARIMA معايير صناعية للتنبؤ. لكن gradient boosting مع ميزات التأخر الدقيقة وتحقق متقاطع TimeSeriesSplit غالباً يتفوق على كليهما في السلاسل الزمنية الجدولية.
التحليل: فصل الإشارة عن الضوضاء
معظم السلاسل الزمنية الحقيقية لها ثلاثة مكونات: الاتجاه (الاتجاه طويل الأمد — ارتفاع المبيعات على مر السنين)، الموسمية (الأنماط المتكررة — مبيعات أعلى في ديسمبر)، والبواقي (ضوضاء عشوائية بعد إزالة الاتجاه والموسمية). التحليل الإضافي يعمل عند ثبات سعة الموسمية؛ التضاعفي عندما تنمو مع الاتجاه. يُعدّ STL (التحليل الموسمي-الاتجاهي باستخدام LOESS) النهج الحديث المتين — يتعامل مع فترات موسمية متعددة والشذوذات.
إنشاء ميزات من الزمن
يمكن التعامل مع السلاسل الزمنية كتعلم آلي خاضع للإشراف بإنشاء ميزات التأخر والإحصائيات المتدحرجة. ميزات التأخر: y_{t-1}، y_{t-2}، ...، y_{t-p} تلتقط الارتباط الذاتي. الإحصائيات المتدحرجة: rolling_mean(window=7)، rolling_std، rolling_max تلتقط الاتجاه الأخير والتذبذب. ميزات التقويم: ساعة_اليوم، يوم_الأسبوع، الشهر، هل_عطلة تلتقط الموسمية. ميزات فورييه: sin(2πt/الفترة)، cos(2πt/الفترة) تُرمِّز الأنماط الموسمية السلسة.
إنشاء التأخرات: df['lag_1'] = df['y'].shift(1)
الإحصائيات المتدحرجة: df['roll_mean_7'] = df['y'].rolling(7).mean()
ميزات التقويم: df['يوم_الأسبوع'] = df.index.dayofweek
الموسمية بفورييه: أزواج sin/cos لكل فترة موسمية
دائماً استخدم TimeSeriesSplit — لا تخلط السلاسل الزمنية للتحقق المتقاطع أبداً
فجوة بين التدريب/التحقق: أضف gap= لتجنب التسريب بالارتباط الذاتي
TimeSeriesSplit: التحقق المتقاطع الصحيح
الطوق 1: تدريب=[t₁…t₃₀₀]، تحقق=[t₃₀₁…t₄₀₀]
الطوق 2: تدريب=[t₁…t₄₀₀]، تحقق=[t₄₀₁…t₅₀₀]
الطوق 3: تدريب=[t₁…t₅₀₀]، تحقق=[t₅₀₁…t₆₀₀]
نافذة التدريب تنتهي دائماً قبل التحقق — لا تسريب من المستقبل
خيار: gap=k بين نهاية التدريب وبداية التحقق (يتجنب التسريب بالارتباط الذاتي)
خيار: max_train_size=N لنافذة متدحرجة (فقط آخر N نقطة في التدريب)
التنبؤ مع sklearn + LightGBM
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}")
مزالق السلاسل الزمنية
استخدام تقسيم عشوائي للتدريب/الاختبار على بيانات السلاسل الزمنية هو الخطأ رقم 1 — يتدرب نموذجك على البيانات المستقبلية مما يُنتج تقييماً متفائلاً للغاية. دائماً استخدم TimeSeriesSplit أو تقسيماً زمنياً وحيداً. الثاني: عدم إضافة فجوة بين نوافذ التدريب والتحقق — الارتباط الذاتي يجعل آخر نقطة تدريب وأول نقطة تحقق مترابطتين بشدة. الثالث: تسريب الميزات — استخدام متوسط متدحرج لـy بلا إزاحة مناسبة يعني أن القيم المستقبلية تُلوِّث الميزات الحالية. دائماً shift(1) قبل rolling.
للتنبؤ في الإنتاج، أعِد تدريب نموذجك مع وصول بيانات جديدة. النماذج التي كانت دقيقة قبل 6 أشهر قد تكون انجرفت مع تغيّر توزيع السلسلة الزمنية.
?اختبار المعرفة
يتم حفظ التقدم في متصفحك — لا حاجة لحساب.