فاز 2 · درس 15

مبانی سری زمانی: ویژگی‌های تأخیری و اعتبارسنجی پیش‌رونده

نوع
ساختنی
زمان
حدود 90 دقیقه
زبان‌ها
Python
پیش‌نیاز
یادگیری ماشین چیست؟ مفاهیم پایه، انواع و پیاده‌سازی از صفر، رگرسیون خطی از صفر تا پیاده‌سازی با scikit-learn، رگرسیون لجستیک و دسته‌بندی از صفر، درخت تصمیم و جنگل تصادفی: پیاده‌سازی از صفر و تئوری ریاضی، ماشین‌های بردار پشتیبان (SVM)؛ از فرمول‌بندی ریاضی تا پیاده‌سازی، الگوریتم K-نزدیک‌ترین همسایه (KNN) و معیارهای فاصله، یادگیری نظارت‌نشده و الگوریتم‌های خوشه‌بندی، مهندسی و انتخاب ویژگی در یادگیری ماشین، ارزیابی مدل در یادگیری ماشین: از صفر تا پیاده‌سازی و تحلیل
نمودار خطی نوسان داده‌های زمانی همراه با یک ساعت شنی و تقویم رومیزی مینیمال روی میز کار مهندسی
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. مفاهیم پایه
  4. چه چیزی سری زمانی را متفاوت می‌کند؟
  5. مؤلفه‌های سری زمانی
  6. مانایی (Stationarity)
  7. خودهمبستگی (Autocorrelation)
  8. ویژگی‌های تأخیری: تبدیل سری زمانی به یادگیری با نظارت
  9. اعتبارسنجی پیش‌رونده (Walk-Forward Validation)
  10. درک شهودی مدل ARIMA
  11. کدام روش برای چه کاری مناسب است؟
  12. افق‌ها و استراتژی‌های پیش‌بینی
  13. اشتباهات رایج در سری زمانی
  14. پیاده‌سازی
  15. سازنده‌ی ویژگی‌های تأخیری
  16. اعتبارسنجی متقاطع پیش‌رونده
  17. مدل خودهمبسته‌ی ساده (AR)
  18. بررسی مانایی
  19. خودهمبستگی
  20. استفاده در عمل
  21. ابزار TimeSeriesSplit در sklearn
  22. معیارهای ارزیابی
  23. ویژگی‌های متحرک (Rolling Features)
  24. خروجی نهایی
  25. خطوط مبنایی که باید شکست دهید
  26. نکات کاربردی
  27. تمرین‌ها
  28. اصطلاحات کلیدی
  29. مطالعه‌ی بیشتر

بسیاری از مسائلی که در پروژه‌های واقعی با آن‌ها روبه‌رو می‌شوید؛ از پیش‌بینی ترافیک و فروش فروشگاه‌ها گرفته تا مصرف سرورها و شاخص‌های مالی، داده‌هایی وابسته به زمان دارند. خطای بزرگی که خیلی از توسعه‌دهندگان مرتکب می‌شوند، برخورد با داده‌های زمانی درست مثل داده‌های جدولی معمولی است؛ یعنی بر زدن داده‌ها، تقسیم تصادفی آموزش و آزمون و سپس مواجهه با مدلی که در عمل و پروداکشن به شدت افت می‌کند.

داده‌های سری زمانی دو اصل مهم یادگیری ماشین کلاسیک یعنی استقلال نمونه‌ها و توزیع یکسان (i.i.d.) را نقض می‌کنند. در این درس یاد می‌گیرید چگونه داده‌ها را از نظر مانایی، روند و فصلی‌بودن ارزیابی کنید، با تفاضل‌گیری نوسانات را مهار سازید و از ویژگی‌های تأخیری (lag features) برای آموزش مدل‌های رگرسیون استفاده کنید.

همچنین با چارچوب اعتبارسنجی پیش‌رونده (walk-forward validation) آشنا می‌شوید تا بدون نشت داده‌های آینده به گذشته، ارزیابی دقیق و معتبری از عملکرد مدل داشته باشید. همه‌ی محاسبات و کدهای این درس روی CPU معمولی سیستم شخصی شما اجرا می‌شوند و به ابزار ابری یا سخت‌افزار خاصی نیاز نخواهید داشت.

عملکرد گذشته نتایج آینده را پیش‌بینی می‌کند؛ البته به شرطی که اول مانایی را بررسی کرده باشید.

اهداف یادگیری

  • تجزیه‌ی سری زمانی به مؤلفه‌های روند، فصلی‌بودن و باقی‌مانده، و آزمون مانایی داده‌ها
  • پیاده‌سازی ویژگی‌های تأخیری (lag features) و آماره‌های متحرک برای تبدیل سری زمانی به یک مسئله‌ی یادگیری با نظارت
  • ساخت چارچوب اعتبارسنجی پیش‌رونده (walk-forward validation) برای جلوگیری از نشت داده‌های آینده به مرحله‌ی آموزش
  • توضیح اینکه چرا تقسیم تصادفی به آموزش/آزمون در سری‌های زمانی نامعتبر است و نمایش اختلاف عملکرد آن در مقایسه با تقسیم زمانی اصولی

صورت مسئله

داده‌هایی دارید که بر اساس زمان مرتب شده‌اند: فروش روزانه، دمای ساعتی، مصرف دقیقه‌ای CPU یا قیمت هفتگی سهام. می‌خواهید مقدار بعدی، هفته‌ی بعد یا فصل مالی بعد را پیش‌بینی کنید.

