Image

Прогнозирование временных рядов стало проще (часть 3.1): разложение STL

Разложение STL превосходно работает, когда сезонные закономерности со временем меняются.

Делиться

7d755dfbc785caa7b34166d043078208

В первых двух частях этой серии мы исследовали тренд, сезонность и остаточные явления на примере данных о температуре. Мы начали с выявления закономерностей в данных с помощью метода season_decompose в Python. Затем мы составили наши первые прогнозы температуры, используя стандартные базовые модели, такие как сезонная наивная модель.

Далее мы пошли глубже и узнали, как season_decompose на самом деле вычисляет тренд, сезонность и остаточные компоненты.

Мы извлекли эти фрагменты, чтобы построить базовую модель на основе декомпозиции, а затем экспериментировали с пользовательскими базовыми показателями, адаптированными к нашим данным.

Наконец, мы оценили каждую модель с помощью средней абсолютной процентной ошибки (MAPE), чтобы увидеть, насколько эффективны наши подходы.

В первых двух частях мы работали с данными о температуре — относительно простым набором данных, в котором тенденция и сезонность были очевидны, а season_decompose хорошо справлялся с фиксацией этих закономерностей.

Однако во многих реальных наборах данных всё не так однозначно. Тенденции и сезонные закономерности могут меняться или становиться запутанными, и в таких случаях season_decompose может не так эффективно отражать базовую структуру.

Здесь мы обратимся к более продвинутому методу разложения, чтобы лучше понять данные: STL — сезонно-трендовая разложение с использованием LOESS.

LOESS означает локально оцененное сглаживание диаграмм рассеяния .

Чтобы лучше понять это на практике, мы воспользуемся набором данных о розничных продажах в универмагах из FRED (Федеральная резервная система экономических данных).

Вот как выглядят данные:

6bf7d838904cfb48eb8587684219a787

Набор данных, с которым мы работаем, отслеживает ежемесячные розничные продажи в универмагах США и поступает из надежного источника FRED (Федеральная резервная система экономических данных).

В нем всего два столбца:

  • Дата_наблюдения – начало каждого месяца
  • Retail_Sales – общий объем продаж за этот месяц, в миллионах долларов.

Временной ряд охватывает период с января 1992 года по март 2025 года , что дает нам для изучения данные о продажах за более чем 30 лет.

Примечание: несмотря на то, что каждая дата отмечает начало месяца (например, 01.01.1992), объем продаж представляет собой общий объем продаж за весь месяц.

Но прежде чем перейти к STL, мы запустим классический season_decompose на нашем наборе данных и посмотрим, что он нам покажет.

Код:

import pandas as pd import matplotlib.pyplot as plt from statsmodels.tsa.seasonal import season_decompose # Загрузка набора данных df = pd.read_csv(«C:/RSDSELDN.csv», parse_dates=['Observation_Date'], dayfirst=True) # Установка столбца даты в качестве индекса df.set_index('Observation_Date', inplace=True) # Установка ежемесячной частоты df = df.asfreq('MS') # MS = Начало месяца # Извлечение ряда series = df['Retail_Sales'] # Применение классической сезонной декомпозиции result = season_decompose(series, model='additive', period=12) # График с пользовательскими цветами fig, axs = plt.subplots(4, 1, figsize=(12, 8), sharex=True) axs[0].plot(result.observed, color='olive') axs[0].set_title('Наблюдаемый') axs[1].plot(result.trend, color='darkslateblue') axs[1].set_title('Тенденция') axs[2].plot(result.seasonal, color='darkcyan') axs[2].set_title('Сезонный') axs[3].plot(result.resid, color='peru') axs[3].set_title('Остаток') plt.suptitle('Классическая сезонная декомпозиция (аддитивная)', fontsize=16) plt.tight_layout() plt.show()

Сюжет:

6b027f8cbacc77a71961a2b7d5e18f58

Во второй части мы рассмотрели, как season_decompose вычисляет трендовые и сезонные компоненты в предположении фиксированной повторяющейся сезонной структуры.

Однако реальные данные не всегда следуют фиксированной схеме. Тенденции могут меняться постепенно, а сезонные колебания могут меняться из года в год. Именно поэтому нам нужен более адаптивный подход, и декомпозиция STL предлагает именно это.

Мы применим разложение STL к данным, чтобы увидеть, как они справляются с меняющимися тенденциями и сезонностью.

