Предсказание временных рядов python keras

Узнайте, как быстро построить модель предсказания временных рядов в Python, используя Keras. Пошаговый туториал с кодом и советами для реальных данных.

Временные ряды – один из самых популярных типов данных в бизнес‑аналитике, финансах, IoT, медицине и многих других областях. Способность предсказывать будущее значение ряда позволяет принимать более обоснованные решения, планировать ресурсы и автоматически реагировать на изменения.

В этой статье мы подробно разберём, как построить модель предсказания временных рядов, используя Python и библиотеку Keras (часть TensorFlow). Мы охватим всё: от подготовки данных до выбора архитектуры модели, от обучения до оценки качества и практических советов по деплою.


Содержание

  1. Почему Keras?
  2. Подготовка и визуализация данных
  3. Типичные архитектуры моделей
  4. Обучение модели
  5. Оценка и интерпретация результатов
  6. Тонкая настройка гиперпараметров
  7. Практический пример (прогнозирование продаж)
  8. Лучшие практики и типичные ошибки

Временной ряд – это последовательность наблюдений, упорядоченных во времени, например:

  • курс валют каждый час;
  • показатели температуры по дням;
  • объём продаж за каждый месяц.

Ключевые свойства, которые влияют на выбор модели:

  • Тренд – долгосрочное направление изменения;
  • Сезонность – повторяющиеся паттерны (день‑неделя, год‑квартал);
  • Автокорреляция – зависимость текущего значения от прошлых;
  • Шум – случайные отклонения.

Традиционные статистические методы (ARIMA, SARIMA, Exponential Smoothing) работают хорошо при линейных зависимостях, но часто не справляются с нелинейными паттернами. Именно здесь в игру вступают нейронные сети.


Почему Keras?

Keras – высокоуровневый API для построения и обучения нейронных сетей, встроенный в TensorFlow 2.x. Преимущества:

  • Простота и читаемость кода;
  • Поддержка разнообразных слоёв (LSTM, GRU, Conv1D, Transformer и др.);
  • Автоматическое управление GPU/CPU;
  • Интеграция с tf.data для эффективной обработки больших наборов данных;
  • Встроенные функции обратного вызова (Callback) для ранней остановки, логирования и сохранения модели.

Все примеры ниже реализованы с использованием Keras, но их легко адаптировать к чистому TensorFlow или другим фреймворкам.


Подготовка и визуализация данных

Загрузка данных

Для примера будем использовать набор «Daily Minimum Temperatures in Melbourne» (доступен в UCI Machine Learning Repository).


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-min-temperatures.csv"
df = pd.read_csv(url, parse_dates=['Date'], index_col='Date')
df.head

Визуализация


plt.figure(figsize=(12,4))
plt.plot(df.index, df['Temp'], label='Daily min temperature')
plt.title('Daily Minimum Temperatures in Melbourne')
plt.xlabel('Date')
plt.ylabel('Temperature (°C)')
plt.legend
plt.show

Преобразование в обучающие окна

Нейронные сети работают с фиксированным размером входа. Мы формируем скользящие окна длиной window_size и предсказываем значение, следующее за окном.


def create_dataset(series, window_size=30, horizon=1):
 """
 series – 1‑D массив (numpy) с последовательностью.
 window_size – количество прошлых точек, используемых как вход.
 horizon – сколько шагов вперёд предсказываем.
 """ X, y = [], []
 for i in range(len(series) ー window_size ー horizon + 1):
 X.append(series[i:i+window_size])
 y.append(series[i+window_size+horizon-1])
 return np.array(X), np.array(y)
values = df['Temp'].values.astype(np.float32)
window_size = 30
horizon = 1
X, y = create_dataset(values, window_size, horizon)

X = X[..., np.newaxis] # shape: (samples, window_size, 1)
print('X shape:', X.shape, 'y shape:', y.shape)

Деление на train/validation/test


train_size = int(0.7 * len(X))
val_size = int(0.15 * len(X))

