← Назад к вопросам

Как анализировать временной ряд: тренд, сезонность, шум?

2.3 Middle🔥 171 комментариев
#Временные ряды

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Анализ временных рядов: компоненты и методы

Временной ряд (time series) — это последовательность наблюдений, упорядоченная по времени. Классический подход предполагает разложение ряда на три основные компоненты: тренд, сезонность и шум. Понимание этих компонент критично для прогнозирования и анализа.

Математическое представление

Y(t) = Trend(t) + Seasonality(t) + Noise(t)

Или в мультипликативной форме (когда компоненты зависят друг от друга):

Y(t) = Trend(t) * Seasonality(t) * Noise(t)

1. Тренд (Trend)

Тренд — это долгосрочное движение временного ряда вверх или вниз.

Визуализация и выявление тренда

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

# Сгенерировать данные с трендом
date_range = pd.date_range('2020-01-01', periods=365)
y = 10 + 0.1 * np.arange(365) + np.random.normal(0, 2, 365)
ts = pd.Series(y, index=date_range)

# Визуализировать
plt.figure(figsize=(12, 4))
plt.plot(ts.index, ts.values, label='Исходный ряд')
plt.title('Временной ряд с трендом')
plt.legend()
plt.show()

Методы выделения тренда

Метод скользящего среднего (Moving Average)

# Простое скользящее среднее
trend_ma = ts.rolling(window=30).mean()

plt.plot(ts.index, ts.values, label='Исходный ряд')
plt.plot(ts.index, trend_ma, label='Тренд (MA=30)', color='red')
plt.legend()
plt.show()

Метод экспоненциального сглаживания

from scipy.ndimage import uniform_filter1d

alpha = 0.3
trend_exp = ts.ewm(span=30, adjust=False).mean()

Полиномиальная регрессия

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

X = np.arange(len(ts)).reshape(-1, 1)
poly = PolynomialFeatures(degree=2)
X_poly = poly.fit_transform(X)
model = LinearRegression()
model.fit(X_poly, ts.values)
trend_poly = model.predict(X_poly)

2. Сезонность (Seasonality)

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

Выявление периода сезонности

Метод автокорреляции (ACF)

from statsmodels.graphics.tsaplots import plot_acf
from statsmodels.tsa.stattools import adfuller

fig, ax = plt.subplots(figsize=(12, 4))
plot_acf(ts.dropna(), lags=100, ax=ax)
plt.title('Автокорреляция (ACF)')
plt.show()

Анализ Фурье (FFT)

from scipy.fft import fft

fft_values = np.abs(fft(ts.dropna()))
frequencies = np.fft.fftfreq(len(ts))

top_freq_idx = np.argsort(fft_values)[-5:]
print(f'Периоды сезонности: {1 / frequencies[top_freq_idx]}')

Разложение (Decomposition)

from statsmodels.tsa.seasonal import seasonal_decompose

decomposition = seasonal_decompose(ts, model='additive', period=30)

trend = decomposition.trend
seasonal = decomposition.seasonal
residual = decomposition.resid

fig, axes = plt.subplots(4, 1, figsize=(12, 10))
axes[0].plot(ts)
axes[0].set_ylabel('Исходный ряд')
axes[1].plot(trend)
axes[1].set_ylabel('Тренд')
axes[2].plot(seasonal)
axes[2].set_ylabel('Сезонность')
axes[3].plot(residual)
axes[3].set_ylabel('Шум')
plt.tight_layout()
plt.show()

3. Шум (Noise)

Шум — это случайная компонента, которая остаётся после удаления тренда и сезонности.

Анализ шума

residuals = decomposition.resid.dropna()

from statsmodels.tsa.stattools import adfuller

adf_result = adfuller(residuals)
print(f'ADF статистика: {adf_result[0]}')
print(f'p-value: {adf_result[1]}')
if adf_result[1] < 0.05:
    print('Ряд стационарен')
else:
    print('Ряд нестационарен')

plt.hist(residuals, bins=30, edgecolor='black')
plt.title('Распределение шума')
plt.xlabel('Значение')
plt.ylabel('Частота')
plt.show()

Полный пример анализа

import pandas as pd
import numpy as np
from statsmodels.tsa.seasonal import seasonal_decompose
import matplotlib.pyplot as plt

df = pd.read_csv('stock_prices.csv', parse_dates=['date'], index_col='date')
ts = df['close']

decomposition = seasonal_decompose(ts, model='multiplicative', period=252)

trend = decomposition.trend
seasonal = decomposition.seasonal
residual = decomposition.resid

print(f'Тренд: минимум={trend.min():.2f}, максимум={trend.max():.2f}')
print(f'Сезонность: амплитуда={seasonal.max() - seasonal.min():.4f}')
print(f'Шум: std={residual.std():.4f}')

fig, axes = plt.subplots(4, 1, figsize=(14, 10))
axes[0].plot(ts.index, ts.values)
axes[0].set_title('Исходный ряд')
axes[1].plot(trend.index, trend.values)
axes[1].set_title('Тренд')
axes[2].plot(seasonal.index, seasonal.values)
axes[2].set_title('Сезонность')
axes[3].plot(residual.index, residual.values)
axes[3].set_title('Шум')
plt.tight_layout()
plt.show()

Выводы

  • Тренд определяет долгосрочное направление через скользящее среднее или полиномиальную регрессию
  • Сезонность выявляется через ACF, FFT или автоматическое разложение
  • Шум анализируется проверкой стационарности и его распределением
  • Разложение — ключевой инструмент для понимания структуры временного ряда перед прогнозированием