سراغ جعبه‌ابزار استاندارد یادگیری ماشین می‌روید: تقسیم تصادفی به آموزش/آزمون، اعتبارسنجی متقاطع (cross-validation)، تحویل ماتریس ویژگی‌ها و دریافت پیش‌بینی. اینجا تک‌تک قدم‌ها اشتباه‌اند.

سری زمانی فرض‌های بنیادینی را که یادگیری ماشین استاندارد بر آن‌ها تکیه دارد بر هم می‌زند. نمونه‌ها مستقل از هم نیستند؛ دمای امروز به دمای دیروز وابسته است. تقسیم تصادفی، اطلاعات آینده را وارد گذشته می‌کند. ویژگی‌هایی که در بک‌تست عالی به نظر می‌رسند، در پروداکشن شکست می‌خورند؛ چون به الگوهایی وابسته‌اند که در طول زمان تغییر می‌کنند.

مدلی که در اعتبارسنجی متقاطع تصادفی به دقت 95% می‌رسد، ممکن است با ارزیابی دقیقِ زمانی روی 55% بیفتد. این تفاوت صرفاً یک ریزه‌کاری فنی نیست؛ فاصله‌ی میان مدلی است که فقط روی کاغذ کار می‌کند با مدلی که در پروداکشن جواب می‌دهد.

در این درس به مفاهیم پایه می‌پردازیم: چه چیزی داده‌های زمانی را متفاوت می‌کند، چطور مدل‌ها را صادقانه ارزیابی کنیم، و چگونه یک سری زمانی را به ویژگی‌هایی تبدیل کنیم که مدل‌های استاندارد یادگیری ماشین بتوانند از آن‌ها استفاده کنند.

مفاهیم پایه

چه چیزی سری زمانی را متفاوت می‌کند؟

یادگیری ماشین استاندارد فرض می‌کند داده‌ها i.i.d. هستند: مستقل و با توزیع یکسان (independent and identically distributed). یعنی هر نمونه مستقل از بقیه‌ی نمونه‌ها و از توزیعی یکسان انتخاب شده است. سری زمانی هر دو فرض را نقض می‌کند:

  • مستقل نیستند. قیمت امروز سهام به دیروز بستگی دارد. فروش این هفته با هفته‌ی گذشته همبستگی دارد.
  • توزیع یکسان ندارند. توزیع داده‌ها در طول زمان تغییر می‌کند. الگوی فروش در ماه آذر کاملاً با خرداد فرق دارد.

این نقض‌ها خطاهای جزئی نیستند. شیوه‌ی مهندسی ویژگی‌ها، نحوه‌ی ارزیابی مدل و الگوریتم‌های کاربردی، همگی تحت تأثیر این تفاوت‌ها تغییر می‌کنند.

سری زمانی (غیر i.i.d.)یادگیری ماشین استاندارد (i.i.d.)نمونه 1نمونه 2نمونه 3t=1t=2t=3t=4

در یادگیری ماشین استاندارد، نمونه‌ها جابه‌جاشدنی هستند و بُر زدن آن‌ها چیزی را عوض نمی‌کند. اما در سری زمانی، ترتیب همه چیز است؛ بر زدن نمونه‌ها، سیگنال داده را نابود می‌کند.

مؤلفه‌های سری زمانی

هر سری زمانی ترکیبی از سه مؤلفه است:

سری زمانی مشاهده‌شدهروندفصلی بودنباقی‌مانده/نویزجهت بلندمدت: صعودی، نزولی، خنثیالگوهای تکرارشونده: روزانه، هفتگی، سالانهتغییرات تصادفی پس از حذف روند و فصلیبودن
  • روند (Trend): جهت حرکت بلندمدت داده‌ها؛ مانند رشد سالانه‌ی 10 درصدی درآمد یا افزایش دمای کره‌ی زمین.
  • فصلی‌بودن (Seasonality): الگوهای تکرارشونده در بازه‌های زمانی ثابت؛ مثل جهش فروش خرده‌فروشی‌ها در اسفند یا اوج‌گیری مصرف کولر در تیرماه.
  • باقی‌مانده (Residual): هر آنچه پس از حذف روند و الگوهای فصلی باقی می‌ماند. اگر باقی‌مانده شبیه به نویز سفید (white noise) باشد، یعنی تجزیه‌ی سری سیگنال اصلی را استخراج کرده است.

مانایی (Stationarity)

سری زمانی وقتی مانا (stationary) است که ویژگی‌های آماری آن (میانگین، واریانس و خودهمبستگی) در طول زمان ثابت بمانند. بیشتر روش‌های پیش‌بینی، فرض را بر مانا بودن سری می‌گذارند.

چرا اهمیت دارد؟ در سری نامانا، میانگین در طول زمان جا‌به‌جا می‌شود. مدلی که با داده‌های فروردین آموزش دیده، میانگینی را یاد گرفته که با میانگین اردیبهشت فرق دارد؛ در نتیجه پیش‌بینی‌های مدل دچار خطای سیستماتیک می‌شوند.

روش بررسی: میانگین متحرک (rolling mean) و انحراف معیار متحرک (rolling standard deviation) را در پنجره‌های زمانی مختلف حساب کنید. اگر این مقادیر تغییر جهت دهند و جا‌به‌جا شوند، سری نامانا است.

روش اصلاح: تفاضل‌گیری (differencing). به‌جای مدل‌سازی خود مقادیر خام، تغییرات بین داده‌های متوالی را مدل‌سازی کنید:

diff[t]=value[t]−value[t−1]\text{diff}[t] = \text{value}[t] - \text{value}[t-1]

اگر یک مرتبه تفاضل‌گیری سری را مانا نکرد، یک بار دیگر تفاضل‌گیری کنید (تفاضل‌گیری مرتبه‌ی دوم). بیشتر سری‌های دنیای واقعی با حداکثر دو بار تفاضل‌گیری مانا می‌شوند.

مثال:

سری اصلی: [100, 102, 106, 112, 120] تفاضل اول: [2, 4, 6, 8] (هنوز روند صعودی دارد) تفاضل دوم: [2, 2, 2] (ثابت — مانا شده است)

سری اصلی روندی درجه‌دو داشت. تفاضل اول آن را به روندی خطی تبدیل کرد و تفاضل دوم آن را مسطح ساخت. در عمل، به‌ندرت به بیش از دو بار تفاضل‌گیری نیاز پیدا می‌کنید.

آزمون رسمی: آزمون دیکی-فولر تعمیم‌یافته (Augmented Dickey-Fuller یا ADF) آزمون آماری استاندارد برای بررسی مانایی است. فرض صفر (Null hypothesis) این آزمون می‌گوید «سری نامانا است». مقدار p-value کمتر از 0.05 یعنی می‌توانید فرض صفر را رد کنید و نتیجه بگیرید سری مانا است. ما آزمون ADF را از صفر پیاده نمی‌کنیم (چون نیاز به جدول‌های توزیع مجانبی دارد)، اما رویکرد آماره‌های متحرک در کد، روشی بصری و کاربردی برای ارزیابی مانایی به ما می‌دهد.

خودهمبستگی (Autocorrelation)

خودهمبستگی اندازه می‌گیرد که مقدار سری در زمان tt چقدر با مقدار آن در زمان t−kt-k (یعنی kk گام قبل) همبستگی دارد. تابع خودهمبستگی (Autocorrelation Function یا ACF) این همبستگی را به ازای هر تأخیر (lag) kk رسم می‌کند.

ACF به شما می‌گوید:

  • حافظه‌ی سری چقدر به عقب برمی‌گردد. اگر ACF بعد از لگ 5 به صفر برسد، داده‌های قدیمی‌تر از 5 گام قبل اهمیتی ندارند.
  • آیا الگوی فصلی وجود دارد یا نه. اگر در داده‌های ماهانه، ACF در لگ 12 جهش کند، فصلی‌بودن سالانه داریم.
  • چند ویژگی تأخیری بسازید. باید تا لگی که ACF ناچیز می‌شود، ویژگی بسازید.

تابع خودهمبستگی جزئی (Partial Autocorrelation Function یا PACF) همبستگی‌های غیرمستقیم را حذف می‌کند. اگر مقدار امروز با 3 روز پیش همبستگی دارد صرفاً به این دلیل که هر دو با دیروز همبسته‌اند، PACF در لگ 3 صفر خواهد بود، در حالی که ACF در لگ 3 صفر نخواهد بود.

ویژگی‌های تأخیری: تبدیل سری زمانی به یادگیری با نظارت

مدل‌های استاندارد یادگیری ماشین به ماتریس ویژگی X و متغیر هدف y نیاز دارند. سری زمانی فقط یک ستون داده به شما می‌دهد. پل ارتباطی میان این دو، ویژگی‌های تأخیری (lag features) هستند.

سری [10, 12, 14, 13, 15] را در نظر بگیرید و ویژگی‌های لگ 1 و لگ 2 را بسازید:

lag_2 lag_1 target
10 12 14
12 14 13
14 13 15

حالا یک مسئله‌ی رگرسیون استاندارد دارید. هر مدل یادگیری ماشینی (رگرسیون خطی، جنگل تصادفی، گرادیان بوستینگ) می‌تواند مقدار هدف را از روی لگ‌ها پیش‌بینی کند.

ویژگی‌های دیگری که می‌توانید مهندسی کنید:

  • آماره‌های متحرک: میانگین، انحراف معیار، کمینه و بیشینه‌ی k داده‌ی اخیر
  • ویژگی‌های تقویمی: روز هفته، ماه، تعطیل بودن، آخر هفته بودن
  • مقادیر تفاضلی: تغییر نسبت به گام قبل
  • آماره‌های گسترش‌پذیر (Expanding statistics): میانگین تجمعی، مجموع تجمعی
  • ویژگی‌های نسبتی: مقدار فعلی تقسیم بر میانگین متحرک (میزان فاصله از میانگین اخیر)
  • ویژگی‌های تعاملی: lag_1 * day_of_week (بررسی اثر روزهای هفته بر تکانه یا momentum)

چند تا لگ بسازیم؟ از تابع خودهمبستگی استفاده کنید. اگر ACF تا لگ 10 معنادار است، حداقل 10 لگ به کار ببرید. اگر فصلی‌بودن هفتگی دارید، لگ 7 (و احتمالاً 14) را هم اضافه کنید. لگ‌های بیشتر، تاریخچه‌ی بیشتری به مدل می‌دهند اما تعداد ویژگی‌ها را برای برازش بالا می‌برند و خطر بیش‌برازش (overfitting) را بیشتر می‌کنند.