X_train, y_train = X[:train_size], y[:train_size]
X_val, y_val = X[train_size:train_size+val_size], y[train_size:train_size+val_size]
X_test, y_test = X[train_size+val_size:], y[train_size+val_size:]

print(f'Train: {X_train.shape[0]}, Val: {X_val.shape[0]}, Test: {X_test.shape[0]}')

Типичные архитектуры моделей для временных рядов

Полносвязные (Dense) сети

Самый простой вариант – «flatten» вход и подать в несколько полносвязных слоёв. Подходит для небольших наборов, но обычно уступает рекуррентным моделям.

Рекуррентные сети (RNN) – LSTM / GRU

Long Short‑Term Memory (LSTM) и Gated Recurrent Unit (GRU) способны запоминать длительные зависимости.


from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, GRU, Dense, Dropout

def build_lstm(window_size, units=64, dropout=0.2):
 model = Sequential([
 LSTM(units, input_shape=(window_size, 1), return_sequences=False),
 Dropout(dropout),
 Dense(1)
 ])
 model.compile(optimizer='adam', loss='mse')
 return model

lstm_model = build_lstm(window_size)
lstm_model.summary

1‑D сверточные сети (Conv1D)

Свертки способны быстро извлекать локальные паттерны (например, резкие скачки). Комбинация Conv1D + MaxPooling часто используется перед рекуррентным слоем.


from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten

def build_cnn(window_size, filters=32, kernel_size=3):
 model = Sequential([
 Conv1D(filters, kernel_size, activation='relu',
 input_shape=(window_size, 1)),
 MaxPooling1D(pool_size=2),
 Flatten,
 Dense(50, activation='relu'),
 Dense(1)
 ])
 model.compile(optimizer='adam', loss='mse')
 return model

cnn_model = build_cnn(window_size)
cnn_model.summary

Смешанные модели (Conv1D + LSTM)

Сначала Conv1D извлекает локальные признаки, затем LSTM «понимает» их во времени.


def build_cnn_lstm(window_size, conv_filters=32, lstm_units=64):
 model = Sequential([
 Conv1D(conv_filters, 3, activation='relu',
 input_shape=(window_size, 1)),
 MaxPooling1D(2),
 LSTM(lstm_units),
 Dense(1)
 ])
 model.compile(optimizer='adam', loss='mse')
 return model

cnn_lstm_model = build_cnn_lstm(window_size)
cnn_lstm_model.summary

Трансформеры для временных рядов

Модели типа Transformer (в частности Temporal Fusion Transformer) показывают отличные результаты при наличии длинных зависимостей и множества внешних регрессоров.


from tensorflow.keras.layers import MultiHeadAttention, LayerNormalization, Add, Dropout

def build_transformer(window_size, d_model=64, num_heads=4, ff_dim=128, dropout=0.1):
 inputs = tf.keras.Input(shape=(window_size, 1))
 # Линейное проецирование к d_model
 x = tf.keras.layers.Dense(d_model)(inputs)

 # Multi‑Head Attention
 attn_output = MultiHeadAttention(num_heads=num_heads,
 key_dim=d_model)(x, x)
 attn_output = Dropout(dropout)(attn_output)
 out1 = LayerNormalization(epsilon=1e-6)(x + attn_output)
 # Feed‑Forward
 ffn = tf.keras.Sequential([
 tf.keras.layers.Dense(ff_dim, activation='relu'),
 tf.keras.layers.Dense(d_model)
 ])
 ffn_output = ffn(out1)
 ffn_output = Dropout(dropout)(ffn_output)
 out2 = LayerNormalization(epsilon=1e-6)(out1 + ffn_output)

 # Пулинг и предсказание
 out2 = tf.keras.layers.GlobalAveragePooling1D(out2)
 outputs = tf.keras.layers.Dense(1)(out2)
 model = tf.keras.Model(inputs, outputs)
 model.compile(optimizer='adam', loss='mse')
 return model
transformer_model = build_transformer(window_size)
transformer_model.summary

Обучение модели

Выбор функции потерь и метрик

  • Mean Squared Error (MSE) – стандарт для регрессии.
  • Mean Absolute Error (MAE) – менее чувствителен к выбросам.
  • Для финансовых задач часто используют Mean Absolute Percentage Error (MAPE).

