Прогнозирование временных рядов с использованием рекуррентных нейронных сетей
Есть csv данные о заболеваемости коронавирусной инфекцией за период с апреля 2020 года по октябрь 2021 года в конкретном регионе страны. Данные имеют следующие атрибуты:
- Медицинская организация
- Идентификатор пациента
- Возраст
- Пол
- Дата госпитализации
Я сгруппировал данные по дате госпитализации, чтобы увидеть количество случаев по дням за весь период. Получилось вот так:
Идея состоит в том, чтобы обучить модель на данных до сентября 2021 года и спрогнозировать данные на октябрь 2021 года, а затем сравнить их с реальными данными за октябрь 2021 года. Сейчас у меня следующие результаты. Значение RMSE составляет 21,5:
В связи с этим у меня следующие вопросы:
- Как правильно настроить модель для повышения точности прогнозирования, поскольку текущий результат неудовлетворительный (я новичок в области нейронных сетей)
- Правильно ли я выбрал тип нейронных сетей для своей задачи?
- Насколько правильно попытаться спрогнозировать данные на месяц. Как определить оптимальный период прогнозирования для рекуррентной нейронной сети?
Буду рад любой помощи!
Вот мой код:
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 шт):
Давайте начнем с вопроса №2. А почему вы выбрали нейросети для решения вот этой, в общем-то абсолютно рядовой задачи (я имею ввиду не ковид-прогноз, а работу с обычным, эквидистантным, одномерным временным рядом), с решением которой традиционно работают другими методами, причём давно и достаточно успешно. Причем известно, что традиционные методы часто дают прогноз даже лучше чем навороченные нейросети. (Посмотрите, например, Makridakis Competitions). Т.е. вопрос стоит так - вам задачу решить надо или нейросети как таковые изучать?
Вопрос №3. Прогнозировать временной ряд можно на сколь угодно длительный период упреждения. Однако надо иметь ввиду, что чем больший период прогноза, тем шире доверительный интервал. А значит - тем меньше смысла/пользы в вашем прогнозе. Если строить прогноз предварительно ресемплировав данные помесячно - то толку от такого прогноза тоже будет мало, т.к. вариабельность значений станет неадекватно широкой. Кроме того, период прогноза зависит и от природы объекта исследования. Поэтому, если у вас цель "задачу решать", ть с прикладной точки зрения реален (точным) может быть прогноз на короткий период - 3-5-7 максимум 10 дней. (Так мне кажется, хотя это надо проверять на ваших данных). "Оптимального" периода прогноза нет и быть не может. Вот это надо понять четко.
Вопрос №1. Вы приводите единственный параметр вашей модели (RMSE) и просите сказать, как повысить точность, ибо результат - "неудовлетворительный". А как можно по этому показателю прийти к такому выводу? Во-первых, этот показатель не показывает абстрактного качества модели. Он может использоваться для взаимного сравнения моделей между собой (лучше-хуже). Не более того. Для оценки абстрактного качества модели тогда уж лучше использовать коэффициент детерминации. Он хоть (неявно) сравнивает результат вашей модели с некоторой наивной модели, причем результат этого сравнения всегда лежит в известном диапазоне, а следовательно уже можно говорить об некоторой абстрактной "удовлетворенности" вашей моделью.
Ну и наконец, глобальный ответ. Задача прогнозирования временного ряда - это не школьная задача, где есть единственно правильный ответ, который знает и скрывает от вас учитель. Реальная задача прогнозирования - это всегда (!!!) некоторый научный поиск. И всегда попытки перепробовать (!) некоторые методы решения в поисках лучшего решения. Парадокс в том, что один и тот-же метод, на данных которые "на глаз" кажутся очень похожими может давать интересные результаты, а в некоторых случаях - совершенно негодные. Т.е. не попробуешь - не построишь нормальную модель. Не даром люди продолжают искать и предлагать новые и новые методы и соответствующие реализации (в последнем упомянутом выше соревновании-исследовании задействовано уже неколько тысяч команд создателей моделей предсказания). Поэтому подскзывать что именно в вашей модели "не так" и давать рекомендации, не "поигравшись" конкретно с вашими данными - это все равно, что ставить диагноз заочно. Тут может быть все что угодно - от "выкинте нейросети", до "попробуйте увеличить количество слоев" или "используйте Prophet". Даже в том источнике, который вы скорее всего использовали (https://machinelearningmastery.com/time-series-prediction-lstm-recurrent-neural-networks-python-keras/) есть несколько вариантов действий на случай такой неудовлетворенности. Так что все что можно насоветовать - экспериментируйте. Удачи!