دام تراز نبودن متغیر هدف: هنگام ساخت ویژگی‌های تأخیری، مقدار هدف باید مقدار در زمان tt باشد و تمام ویژگی‌ها باید حتماً مقادیر در زمان t−1t-1 یا قبل‌تر باشند. اگر تصادفاً مقدار زمان tt را به عنوان ویژگی وارد کنید، یک پیش‌بینی‌کننده‌ی کامل اما مدلی کاملاً بی‌مصرف ساخته‌اید. این رایج‌ترین باگ در مهندسی ویژگی‌های سری زمانی است.

اعتبارسنجی پیش‌رونده (Walk-Forward Validation)

این بخش مهم‌ترین مفهوم این درس است. اعتبارسنجی متقاطع k-fold استاندارد نمونه‌ها را به صورت تصادفی به آموزش و آزمون اختصاص می‌دهد. در سری زمانی، این کار باعث نشت اطلاعات آینده به گذشته می‌شود.

اعتبارسنجی پیش‌رو (درست)تقسیم تصادفی (نادرست)ژانویهمارسفوریهمهآوریلآموزش: ژانویه-مارسآزمون: آوریلآموزش: ژانویه-آوریلآزمون: مهآموزش: ژانویه-مهآزمون: ژوئن

اعتبارسنجی پیش‌رونده:

  1. مدل را با داده‌های تا زمان tt آموزش دهید
  2. مقدار زمان t+1t+1 را پیش‌بینی کنید (یا بازه‌ی t+1t+1 تا t+kt+k برای پیش‌بینی‌های چندگامی)
  3. پنجره را به سمت جلو بلغزانید
  4. مراحل را تکرار کنید

هر فولد آزمون فقط شامل داده‌هایی است که از نظر زمانی بعد از تمام داده‌های آموزش قرار گرفته‌اند؛ بدون هیچ نشت از آینده. این روش تخمینی واقعی از نحوه‌ی عملکرد مدل پس از دیپلوی به شما می‌دهد.

در حالت پنجره‌ی گسترش‌پذیر (expanding window)، از تمام داده‌های گذشته برای آموزش استفاده می‌شود (پنجره رشد می‌کند). در حالت پنجره‌ی لغزان (sliding window)، از یک پنجره‌ی آموزش با اندازه‌ی ثابت استفاده می‌شود (پنجره می‌لغزد). وقتی معتقدید داده‌های قدیمی‌تر هنوز معتبرند از پنجره‌ی گسترش‌پذیر استفاده کنید؛ و زمانی که شرایط دنیا عوض شده و داده‌های قدیمی آسیب می‌زنند، پنجره‌ی لغزان را به کار ببرید.

درک شهودی مدل ARIMA

مدل ARIMA مدل کلاسیک سری زمانی است و سه مؤلفه دارد:

  • AR (خودهمبسته - Autoregressive): پیش‌بینی بر اساس مقادیر گذشته. مدل AR(p) از pp مقدار قبلی استفاده می‌کند.
  • I (یکپارچه - Integrated): تفاضل‌گیری برای رسیدن به مانایی. I(d) به معنی dd دور تفاضل‌گیری است.
  • MA (میانگین متحرک - Moving Average): پیش‌بینی بر اساس خطاهای پیش‌بینی گذشته. مدل MA(q) از qq خطای قبلی استفاده می‌کند.

مدل ARIMA(p, d, q) هر سه را با هم ترکیب می‌کند. مقادیر pp، dd و qq را بر اساس تحلیل نمودارهای ACF و PACF یا از طریق جست‌وجوی خودکار (auto-ARIMA) انتخاب می‌کنید.

در این درس ARIMA را از صفر پیاده‌سازی نمی‌کنیم؛ چون نیاز به بهینه‌سازی عددی دارد که فراتر از دامنه (scope) این درس است. نکته‌ی کلیدی درک نقش هر مؤلفه است تا بتوانید نتایج ARIMA را تفسیر کنید و بدانید چه زمانی باید سراغش بروید.

کدام روش برای چه کاری مناسب است؟

رویکرد بهترین کاربرد پشتیبانی از فصلی‌بودن پشتیبانی از ویژگی‌های بیرونی
ویژگی‌های تأخیری + یادگیری ماشین داده‌های جدولی با ویژگی‌های بیرونی فراوان با ویژگی‌های تقویمی بله
ARIMA تک‌سری تک‌متغیره، کوتاه‌مدت نوع SARIMA خیر (با ARIMAX به شکل محدود)
هموارسازی نمایی (Exponential smoothing) روند و فصلی‌بودن ساده بله (Holt-Winters) خیر
Prophet پیش‌بینی کسب‌وکار، تعطیلات بله (جملات فوریه) محدود
شبکه‌های عصبی (LSTM، ترنسفورمر) توالی‌های طولانی، سری‌های چندگانه یادگیری خودکار بله

برای بیشتر مسائل عملی، ترکیب ویژگی‌های تأخیری و گرادیان بوستینگ قوی‌ترین نقطه‌ی شروع است. این رویکرد ویژگی‌های بیرونی را به‌طور طبیعی دریافت می‌کند، نیازی به مانایی ندارد و دیباگ کردنش ساده است.

افق‌ها و استراتژی‌های پیش‌بینی

پیش‌بینی تک‌گامی یک گام زمانی بعد را تخمین می‌زند. پیش‌بینی چندگامی چند گام را پیش‌بینی می‌کند. سه استراتژی برای این کار وجود دارد:

بازگشتی (Recursive یا تکرارشونده): یک گام به جلو پیش‌بینی کنید و از پیش‌بینی به عنوان ورودی گام بعد بهره ببرید. پیاده‌سازی‌اش ساده است اما خطاها جمع می‌شوند؛ هر پیش‌بینی بر پایه‌ی پیش‌بینی قبلی شکل می‌گیرد و در نتیجه اشتباهات تشدید می‌شوند.

مستقیم (Direct): برای هر افق یک مدل جداگانه آموزش دهید. مدل 1 مقدار t+1t+1 را پیش‌بینی می‌کند و مدل 5 مقدار t+5t+5 را. در این روش انباشت خطا رخ نمی‌دهد، اما هر مدل نمونه‌های آموزشی کمتری دارد و اطلاعات بین مدل‌ها به اشتراک گذاشته نمی‌شود.

چندخروجی (Multi-output): یک مدل واحد آموزش دهید که تمام افق‌ها را هم‌زمان خروجی دهد. اطلاعات در طول افق‌ها به اشتراک گذاشته می‌شود، اما به مدلی نیاز دارید که از خروجی‌های چندگانه پشتیبانی کند (یا یک تابع زیان (loss) سفارشی).

برای بیشتر مسائل عملی، در افق‌های کوتاه (1 تا 5 گام) با روش بازگشتی شروع کنید و برای افق‌های طولانی‌تر سراغ روش مستقیم بروید.

اشتباهات رایج در سری زمانی

اشتباه علت وقوع روش رفع
تقسیم تصادفی به آموزش/آزمون عادت از یادگیری ماشین استاندارد استفاده از اعتبارسنجی پیش‌رونده یا تقسیم زمانی
استفاده از ویژگی‌های آینده ورود تصادفی ویژگی مربوط به زمان tt بررسی تک‌تک ویژگی‌ها از نظر تراز زمانی
بیش‌برازش روی فصلی‌بودن مدل الگوهای تقویمی را حفظ می‌کند کنار گذاشتن یک چرخه‌ی فصلی کامل در مجموعه‌ی آزمون
نادیده گرفتن تغییر مقیاس درآمد دو برابر می‌شود اما الگوها می‌مانند مدل‌سازی تغییرات درصدی به‌جای مقادیر مطلق
ویژگی‌های تأخیری بیش از حد تفکر اینکه «تاریخچه‌ی بیشتر همیشه بهتر است» استفاده از ACF برای تعیین لگ‌های مرتبط
تفاضل‌گیری نکردن تصور اینکه «خود مدل موضوع را می‌فهمد» مدل‌های درختی با روند کنار می‌آیند؛ مدل‌های خطی به مانایی نیاز دارند
تجزیه سری زمانیجداسازی لایه‌ها از یکدیگر
TIME SERIES DECOMPOSITIONThe observed series is a sum of three simpler signals: a slow trend, a repeating seasonal cycle, and what is left over, the residual. Decomposition separates them so each can be handled on its own terms: detrend and deseasonalize to reach stationarity, then model the residual. The sweep line reminds you the parts line up point-for-point in time.سری مشاهده‌شدهروند=فصلی بودن+پسماند+
سری مشاهده‌شده مجموعی از سه سیگنال ساده‌تر است: یک روند کُند، یک چرخه فصلی تکرارشونده و آنچه باقی می‌ماند یعنی پسماند. تجزیه، این بخش‌ها را از هم تفکیک می‌کند تا بتوان با هرکدام بر اساس ماهیت خودش برخورد کرد: حذف روند و حذف اثر فصلی برای رسیدن به مانایی، و سپس مدل‌سازی پسماند. خط پویش به یاد می‌آورد که این بخش‌ها نقطه به نقطه در زمان بر هم منطبق هستند.

پیاده‌سازی

کدهای فایل code/time_series.py ساختارهای پایه‌ای را از صفر پیاده‌سازی می‌کنند.

سازنده‌ی ویژگی‌های تأخیری

def make_lag_features(series, n_lags):
    n = len(series)
    X = np.full((n, n_lags), np.nan)
    for lag in range(1, n_lags + 1):
        X[lag:, lag - 1] = series[:-lag]
    valid = ~np.isnan(X).any(axis=1)
    return X[valid], series[valid]

این کد سری یک‌بعدی را به ماتریس ویژگی‌ها تبدیل می‌کند؛ طوری که هر سطر شامل n_lags مقدار اخیر به عنوان ویژگی و مقدار فعلی به عنوان هدف است.

اعتبارسنجی متقاطع پیش‌رونده

