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

Вопрос или проблема

Я только что начал использовать рекурсивные нейронные сети (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 (вторая размерность). Для меня эти строки крайне запутаны, хотя, очевидно, они делают правильное дело. Может кто-то объяснить мне немного больше о синтаксисе этих строк?

В общем, я был бы признателен за любые комментарии и был бы очень благодарен за вашу помощь.


Обновление

Связанные вопросы: Привет всем, поскольку у меня все еще есть проблемы с этими вопросами, я хотел бы задать несколько связанных вопросов.

  1. О создании входных данных: как мне знать, какую структуру должны иметь входные данные? И как я могу затем вывести что-то вроде этого кода
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]?

  1. Я все еще не понимаю один из своих первоначальных вопросов: почему метка 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 являются очень распространёнными среди тех, кто только начинает работать с этой технологией. Данная статья направлена на выяснение формата данных и синтаксиса, который используется при подготовке данных для обучения модели.

Формат данных

  1. Формат входных данных (X_train):

    • В вашем коде массив X_train имеет размерность (43800, 168, 6). Здесь:
      • 43800 — количество последовательностей (батчей).
      • 168 — количество шагов времени, которые мы рассматриваем для предсказания.
      • 6 — число признаков (фичей) на каждом временном шаге.
    • То есть, для каждой последовательности длиной 168 временных шагов мы имеем 6 различных признаков.
  2. Формат выходных данных (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 может быть сложной задачей, но понимание структуры временных рядов поможет вам создать подходящие массивы для обучения модели. Если у вас есть дальнейшие вопросы, не стесняйтесь спрашивать — данная часть машинного обучения требует детального подхода.

Оцените материал
Добавить комментарий

Капча загружается...