Вопрос или проблема
Я только что начал использовать рекурсивные нейронные сети (RNN) с Keras для прогнозирования временных рядов и нашел этот учебник Прогнозирование с помощью RNN. У меня возникают трудности с пониманием того, как построить обучающие данные как касательно синтаксиса, так и формата входных данных.
Вот код:
import pandas as pd
import numpy as np
import tensorflow as tf
from tensorflow import keras
from matplotlib import pyplot as plt
# Чтение данных для параметров из файла csv
df = pd.read_csv("C:/Users/Python/Data/tutorial_electricityPrice.csv", sep =",")
# Удаление первого столбца, так как он не используется в учебнике для прогнозирования
del df['datetime']
data = df.values
n_steps = 168
series_reshaped = np.array([data[i:i + (n_steps+24)].copy() for i in range(len(data) - (n_steps+24))])
X_train = series_reshaped[:43800, :n_steps]
X_valid = series_reshaped[43800:52560, :n_steps]
X_test = series_reshaped[52560:, :n_steps]
Y = np.empty((61134, n_steps, 24))
for step_ahead in range(1, 24 + 1):
Y[..., step_ahead - 1] = series_reshaped[..., step_ahead:step_ahead + n_steps, 0]
Y_train = Y[:43800]
Y_valid = Y[43800:52560]
Y_test = Y[52560:]
np.random.seed(42)
tf.random.set_seed(42)
model6 = keras.models.Sequential([
keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 6]),
keras.layers.SimpleRNN(20, return_sequences=True),
keras.layers.TimeDistributed(keras.layers.Dense(24))
])
model6.compile(loss="mean_squared_error", optimizer="adam", metrics=['mean_absolute_percentage_error'])
history = model6.fit(X_train, Y_train, epochs=10, batch_size=64,
validation_data=(X_valid, Y_valid))
Таким образом, в данном случае используются 168 часов прошлого (n_steps) для прогнозирования следующих 24 часов цен на электроэнергию. Используется 6 признаков.
У меня есть проблемы как с пониманием формата, так и с синтаксисом создания входных данных для RNN.
Вопрос о формате
Я загрузил скриншот размеров массивов данных из Spyder. В общем, у нас есть полный массив данных ‘series_reshaped’ размером (61134, 192, 6). Затем у нас есть входные данные X_train размером (43800, 168, 6). Первая размерность – это временные слоты, вторая размерность – это прошлые временные слоты, которые используются для прогнозирования, а третья размерность – это 6 признаков для каждого из 168 прошлых временных слотов. Затем у нас есть метки Y_train размером (43800, 168, 24). Здесь я не понимаю, почему во второй размерности у нас 168. Насколько я понял, для каждого из 168 прошлых значений * 6 признаков входных данных у нас есть 24 целевых значения. Почему тогда вторая размерность не 168*6 = 1008? Потому что у нас есть соответствие 1008 входов и 24 выхода?
Вопрос о синтаксисе
Я действительно не понимаю, как работает этот код на Python:
for step_ahead in range(1, 24 + 1):
Y[..., step_ahead - 1] = series_reshaped[..., step_ahead:step_ahead + n_steps, 0]
Почему это создает массив Y размерности (61134, 168, 24) или переносит в него правильные данные? Индекс step_ahead принимает только значения от 1 до 24, и теперь мы назначаем 24 значения второй размерности массива Y 168 значениями из прошлых значений series_reshaped. Почему мы назначаем значения только для 24 элементов второй размерности Y, а не для всех 168 элементов? И почему мы обращаемся к прошлым данным массива series_reshaped (вторая размерность). Для меня эти строки крайне запутаны, хотя, очевидно, они делают правильное дело. Может кто-то объяснить мне немного больше о синтаксисе этих строк?
В общем, я был бы признателен за любые комментарии и был бы очень благодарен за вашу помощь.
Обновление
Связанные вопросы: Привет всем, поскольку у меня все еще есть проблемы с этими вопросами, я хотел бы задать несколько связанных вопросов.
- О создании входных данных: как мне знать, какую структуру должны иметь входные данные? И как я могу затем вывести что-то вроде этого кода
for step_ahead in range(1, 24 + 1): Y[..., step_ahead - 1] = series_reshaped[..., step_ahead:step_ahead + n_steps, 0]
2)В конце обучения в учебнике они используют следующий код для предсказания
Y_pred = model6.predict(X_test)
last_list=[]
for i in range (0, len(Y_pred)):
last_list.append((Y_pred[i][0][23]))
Так что они берут Y_pred[i][0][23], чтобы создать одномерный список с предсказанными значениями. Почему они берут [0][23], а не, например, [1][14]? Они хотят предсказать на 24 часа вперед. Могу ли я просто всегда брать Y_pred[i][0][23]?
- Я все еще не понимаю один из своих первоначальных вопросов: почему метка Y для обучения имеет размер [Batch, 168, 24], если return sequence = true? Мы используем 168 прошлых значений для прогнозирования 24 часов. Мы используем 168*6 признаков для прогнозирования. Для каждого элемента в батче (каждого временного слота) у нас затем есть выход в 24 часа. Так что у нас должны быть обучающие данные с размерностью [Batch, 24], а не [Batch, 168, 24]. Для каждого временного слота в батче нам нужны 168 прошлых значений. Как тогда возможно сопоставить 24 часа прогнозов с каждым из 168 прошлых значений?
Напоминание: Мой срок действия награды истекает через три дня, и, к сожалению, я не получил другого более подробного ответа. Я был бы очень признателен за любой новый ответ, который мог бы объяснить входные данные для прогнозирования временных рядов с помощью рекуррентной нейронной сети.
Вам следует смотреть на данные с сохранением признаков для каждого шага. Признаки не могут быть развернуты, так как каждая точка времени определяется всеми признаками.
Давайте посмотрим на этот снимок,
Верхняя таблица – это данные
Предположим, мы хотим предсказать 2 шага, используя 3 входных шага.
Таким образом, один экземпляр нашего ввода будет иметь 3 последовательных шага с 6 признаками на каждом последовательном шаге. Таким образом, ввод становится [Batch, 3, 6]. В вашем случае [Batch, 168, 6].
Выход должен иметь 2 последовательных шага (по требованиям). Поскольку мы прогнозируем один признак, то он будет иметь только один признак. Таким образом, выходная форма [Batch, 2]. В вашем случае [Batch, 24].
Но это было бы так, если бы мы хотели осуществить обратное распространение только после последнего шага, т.е. return_sequences=False
для последнего RNN.
Поскольку мы возвращаем последовательность каждый раз, выход должен иметь 24 значения для каждого последовательного шага. Таким образом, получается выход [Batch, 168, 24].
Признаки
Признаки не проходят последовательно, все 6 признаков будут переданы вместе для каждого временного шага. Проверьте это изображение ниже.
Каждый признак войдет в каждый нейрон, и каждый нейрон добавит рекурсивный вес к каждому нейрону. Если вы проверите количество параметров вашей модели для первого слоя, оно будет 540.
6*20(входные веса) + 20*20(рекурсивные) + 20(смещение) = 540
$\hspace{5cm}$ Изображение предоставлено – Ответ SO
Ответ или решение
Введение
Вопросы о создании входных данных для временных рядов при использовании рекуррентных нейронных сетей (RNN) в Keras являются очень распространёнными среди тех, кто только начинает работать с этой технологией. Данная статья направлена на выяснение формата данных и синтаксиса, который используется при подготовке данных для обучения модели.
Формат данных
-
Формат входных данных (X_train):
- В вашем коде массив
X_train
имеет размерность(43800, 168, 6)
. Здесь:43800
— количество последовательностей (батчей).168
— количество шагов времени, которые мы рассматриваем для предсказания.6
— число признаков (фичей) на каждом временном шаге.
- То есть, для каждой последовательности длиной 168 временных шагов мы имеем 6 различных признаков.
- В вашем коде массив
-
Формат выходных данных (Y_train):
- Массив
Y_train
имеет размерность(43800, 168, 24)
. Здесь:43800
— количество выходных последовательностей, которые соответствуютX_train
.168
— это число временных шагов, но в данном случае оно служит для обозначения того, что для каждого временного шага мы предсказываем 24 будущих значения (например, 24 часа).24
— это количество целевых значений (в нашем случае, предсказание цен на электроэнергию на следующие 24 часа).
- Таким образом, для каждого временного шага в
Y_train
у нас есть 24 предсказанных значения.
- Массив
Почему 168 в Y_train?
Ваш вопрос о том, почему выходной массив Y
имеет вторую размерность 168, а не 1008 (то есть 168 * 6), связан с тем, что выходными данными являются 24 предсказания для каждого из 168 временных шагов. Структура фрейма данных позволяет делать предсказания по каждому шагу, а не для каждой фичи. В итоге мы имеем 24 значения, предсказываемые для каждого из 168 шагов.
Синтаксис создания Y
Рассмотрим следующую строку кода:
for step_ahead in range(1, 24 + 1):
Y[..., step_ahead - 1] = series_reshaped[..., step_ahead:step_ahead + n_steps, 0]
- Эта строка выполняет присвоение значений в
Y
для каждого из 24 целевых временных шагов:step_ahead
рассматривает шаги от 1 до 24.Y[..., step_ahead - 1]
обращается к столбцу, который мы заполняем текущими 168 значениями изseries_reshaped
, начиная сstep_ahead
.series_reshaped[..., step_ahead:step_ahead + n_steps, 0]
извлекает значения изseries_reshaped
, которые соответствуют текущему шагу предсказания.
Таким образом, каждая итерация цикла наполняет определённую таблицу Y
значениями из series_reshaped
, создавая необходимый формат выходных данных.
Как правильно выстраивать данные для RNN
Чтобы правильно создать входные и выходные данные для RNN, нужно понимать, как данные должны структурироваться:
- Входные данные (X): Контекст, на котором будет производиться предсказание. Обычно они представляют собой временные шаги (несколько последовательных шагов).
- Выходные данные (Y): Зависимости от входного контекста. Если мы предсказываем 24 значения, то каждый временной шаг должен давать доступ к необходимым выходным данным.
Работа с предсказаниями
В конце обучения:
Y_pred = model6.predict(X_test)
last_list=[]
for i in range(len(Y_pred)):
last_list.append((Y_pred[i][0][23]))
Здесь выбор Y_pred[i][0][23]
берёт 24-е предсказание для каждого батча. Вы можете, конечно, выбирать любые другие временные шаги (например, [i][0][14]
), если это отвечает вашим требованиям. Поскольку модель предсказывает 24 значения, то вы можете использовать любые индексы в рамках этого диапазона.
Заключение
Подготовка входных и выходных данных для RNN может быть сложной задачей, но понимание структуры временных рядов поможет вам создать подходящие массивы для обучения модели. Если у вас есть дальнейшие вопросы, не стесняйтесь спрашивать — данная часть машинного обучения требует детального подхода.