def walk_forward_split(n_samples, n_splits=5, min_train=50):
    assert min_train < n_samples, "min_train must be less than n_samples"
    step = max(1, (n_samples - min_train) // n_splits)
    for i in range(n_splits):
        train_end = min_train + i * step
        test_end = min(train_end + step, n_samples)
        if train_end >= n_samples:
            break
        yield slice(0, train_end), slice(train_end, test_end)

هر تقسیم تضمین می‌کند داده‌های آموزش دقیقاً پیش از داده‌های آزمون قرار می‌گیرند. پنجره‌ی آموزش با هر فولد بزرگ‌تر می‌شود.

مدل خودهمبسته‌ی ساده (AR)

یک مدل AR خالص همان رگرسیون خطی روی ویژگی‌های تأخیری است:

class SimpleAR:
    def __init__(self, n_lags=5):
        self.n_lags = n_lags
        self.weights = None
        self.bias = None

    def fit(self, series):
        X, y = make_lag_features(series, self.n_lags)
        # حل از طریق معادلات نرمال
        X_b = np.column_stack([np.ones(len(X)), X])
        theta = np.linalg.lstsq(X_b, y, rcond=None)[0]
        self.bias = theta[0]
        self.weights = theta[1:]
        return self

این ساختار از نظر مفهومی همان رگرسیون خطی درس 02 است، با این تفاوت که روی نسخه‌های تأخیریافته‌ی زمانی از همان متغیر اعمال می‌شود.

بررسی مانایی

کد آماره‌های متحرک را محاسبه می‌کند تا وضعیت مانایی را به صورت بصری و عددی ارزیابی کند:

def check_stationarity(series, window=50):
    rolling_mean = np.array([
        series[max(0, i - window):i].mean()
        for i in range(1, len(series) + 1)
    ])
    rolling_std = np.array([
        series[max(0, i - window):i].std()
        for i in range(1, len(series) + 1)
    ])
    return rolling_mean, rolling_std

اگر میانگین متحرک جابه‌جا شود یا انحراف معیار متحرک تغییر کند، سری نامانا است. در این حالت تفاضل‌گیری کنید و دوباره بررسی را انجام دهید.

کد همچنین مانایی را با مقایسه‌ی نیمه‌ی اول و نیمه‌ی دوم سری می‌سنجد. اگر میانگین‌ها به اندازه‌ی بیش از نصف انحراف معیار تفاوت داشته باشند یا نسبت واریانس از 2 برابر فراتر رود، سری به عنوان نامانا علامت‌گذاری می‌شود.

خودهمبستگی

def autocorrelation(series, max_lag=20):
    n = len(series)
    mean = series.mean()
    var = series.var()
    acf = np.zeros(max_lag + 1)
    for k in range(max_lag + 1):
        cov = np.mean((series[:n-k] - mean) * (series[k:] - mean))
        acf[k] = cov / var if var > 0 else 0
    return acf

استفاده در عمل

در scikit-learn می‌توانید ویژگی‌های تأخیری را مستقیماً به هر رگرسیون‌کننده‌ای تحویل دهید:

from sklearn.linear_model import Ridge
from sklearn.ensemble import GradientBoostingRegressor

X, y = make_lag_features(series, n_lags=10)

for train_idx, test_idx in walk_forward_split(len(X)):
    model = Ridge(alpha=1.0)
    model.fit(X[train_idx], y[train_idx])
    predictions = model.predict(X[test_idx])

برای ARIMA از statsmodels استفاده کنید:

from statsmodels.tsa.arima.model import ARIMA

model = ARIMA(train_series, order=(5, 1, 2))
fitted = model.fit()
forecast = fitted.forecast(steps=30)

کد درون time_series.py هر دو رویکرد را نشان می‌دهد و آن‌ها را با استفاده از اعتبارسنجی پیش‌رونده مقایسه می‌کند.

ابزار TimeSeriesSplit در sklearn

کتابخانه‌ی sklearn کلاسی به نام TimeSeriesSplit دارد که اعتبارسنجی پیش‌رونده را پیاده‌سازی می‌کند:

from sklearn.model_selection import TimeSeriesSplit

tscv = TimeSeriesSplit(n_splits=5)
for train_index, test_index in tscv.split(X):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    model.fit(X_train, y_train)
    score = model.score(X_test, y_test)

این ابزار معادل تابع walk_forward_split ما است، اما در چارچوب اعتبارسنجی متقاطع sklearn ادغام شده است. می‌توانید آن را با cross_val_score به کار ببرید:

from sklearn.model_selection import cross_val_score

scores = cross_val_score(model, X, y, cv=TimeSeriesSplit(n_splits=5))
print(f"Mean score: {scores.mean():.4f} +/- {scores.std():.4f}")

معیارهای ارزیابی

پیش‌بینی سری‌های زمانی از معیارهای رگرسیون استفاده می‌کند، اما با توجه به بافت زمانی داده‌ها:

  • MAE (میانگین قدر مطلق خطا): میانگین ∣ytrue−ypred∣\lvert y_{\text{true}} - y_{\text{pred}} \rvert. تفسیر آن بر حسب واحدهای اصلی راحت است: «پیش‌بینی‌ها به‌طور میانگین 3.2 درجه خطا دارند.»
  • RMSE (جذر میانگین مربعات خطا): جذر میانگین مربعات خطا. خطاهای بزرگ را بسیار بیشتر از MAE جریمه می‌کند. وقتی چند خطای بزرگ بدتر از خطاهای کوچک متعدد هستند از آن استفاده کنید.
  • MAPE (میانگین درصد قدر مطلق خطا): میانگین 100 * |error / true_value|. مستقل از مقیاس است و برای مقایسه بین سری‌های مختلف به کار می‌رود؛ اما اگر مقادیر واقعی صفر باشند تعریف‌نشده است.
  • مقایسه با خط مبنای ساده (Naive baseline): همیشه مدل را با خطوط مبنای ساده مقایسه کنید. خط مبنای ساده‌ی فصلی، مقدار یک دوره قبل (دیروز، هفته‌ی پیش) را به عنوان پیش‌بینی در نظر می‌گیرد. اگر مدل نتواند این خط مبنا را شکست دهد، مشکلی در کار است.

ویژگی‌های متحرک (Rolling Features)

کد نشان می‌دهد که چطور می‌توان آماره‌های متحرک (میانگین، انحراف معیار، کمینه و بیشینه در پنجره‌های 7 و 14 روزه) را به ویژگی‌های تأخیری افزود. این موارد اطلاعاتی درباره‌ی روندها و نوسانات اخیر به مدل می‌دهند که ویژگی‌های تأخیری به‌تنهایی قادر به ثبت آن‌ها نیستند.

برای نمونه، بالا رفتن میانگین متحرک نشان‌دهنده‌ی روند صعودی است. افزایش انحراف معیار متحرک نوسان فزاینده را نشان می‌دهد. این‌ها الگوهایی هستند که مدل‌های مبتنی بر درخت یاد می‌گیرند اما مدل‌های خطی متوجه‌شان نمی‌شوند.

خروجی نهایی

این درس خروجی‌های زیر را تولید می‌کند:

  • outputs/prompt-time-series-advisor.md -- پرامپتی برای ساختاربندی مسائل سری زمانی
  • code/time_series.py -- ویژگی‌های تأخیری، اعتبارسنجی پیش‌رونده، مدل AR، و بررسی‌های مانایی

خطوط مبنایی که باید شکست دهید

قبل از ساخت هر مدلی، این خطوط مبنا را تعریف کنید:

  1. آخرین مقدار (ماندگاری یا persistence): پیش‌بینی کنید که فردا مثل امروز خواهد بود. شکست دادن این روش در بسیاری از سری‌ها به‌طرز عجیبی دشوار است.
  2. ساده‌ی فصلی (Seasonal naive): پیش‌بینی کنید که امروز مثل روز مشابه در هفته‌ی قبل (یا سال قبل) خواهد بود. مدلی که این معیار را شکست ندهد، الگوی مفیدی فراتر از فصلی‌بودن یاد نگرفته است.
  3. میانگین متحرک: میانگین k مقدار اخیر را پیش‌بینی کنید. نویز را هموار می‌کند، اما تغییرات ناگهانی را متوجه نمی‌شود.

اگر مدل پرزرق‌وبرق یادگیری ماشین شما در برابر خط مبنای فصلی ساده ببازد، باگی در کار است؛ معمولاً نشت اطلاعات آینده در ویژگی‌ها، روش ارزیابی اشتباه، یا کاملاً تصادفی و غیرقابل‌پیش‌بینی بودن سری زمانی.

نکات کاربردی

  1. اول رسم کنید. قبل از هر مدل‌سازی، نمودار سری خام را بکشید. دنبال روند، فصلی‌بودن، داده‌های پرت و شکست‌های ساختاری (تغییر ناگهانی رفتار) بگردید. یک بازرسی چشمی 30 ثانیه‌ای اغلب اطلاعات بیشتری نسبت به یک ساعت تحلیل خودکار به شما می‌دهد.

  2. اول تفاضل‌گیری، بعد مدل‌سازی. اگر سری روند واضحی دارد، قبل از ساخت ویژگی‌های تأخیری آن را تفاضل‌گیری کنید. مدل‌های مبتنی بر درخت از پس روندها برمی‌آیند، اما مدل‌های خطی بدون تعریف یک جمله‌ی صریح برای روند ناتوانند. به محض مانا شدن سری، تفاضل‌گیری را متوقف کنید؛ هر دور تفاضل‌گیری اضافی، نویز وارد داده می‌کند و اطلاعات سطح سری را دور می‌ریزد.

  3. حداقل یک چرخه‌ی فصلی کامل را کنار بگذارید. اگر فصلی‌بودن هفتگی دارید، مجموعه‌ی آزمون شما حداقل به یک هفته‌ی کامل نیاز دارد؛ اگر ماهانه است، حداقل یک ماه کامل. در غیر این صورت نمی‌توانید بررسی کنید که مدل الگوی فصلی را یاد گرفته است یا خیر.

  4. پایش در محیط پروداکشن. مدل‌های سری زمانی با تغییر شرایط دنیا در طول زمان افت می‌کنند. خطاهای پیش‌بینی را در پنجره‌های متحرک زیر نظر بگیرید. وقتی خطاها شروع به افزایش کردند، مدل را با داده‌های جدید بازآموزی کنید.

  5. مراقب تغییر رژیم (Regime changes) باشید. مدلی که با داده‌های قبل از کرونا آموزش دیده، رفتار پس از کرونا را پیش‌بینی نمی‌کند. نقاط عطف و تغییرات رژیم شناخته‌شده را به عنوان ویژگی وارد مدل کنید، یا سراغ پنجره‌ی لغزان بروید تا داده‌های قدیمی فراموش شوند.

  6. تبدیل لگاریتمی برای سری‌های چوله. درآمد، قیمت و داده‌های شمارشی معمولاً چولگی راست دارند. لگاریتم گرفتن واریانس را تثبیت می‌کند و الگوهای ضرب‌شونده را جمع‌شونده می‌سازد که مدل‌های خطی بهتر از پس آن برمی‌آیند. پیش‌بینی را در فضای لگاریتمی انجام دهید، سپس با معکوس نمایی آن را به واحدهای اصلی بازگردانید.

تمرین‌ها

  1. آزمایش مانایی. سری با روند خطی بسازید. مانایی آن را با آماره‌های متحرک بسنجید. یک بار تفاضل‌گیری کنید و دوباره بررسی را انجام دهید. برای یک روند درجه‌دو به چند بار تفاضل‌گیری نیاز است؟

  2. انتخاب لگ. مقدار ACF را برای یک سری فصلی (با دوره‌ی 7 روزه) محاسبه کنید. کدام لگ‌ها بیشترین خودهمبستگی را دارند؟ ویژگی‌های تأخیری را فقط بر اساس همان لگ‌ها بسازید (نه لگ‌های متوالی). آیا دقت در مقایسه با استفاده از لگ‌های 1 تا 7 بهبود می‌یابد؟

  3. اعتبارسنجی پیش‌رونده در برابر تقسیم تصادفی. یک رگرسیون ریج (Ridge) را روی ویژگی‌های تأخیری آموزش دهید. مدل را با تقسیم تصادفی 80/20 و اعتبارسنجی پیش‌رونده ارزیابی کنید. تقسیم تصادفی چقدر عملکرد را بیش از حد خوب برآورد می‌کند؟

  4. مهندسی ویژگی. میانگین متحرک (پنجره‌ی 7)، انحراف معیار متحرک (پنجره‌ی 7) و ویژگی‌های روز هفته را به ویژگی‌های تأخیری اضافه کنید. دقت را در حالت با و بدون این ویژگی‌ها با اعتبارسنجی پیش‌رونده مقایسه کنید.

  5. پیش‌بینی چندگامی. مدل AR را طوری تغییر دهید که به‌جای 1 گام، 5 گام آینده را پیش‌بینی کند. دو استراتژی را مقایسه کنید: (الف) یک گام را پیش‌بینی کرده و از پیش‌بینی به عنوان ورودی گام بعد استفاده کنید (بازگشتی)، و (ب) برای هر افق زمانی مدل جداگانه‌ای آموزش دهید (مستقیم). کدام روش دقت بیشتری دارد؟

اصطلاحات کلیدی

اصطلاح در گفت‌وگوها معنای واقعی
مانایی (Stationarity) «آمار داده‌ها در طول زمان عوض نمی‌شود» سری زمانی که میانگین، واریانس و ساختار خودهمبستگی آن در طول زمان ثابت باشد
تفاضل‌گیری (Differencing) «کم کردن مقادیر پشت سر هم» محاسبه‌ی y[t]−y[t−1]y[t] - y[t-1] برای حذف روند و رسیدن به مانایی
خودهمبستگی (ACF) «همبستگی سری با خودش» همبستگی میان یک سری زمانی و نسخه‌ی تأخیریافته‌ی آن، به عنوان تابعی از لگ
خودهمبستگی جزئی (PACF) «فقط همبستگی مستقیم» خودهمبستگی در لگ kk پس از حذف اثر همه‌ی لگ‌های کوتاه‌تر
ویژگی‌های تأخیری (Lag features) «مقادیر گذشته به عنوان ورودی» استفاده از y[t−1],y[t−2],…,y[t−k]y[t-1], y[t-2], \ldots, y[t-k] به عنوان ویژگی برای پیش‌بینی y[t]y[t]
اعتبارسنجی پیش‌رونده (Walk-forward validation) «اعتبارسنجی متقاطع با حفظ تقدم زمان» ارزیابی که در آن داده‌های آموزش همیشه از نظر زمانی قبل از داده‌های آزمون قرار دارند
ARIMA «مدل کلاسیک سری زمانی» AutoRegressive Integrated Moving Average: ترکیب مقادیر گذشته (AR)، تفاضل‌گیری (I) و خطاهای گذشته (MA)
فصلی‌بودن (Seasonality) «الگوهای تکراری تقویم» چرخه‌های منظم و پیش‌بینی‌پذیر در سری زمانی که به دوره‌های تقویمی (روزانه، هفتگی، سالانه) گره خورده‌اند
روند (Trend) «جهت بلندمدت» افزایش یا کاهش پایدار در سطح سری در طول زمان
پنجره‌ی گسترش‌پذیر (Expanding window) «استفاده از تمام تاریخچه» اعتبارسنجی پیش‌رونده که در آن مجموعه‌ی آموزش با هر فولد رشد می‌کند
پنجره‌ی لغزان (Sliding window) «تاریخچه‌ی با اندازه‌ی ثابت» اعتبارسنجی پیش‌رونده که در آن مجموعه‌ی آموزش یک پنجره با طول ثابت است و به جلو می‌لغزد

مطالعه‌ی بیشتر

سؤالات متداول

چرا نباید از تقسیم تصادفی (Random Train/Test Split) در سری زمانی استفاده کرد؟

چون در سری زمانی داده‌ها وابسته به ترتیب تاریخ هستند؛ تقسیم تصادفی باعث نشت اطلاعات آینده به داده‌های آموزش می‌شود و مدل خطایی غیرواقعی و کاذب نشان می‌دهد که در پروداکشن شکست می‌خورد.

ویژگی تأخیری (Lag Feature) چیست و چه کاربردی دارد؟

ویژگی تأخیری استفاده از مقادیر گام‌های زمانی گذشته به عنوان ستون‌های ورودی مدل است که سری زمانی تک‌بعدی را به یک مسئله‌ی یادگیری بانظارت و رگرسیون تبدیل می‌کند.

مانایی (Stationarity) به چه معناست و چطور ایجاد می‌شود؟

مانایی یعنی میانگین، واریانس و خودهمبستگی داده‌ها در طول زمان ثابت بماند. معمولاً با روش تفاضل‌گیری (کم کردن مقدار هر گام از گام قبل) می‌توان روندهای داده را حذف و سری را مانا کرد.

اعتبارسنجی پیش‌رونده (Walk-Forward Validation) چگونه کار می‌کند؟

در این روش، داده‌های آموزش همیشه از نظر زمانی قبل از داده‌های آزمون قرار دارند و با لغزش پنجره به جلو، مدل مرحله به مرحله در طول محور زمان تست می‌شود تا هیچ نشت اطلاعاتی از آینده رخ ندهد.

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.