import pandas as pd import matplotlib.pyplot as plt from statsmodels.tsa.seasonal import STL # Загрузка набора данных df = pd.read_csv(«C:/RSDSELDN.csv», parse_dates=['Observation_Date'], dayfirst=True) df.set_index('Observation_Date', inplace=True) df = df.asfreq('MS') # Обеспечение ежемесячной частоты # Извлечение временного ряда series = df['Retail_Sales'] # Применение разложения STL stl = STL(series, season=13) result = stl.fit() # Построение графика и сохранение компонентов STL fig, axs = plt.subplots(4, 1, figsize=(10, 8), sharex=True) axs[0].plot(result.observed, color='sienna') axs[0].set_title('Наблюдается') axs[1].plot(result.trend, color='goldenrod') axs[1].set_title('Тенденция') axs[2].plot(result.seasonal, color='darkslategrey') axs[2].set_title('Сезонный') axs[3].plot(result.resid, color='rebeccapurple') axs[3].set_title('Остаток') plt.suptitle('STL-разложение розничных продаж', fontsize=16) plt.tight_layout() plt.show()

Сюжет:

fd29c063dc1ae4feb2a81e63108b4f96

После завершения этого шага и понимания того, что делает STL, мы углубимся в то, как он выявляет тенденции и сезонные закономерности за кулисами.

Чтобы лучше понять, как работает разложение STL, мы рассмотрим выборку из нашего набора данных, охватывающую период с января 2010 года по декабрь 2023 года.

1988e629db58590a975e7e9f943da355

Чтобы понять, как разложение STL работает с этими данными, нам сначала нужны грубые оценки тренда и сезонности.

Поскольку STL — это метод, основанный на сглаживании, он требует первоначального представления о том, что именно следует сглаживать, например, где находится тренд и как ведут себя сезонные закономерности.

Начнем с визуализации ряда розничных продаж (январь 2010 г. – декабрь 2023 г.) и применим процедуру STL Python для извлечения его трендовых, сезонных и остаточных частей.

Код:

import pandas as pd import matplotlib.pyplot as plt from statsmodels.tsa.seasonal import STL # Загрузка набора данных df = pd.read_csv(«C:/STL sample data.csv», parse_dates=['Observation_Date'], dayfirst=True) df.set_index('Observation_Date', inplace=True) df = df.asfreq('MS') # Обеспечение ежемесячной частоты # Извлечение временного ряда series = df['Retail_Sales'] # Применение разложения STL stl = STL(series, season=13) result = stl.fit() # Построение графика и сохранение компонентов STL fig, axs = plt.subplots(4, 1, figsize=(10, 8), sharex=True) axs[0].plot(result.observed, color='sienna') axs[0].set_title('Наблюдаемое') axs[1].plot(result.trend, color='goldenrod') axs[1].set_title('Тенденция') axs[2].plot(result.seasonal, color='darkslategrey') axs[2].set_title('Сезонный') axs[3].plot(result.resid, color='rebeccapurple') axs[3].set_title('Остаток') plt.suptitle('STL-разложение розничных продаж (2010-2023)', fontsize=16) plt.tight_layout() plt.show()

Сюжет:

ddc030dac8b62c69234d2c12a20900a6

Чтобы понять, как STL выводит свои компоненты, мы сначала оцениваем долгосрочную тенденцию данных, используя центрированное скользящее среднее.

Мы воспользуемся примером одного месяца, чтобы продемонстрировать, как рассчитать центрированную скользящую среднюю.

Мы рассчитаем центрированную скользящую среднюю за июль 2010 года .

fbf95429242244b6c3757ce526d3c5d1

Поскольку наши данные помесячные, естественный цикл охватывает двенадцать точек, что является чётным числом. Усреднение периода с января по декабрь 2010 года даёт значение, которое находится посередине между июнем и июлем.

Чтобы скорректировать это, мы формируем второе окно с февраля 2010 года по январь 2011 года, двенадцатимесячное среднее значение которого находится посередине между июлем и августом.

Затем мы вычисляем простое среднее значение каждого окна и усредняем эти два результата.

В первом окне июль — седьмой из двенадцати пунктов, поэтому среднее значение приходится на период между шестым и седьмым месяцами.

Во втором окне июль является шестым из двенадцати пунктов, поэтому его среднее значение также попадает между шестым и седьмым месяцами, но смещено вперед.

Усреднение обеих оценок возвращает результат к июлю 2010 года, давая истинно центрированное скользящее среднее значение за этот месяц.

90c41fcec2a470a4b30e1ba92fa242e1
68971a36a25666455a750b5d0689154f

Вот как мы вычисляем начальный тренд, используя центрированную скользящую среднюю.

В самом начале и конце нашего ряда у нас просто нет шести месяцев с обеих сторон для усреднения, поэтому нет «естественной» центрированной скользящей средней за январь-июнь 2010 года или июль-декабрь 2023 года.

Вместо того чтобы отбрасывать эти точки, мы переносим первое действительное значение за июль 2010 года назад, чтобы заполнить период январь–июнь, и переносим наше последнее действительное значение за декабрь 2023 года вперед, чтобы заполнить период июль–декабрь 2023 года.