Callback‑ы

Ключевой элемент – EarlyStopping (остановка при переобучении) и ModelCheckpoint (сохранение лучшей модели).


from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint

early_stop = EarlyStopping(monitor='val_loss',
 patience=10,
 restore_best_weights=True)

checkpoint = ModelCheckpoint('best_model.h5',
 monitor='val_loss',
 save_best_only=True)

history = lstm_model.fit(
 X_train, y_train,
 epochs=100,
 batch_size=32,
 validation_data=(X_val, y_val),
 callbacks=[early_stop, checkpoint],
 verbose=1
)

Визуализация процесса обучения


plt.figure(figsize=(8,4))
plt.plot(history.history['loss'], label='train')
plt.plot(history.history['val_loss'], label='validation')
plt;title('Кривая обучения')
plt.xlabel('Эпоха')
plt.ylabel('MSE')
plt.legend
plt.show

Оценка и интерпретация результатов

Прогноз на тестовом наборе


y_pred = lstm_model.predict(X_test).flatten


plt.figure(figsize=(12,4))
plt.plot(range(len(y_test)), y_test, label='Истинные')
plt.plot(range(len(y_pred)), y_pred, label='Прогноз')
plt.title('Сравнение предсказаний и реальных значений')
plt.legend
plt.show

Метрики качества


from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

print(f'MSE = {mse:.4f}')
print(f'MAE = {mae:.4f}')
print(f'R² = {r2:;4f}')

Инверсия масштабирования

Если вы применяли нормализацию (StandardScaler, MinMaxScaler), не забудьте вернуть предсказания в оригинальные единицы.


from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler
scaled = scaler.fit_transform(values.reshape(-1,1))

y_pred_original = scaler.inverse_transform(y_pred.reshape(-1,1)).flatten

Тонкая настройка гиперпараметров

Для улучшения качества часто используют поиск по сетке (Grid Search) или более продвинутый Bayesian Optimization. В Keras удобно применять keras-tuner.


!pip install -q keras-tuner # выполнить один раз

import keras_tuner as kt

def model_builder(hp):
 model = Sequential
 # Количество LSTM‑слоёв
 for i in range(hp.Int('num_layers', 1, 3)):
 model.add(LSTM(units=hp.Int(f'units_{i}', min_value=32, max_value=256, step=32),
 return_sequences=(i < hp.Int('num_layers', 1, 3)-1)))
 model.add(Dropout(rate=hp.Float('dropout', 0.0, 0.5, step=0.1)))
 model.add(Dense(1))
 model.compile(optimizer='adam', loss='mse')
 return model

tuner = kt.RandomSearch(
 model_builder,
 objective='val_loss',
 max_trials=20,
 executions_per_trial=2,
 directory='my_dir',
 project_name='time_series_tuning'
)
tuner.search(X_train, y_train,
 epochs=50,
 validation_data=(X_val, y_val),
 callbacks=[early_stop])

После завершения поиска можно получить лучшую модель:


best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]
print(best_hps.values)
best_model = tuner.get_best_models(num_models=1)[0]

Практический пример: прогнозирование ежемесячных продаж

Описание задачи

У компании есть исторические данные о продажах за 5 лет (мес × SKU). Нужно предсказать продажи на следующий месяц для каждого SKU.

Шаги решения

  1. Загрузка данных (CSV → pandas).
  2. Агрегация по месяцам и SKU.
  3. Создание признаков:
    • Текущий объём продаж;
    • Среднее за последние 3/6/12 месяцев;
    • Индикатор сезона (месяц года);
    • Внешние регрессоры (реклама, CPI).
  4. Нормализация (например, StandardScaler).
  5. Формирование окон (window_size = 12, horizon = 1).
  6. Обучение модели LSTM с двумя слоями и dropout.
  7. Оценка на отложенной выборке и визуализация.
  8. Сохранение модели в формате .h5 и экспорт в TensorFlow Serving для онлайн‑прогноза.

Ключевой код (сокращённый)


import tensorflow as tf
import pandas as pd
from sklearn.preprocessing import StandardScaler

df = pd.read_csv('sales.csv', parse_dates=['date'])
df['month'] = df['date'].dt.to_period('M')
monthly = df.groupby(['sku', 'month']).agg({'sales':'sum'}).reset_index

monthly['month_num'] = monthly['month'].dt.month
monthly['log_sales'] = np.log1p(monthly['sales'])

scaler = StandardScaler
monthly[['log_sales', 'month_num']] = scaler.fit_transform(
 monthly[['log_sales', 'month_num']])

def build_dataset(df, sku, window=12):
 series = df[df['sku']==sku].sort_values('month')['log_sales'].values
 X, y = create_dataset(series, window, horizon=1)
 X = X[..., np.newaxis]
 return X, y

X_all, y_all = [], []
for sku in monthly['sku'].unique:
 X_s, y_s = build_dataset(monthly, sku)
 X_all.append(X_s); y_all.append(y_s)

X_all = np.concatenate(X_all)
y_all = np.concatenate(y_all)

train_idx = int(0.75 * len(X_all))
X_train, y_train = X_all[:train_idx], y_all[:train_idx]
X_val, y_val = X_all[train_idx:int(0.9len(X_all))], y_all[train_idx:int(0.9len(X_all))]
X_test, y_test = X_all[int(0.9len(X_all)):], y_all[int(0.9len(X_all)):]

model = Sequential([
 LSTM(128, input_shape=(12,1), return_sequences=True),
 Dropout(0.2),
 LSTM(64),
 Dropout(0.2),
 Dense(1)
])
model.compile(optimizer='adam', loss='mse')
model.fit(X_train, y_train,
 epochs=50,
 batch_size=64,
 validation_data=(X_val, y_val),
 callbacks=[early_stop, checkpoint])

Деплой

Сохраните модель:


model.save('sales_forecast_lstm')

Запустите TensorFlow Serving:


docker run -p 8501:8501 
 --mount type=bind,source=$(pwd)/sales_forecast_lstm,target=/models/sales_forecast_lstm 
 -e MODEL_NAME=sales_forecast_lstm -t tensorflow/serving

Отправьте запрос через curl или любой клиент REST.


Лучшие практики и типичные ошибки

  • Не забывайте о сезонности. Добавьте индикаторные переменные (месяц, квартал, день недели).
  • Старайтесь использовать как минимум 3‑5 циклов сезонности. Для месячных данных – 12 мес., для дневных – 7 дн.
  • Разделяйте наборы по времени, а не случайным образом. Перемешивание разрушит временную связь.
  • Нормализуйте только тренировочную часть. При трансформировании теста используйте те же параметры.
  • Следите за переобучением. LSTM‑модели быстро «запоминают» тренировочные последовательности.
  • Регуляризация: dropout, L2‑регуляризация, ранняя остановка.
  • Аугментация данных. Для небольших наборов полезно генерировать синтетические сериалы (шум, сдвиги).
  • Тестирование на реальном бизнес‑периоде. Иногда метрика MSE не отражает финансовый риск – используйте бизнес‑ориентированные KPI.

Предсказание временных рядов с помощью Keras – мощный и гибкий подход, который позволяет решать задачи от простых «скользящих средних» до сложных многовариантных прогнозов с внешними факторами. Мы рассмотрели:

  • Как подготовить данные и сформировать окна;
  • Какие архитектуры (Dense, LSTM, GRU, Conv1D, Transformer) подходят под разные типы рядов;
  • Процесс обучения, визуализации и оценки модели;
  • Методы гиперпараметрической оптимизации;
  • Полный практический пример с деплоем.

Помните, что успех проекта зависит не только от модели, но и от качественной предобработки, корректного разделения данных и правильного выбора метрик. Экспериментируйте, используйте кросс‑валидацию по времени (TimeSeriesSplit) и постоянно проверяйте модель на новых данных – и вы сможете построить надёжный предсказательный сервис.

Удачной разработки!