Прогнозирование временных рядов с использованием рекуррентных нейронных сетей

Есть csv данные о заболеваемости коронавирусной инфекцией за период с апреля 2020 года по октябрь 2021 года в конкретном регионе страны. Данные имеют следующие атрибуты:

  • Медицинская организация
  • Идентификатор пациента
  • Возраст
  • Пол
  • Дата госпитализации

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

Идея состоит в том, чтобы обучить модель на данных до сентября 2021 года и спрогнозировать данные на октябрь 2021 года, а затем сравнить их с реальными данными за октябрь 2021 года. Сейчас у меня следующие результаты. Значение RMSE составляет 21,5: введите сюда описание изображения

В связи с этим у меня следующие вопросы:

  1. Как правильно настроить модель для повышения точности прогнозирования, поскольку текущий результат неудовлетворительный (я новичок в области нейронных сетей)
  2. Правильно ли я выбрал тип нейронных сетей для своей задачи?
  3. Насколько правильно попытаться спрогнозировать данные на месяц. Как определить оптимальный период прогнозирования для рекуррентной нейронной сети?

Буду рад любой помощи!

Вот мой код:

import tensorflow as tf

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense

# Загрузка данных
data = pd.read_csv('out3.csv')
data['index'] = pd.to_datetime(data['index'])
data.set_index('index', inplace=True)

# Нормализация данных
scaler = MinMaxScaler(feature_range=(0, 1))
data_scaled = scaler.fit_transform(data[['count']])

tf.random.set_seed(13)

# Функция для создания датасета
def create_dataset(dataset, look_back=1):
    X, Y = [], []
    for i in range(len(dataset) - look_back - 1):
        a = dataset[i:(i + look_back), 0]
        X.append(a)
        Y.append(dataset[i + look_back, 0])
    return np.array(X), np.array(Y)

# Подготовка данных
look_back = 1
train = data_scaled[data.index < pd.Timestamp('2021-10-01')]
test = data_scaled[data.index >= pd.Timestamp('2021-10-01')]

X_train, Y_train = create_dataset(train, look_back)
X_test, Y_test = create_dataset(test, look_back)
X_train = np.reshape(X_train, (X_train.shape[0], 1, X_train.shape[1]))
X_test = np.reshape(X_test, (X_test.shape[0], 1, X_test.shape[1]))

# Создание модели LSTM
model = Sequential()
model.add(LSTM(50, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')

# Обучение модели
model.fit(X_train, Y_train, epochs=100, batch_size=1, verbose=2)

# Инициализация последнего значения обучающей выборки для начального прогноза
last_train = X_train[-1].reshape(1, 1, look_back)

# Список для сбора прогнозов
test_predictions = []

# Делаем прогнозы на количество шагов, равное размеру тестовой выборки
for _ in range(len(X_test)):
    current_pred = model.predict(last_train)[0]
    test_predictions.append(current_pred)
    # Обновляем last_train, чтобы содержало последний прогноз
    last_train = np.array([[current_pred]])

# Обратное преобразование для визуализации
test_predictions = scaler.inverse_transform(test_predictions)
# print(test_predictions)
# print('------------------')
# print(scaler.inverse_transform(test)[:len(test_predictions)])

# Расчет RMSE
rmse = np.sqrt(mean_squared_error(scaler.inverse_transform(test)[:len(test_predictions)], test_predictions))
print(f'RMSE: {rmse:.2f}')


# Визуализация
plt.figure(figsize=(15, 7))
training_data_to_plot = scaler.inverse_transform(train)[look_back:]
actual_dates = data.index[data.index >= pd.Timestamp('2021-10-01')]
plt.plot(data.index[data.index < pd.Timestamp('2021-10-01')][look_back:], training_data_to_plot, label='Training Data')
plt.plot(actual_dates[:len(test_predictions)], scaler.inverse_transform(test)[:len(test_predictions)], label='Actual October Data')
plt.plot(actual_dates[:len(test_predictions)], test_predictions, label='Predicted October Data', linestyle='--')
plt.title('Comparison of Actual and Predicted Values for October')
plt.xlabel('Date')
plt.ylabel('Count')
plt.legend()
plt.show()

Ответы (1 шт):

Автор решения: passant

Давайте начнем с вопроса №2. А почему вы выбрали нейросети для решения вот этой, в общем-то абсолютно рядовой задачи (я имею ввиду не ковид-прогноз, а работу с обычным, эквидистантным, одномерным временным рядом), с решением которой традиционно работают другими методами, причём давно и достаточно успешно. Причем известно, что традиционные методы часто дают прогноз даже лучше чем навороченные нейросети. (Посмотрите, например, Makridakis Competitions). Т.е. вопрос стоит так - вам задачу решить надо или нейросети как таковые изучать?

Вопрос №3. Прогнозировать временной ряд можно на сколь угодно длительный период упреждения. Однако надо иметь ввиду, что чем больший период прогноза, тем шире доверительный интервал. А значит - тем меньше смысла/пользы в вашем прогнозе. Если строить прогноз предварительно ресемплировав данные помесячно - то толку от такого прогноза тоже будет мало, т.к. вариабельность значений станет неадекватно широкой. Кроме того, период прогноза зависит и от природы объекта исследования. Поэтому, если у вас цель "задачу решать", ть с прикладной точки зрения реален (точным) может быть прогноз на короткий период - 3-5-7 максимум 10 дней. (Так мне кажется, хотя это надо проверять на ваших данных). "Оптимального" периода прогноза нет и быть не может. Вот это надо понять четко.

Вопрос №1. Вы приводите единственный параметр вашей модели (RMSE) и просите сказать, как повысить точность, ибо результат - "неудовлетворительный". А как можно по этому показателю прийти к такому выводу? Во-первых, этот показатель не показывает абстрактного качества модели. Он может использоваться для взаимного сравнения моделей между собой (лучше-хуже). Не более того. Для оценки абстрактного качества модели тогда уж лучше использовать коэффициент детерминации. Он хоть (неявно) сравнивает результат вашей модели с некоторой наивной модели, причем результат этого сравнения всегда лежит в известном диапазоне, а следовательно уже можно говорить об некоторой абстрактной "удовлетворенности" вашей моделью.

Ну и наконец, глобальный ответ. Задача прогнозирования временного ряда - это не школьная задача, где есть единственно правильный ответ, который знает и скрывает от вас учитель. Реальная задача прогнозирования - это всегда (!!!) некоторый научный поиск. И всегда попытки перепробовать (!) некоторые методы решения в поисках лучшего решения. Парадокс в том, что один и тот-же метод, на данных которые "на глаз" кажутся очень похожими может давать интересные результаты, а в некоторых случаях - совершенно негодные. Т.е. не попробуешь - не построишь нормальную модель. Не даром люди продолжают искать и предлагать новые и новые методы и соответствующие реализации (в последнем упомянутом выше соревновании-исследовании задействовано уже неколько тысяч команд создателей моделей предсказания). Поэтому подскзывать что именно в вашей модели "не так" и давать рекомендации, не "поигравшись" конкретно с вашими данными - это все равно, что ставить диагноз заочно. Тут может быть все что угодно - от "выкинте нейросети", до "попробуйте увеличить количество слоев" или "используйте Prophet". Даже в том источнике, который вы скорее всего использовали (https://machinelearningmastery.com/time-series-prediction-lstm-recurrent-neural-networks-python-keras/) есть несколько вариантов действий на случай такой неудовлетворенности. Так что все что можно насоветовать - экспериментируйте. Удачи!

→ Ссылка