Таким образом, каждый месяц будет иметь базовую тенденцию, прежде чем мы перейдем к уточнениям LOESS.

Далее мы будем использовать Python для вычисления первоначального тренда для каждого месяца.

Код:

import pandas as pd # Загрузка и подготовка данных df = pd.read_csv(«C:/STL sample data for part 3.csv», parse_dates=[«Observation_Date»], dayfirst=True, index_col=»Observation_Date») df = df.asfreq(«MS») # обеспечение непрерывного ежемесячного индекса # Извлечение ряда sales = df[«Retail_Sales»] # Вычисление двух 12-месячных скользящих средних n = 12 ma1 = sales.rolling(window=n, center=False).mean().shift(-n//2 + 1) ma2 = sales.rolling(window=n, center=False).mean().shift(-n//2) # Центрирование их путем усреднения T0 = (ma1 + ma2) / 2 # Заполнение краев так, чтобы каждый месяц имел значение T0 = T0.fillna(method=»bfill»).fillna(method=»ffill») # Присоединить к DataFrame df[«Initial_Trend»] = T0

Стол:

4568afc55bb2a5df6a33f2cec8adb4e3

Мы извлекли начальный тренд с помощью центрированной скользящей средней, давайте посмотрим, как это выглядит на самом деле.

Мы отобразим ее на графике вместе с исходным временным рядом и окончательной линией тренда STL, чтобы сравнить, как каждая из них отражает общее движение данных.

Сюжет:

00db072da4d46738920c9cf8a7b591b6

Глядя на график, мы видим, что линия тренда от скользящей средней практически совпадает с трендом STL на протяжении большей части лет.

Однако в январе-феврале 2020 года скользящая средняя линия резко упала. Это падение было вызвано внезапным влиянием COVID на продажи.

STL справляется с этим лучше: он не рассматривает это как долгосрочное изменение тренда, а вместо этого отмечает это как остаточное.

Это связано с тем, что STL рассматривает это как разовое неожиданное событие, а не повторяющуюся сезонную закономерность или изменение общей тенденции.

Чтобы понять, как STL это делает и как он обрабатывает меняющуюся сезонность, давайте продолжим развивать наше понимание шаг за шагом.

Теперь у нас есть начальный тренд с использованием скользящих средних, поэтому давайте перейдем к следующему шагу в процессе STL.

Источник: towardsdatascience.com

✅ Найденные теги: новости, Прогнозирование
Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

Фото сгенерированных лиц: исследование показывает, что люди не могут отличить настоящие лица от сгенерированных
Нейросети построили капитализм за трое суток: 100 агентов Claude заперли…
Скетч: цифровой осьминог и виртуальный мир внутри компьютера с человечком.
Сцена с жестами пальцами, где один жест символизирует "VPN", а другой "KHP".
‼️Paramount купила Warner Bros. Discovery — сумма сделки составила безумные…
Скриншот репозитория GitHub "Claude Scientific Skills" AI для научных исследований.
Структура эффективного запроса Claude с элементами задачи, контекста и референса.
Эскиз и готовая веб-страница платформы для AI-дизайна в современном темном режиме.
ideipro logotyp
Image Not Found
Звёздное небо с галактиками и туманностями, космос, Вселенная, астрофотография.

Система оповещения обсерватории Рубина отправила 800 000 сигналов в первую ночь наблюдений.

Астрономы будут получать оповещения о небесных явлениях в течение нескольких минут после их обнаружения. Теренс О'Брайен, редактор раздела «Выходные». Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной…

Мар 2, 2026
Женщина с длинными тёмными волосами в синем свете, нейтральный фон.

Расследование в отношении 61-фунтовой машины, которая «пожирает» пластик и выплевывает кирпичи.

Обзор компактного пресса для мягкого пластика Clear Drop — и что будет дальше. Шон Холлистер, старший редактор Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной странице вашего…

Мар 2, 2026
Черный углеродное волокно с текстурой плетения, отражающий свет.

Материал будущего: как работает «бессмертный» композит

Учёные из Университета штата Северная Каролина представили композит нового поколения, способный самостоятельно восстанавливаться после серьёзных повреждений.  Речь идёт о модифицированном армированном волокном полимере (FRP), который не просто сохраняет прочность при малом весе, но и способен «залечивать» внутренние…

Мар 2, 2026
Круглый экран с изображением замка и горы, рядом электронная плата.

Круглый дисплей Waveshare для креативных проектов

Круглый 7-дюймовый сенсорный дисплей от Waveshare создан для разработчиков и дизайнеров, которым нужен нестандартный экран.  Это IPS-панель с разрешением 1 080×1 080 пикселей, поддержкой 10-точечного ёмкостного сенсора, оптической склейкой и защитным закалённым стеклом, выполненная в круглом форм-факторе.…

Мар 2, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых