Какая модель работает лучше?

В этом примере модели ARIMA и LSTM используются для прогнозирования моделей потребления электроэнергии для городских управлений Дублина, Ирландия.

Источником данных, о которых идет речь, является data.gov.ie.

В частности, данные о потреблении киловатт предоставляются каждые 15 минут.

Анализ проходит в три этапа:

  1. Соответствующие процедуры обработки данных вызываются для агрегирования общего потребления киловатт в день, т. Е. Формирования дневного временного ряда.
  2. Прогнозируйте потребление киловатт для всего набора тестов с помощью модели ARIMA.
  3. Создайте еще один прогноз для набора тестов с помощью модели LSTM и проверьте, улучшаются ли прогнозы.

Манипуляция данными

Вот исходный набор данных, загруженных в Python.

df = pd.read_csv('dccelectricitycivicsblocks34p20130221-1840.csv', engine='python', skipfooter=3)
df

Мы видим, что для каждой даты соответствующее потребление киловатт предоставляется через 15-минутные интервалы.

Однако в этом случае мы хотим спрогнозировать общее ежедневное потребление, и ожидается, что будет слишком большая волатильность, если временной ряд будет сформирован на 15-минутной основе, чтобы делать любые прогнозы довольно поверхностными.

В связи с этим данные сортируются ежедневно:

df2=df.rename(columns=df.iloc[0])
df3=df2.drop(df.index[0])
df3
df3.drop(df3.index[0])
df4=df3.drop('Date', axis=1)
df5=df4.drop('Values', axis=1)
df5
df6=df5.dropna()
df7=df6.values
df7
dataset=np.sum(df7, axis=1, dtype=float)
dataset

Соответствующие столбцы соответственно переименовываются, а потребление киловатт в день суммируется.

Формируется массив numpy, содержащий агрегированные ежедневные данные:

array([4981.5001927 , 5166.60016445, 3046.35014537, 3101.10013769,
       4908.60016439, 4858.50017742, 4905.00019836, 4999.95019526,
...
       2383.5       , 4481.5       , 4543.        , 4390.        ,
       4385.        , 4289.5       , 2564.        , 2383.        ])

Вот график данных:

ARIMA

Модель ARIMA (или модель авторегрессионного интегрированного скользящего среднего) используется для взятия компонентов рассматриваемого временного ряда (то есть параметров p, d и q) и создания соответствующих новых прогнозов.

Хотя pmdarima будет использоваться для автоматического выбора этих координат, важно определить сезонный тренд.

Первые 80% временных рядов (554 наблюдения) используются в качестве обучающих данных. Вот график автокорреляционной функции, созданной на этом обучающем наборе.

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

В связи с этим сезонная составляющая модели ARIMA определяется как m = 7.

Прежде чем запускать модель ARIMA, давайте кратко рассмотрим 7-дневную скользящую среднюю для этого временного ряда, чтобы лучше визуализировать общую тенденцию.

Мы видим, что общее потребление киловатт, похоже, снижается в первой половине ряда, а во второй половине - увеличивается.

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

Это могло произойти из-за отключения электричества или другого события, которое привело к внезапному падению потребления электроэнергии. При составлении прогнозов мы должны иметь в виду, что этот «шок временного ряда» не обязательно должен быть объяснен прошлыми данными.

Используя данные обучения, теперь выполняется пошаговый поиск с использованием pmdarima, чтобы минимизировать значение AIC, то есть выбрать модель ARIMA, которая показывает самый низкий AIC.

>>> Arima_model=pm.auto_arima(train_df, start_p=0, start_q=0, max_p=10, max_q=10, start_P=0, start_Q=0, max_P=10, max_Q=10, m=7, stepwise=True, seasonal=True, information_criterion='aic', trace=True, d=1, D=1, error_action='warn', suppress_warnings=True, random_state = 20, n_fits=30)
Performing stepwise search to minimize aic
 ARIMA(0,1,0)(0,1,0)[7]             : AIC=8483.714, Time=0.04 sec
 ARIMA(1,1,0)(1,1,0)[7]             : AIC=8421.989, Time=0.12 sec
 ARIMA(0,1,1)(0,1,1)[7]             : AIC=8319.248, Time=0.34 sec
 ARIMA(0,1,1)(0,1,0)[7]             : AIC=8360.091, Time=0.10 sec
 ARIMA(0,1,1)(1,1,1)[7]             : AIC=inf, Time=0.78 sec
 ARIMA(0,1,1)(0,1,2)[7]             : AIC=inf, Time=1.36 sec
 ARIMA(0,1,1)(1,1,0)[7]             : AIC=8328.690, Time=0.27 sec
 ARIMA(0,1,1)(1,1,2)[7]             : AIC=inf, Time=2.29 sec
 ARIMA(0,1,0)(0,1,1)[7]             : AIC=8451.400, Time=0.18 sec
 ARIMA(1,1,1)(0,1,1)[7]             : AIC=inf, Time=0.81 sec
 ARIMA(0,1,2)(0,1,1)[7]             : AIC=inf, Time=0.75 sec
 ARIMA(1,1,0)(0,1,1)[7]             : AIC=8415.537, Time=0.09 sec
 ARIMA(1,1,2)(0,1,1)[7]             : AIC=inf, Time=1.16 sec
 ARIMA(0,1,1)(0,1,1)[7] intercept   : AIC=8321.247, Time=1.30 sec

Best model:  ARIMA(0,1,1)(0,1,1)[7]          
Total fit time: 9.588 seconds

Наиболее подходящая модель ARIMA определяется как ARIMA (0,1,1) (0,1,1) [7].

Теперь можно сделать прогноз на следующие 126 дней, сравнив его с фактическими результатами, полученными по набору тестов.

prediction=pd.DataFrame(Arima_model.predict(n_periods=126), index=test_df)
prediction=np.array(prediction)

Формы прогнозов изменяются, чтобы обеспечить одинаковый формат для набора тестов и прогнозов:

prediction=prediction.reshape(126,-1)

Рассчитывается среднеквадратическая ошибка:

>>> mse = mean_squared_error(test_df, prediction)
>>> rmse = math.sqrt(mse)
>>> print('RMSE: %f' % rmse)
RMSE: 1288.000396

Среднее потребление киловатт для всего тестового набора составило 3 862. Учитывая, что ошибка RMSE составляет 33% от размера среднего, это указывает на то, что модель ARIMA могла бы лучше справляться с прогнозированием потребления электроэнергии.

Чтобы получить более интуитивное представление о том, что происходит, давайте построим прогнозы и тестовые данные.

Мы видим, что модель ARIMA достаточно хорошо уловила сезонный тренд ряда. Тем не менее, прогнозы пикового потребления в первой половине графика оказались немного выше фактических.

Более того, мы видим, что модель не может уловить падение потребления киловатт примерно за 70–80 дней в тестовой выборке. Эта аномалия может вносить вклад в значительную ошибку, которую мы наблюдаем для значения RMSE, поскольку RMSE предназначена для более строгого наказания за ошибки по выбросам.

Обратите внимание, что ручная настройка модели ARIMA, то есть реализация ручного выбора координат p, d, q, показала улучшение точности прогноза со среднеквадратичным значением 965. Вот некоторые более подробные результаты в следующей статье.

LSTM

Модель LSTM теперь реализована на этом наборе данных, чтобы проверить, улучшается ли точность прогноза при использовании этого подхода.

Первоначально данные обрабатывались таким же образом, как и выше, то есть дневной временной ряд был сформирован путем агрегирования потребления киловатт каждые 15 минут в течение одного дня.

Данные разделены на данные для обучения и тестирования:

train_size = int(len(df) * 0.8)
test_size = len(df) - train_size
train, test = df[0:train_size,:], df[train_size:len(df),:]

Формируется матрица набора данных:

def create_dataset(df, previous=1):
    dataX, dataY = [], []
    for i in range(len(df)-previous-1):
        a = df[i:(i+previous), 0]
        dataX.append(a)
        dataY.append(df[i + previous, 0])
    return np.array(dataX), np.array(dataY)

Нормализация данных

Данные нормализованы, чтобы модель LSTM могла правильно интерпретировать данные.

Однако при выполнении этой процедуры есть большой нюанс. Обучающий и тестовый наборы необходимо разделить отдельно (как указано выше) перед проведением процедуры масштабирования для каждого набора отдельно.

Распространенной ошибкой при реализации модели LSTM является простое масштабирование всего набора данных. Это ошибочно, поскольку средство масштабирования будет использовать значения из тестового набора в качестве основы для масштабирования, что приведет к утечке данных обратно в обучающий набор.

Например, предположим, что гипотетический обучающий набор имеет шкалу от 1 до 1000, а гипотетический тестовый набор имеет шкалу от 1 до 1200. MaxMinScaler уменьшит масштаб до числа от 0 до 1. Если данные масштабируются одновременно в обучающем и тестовом наборе, MaxMinScaler также будет использовать шкалу от 1 до 1200 в качестве базовой линии для обучающего набора. Это означает, что новая шкала для обучающего набора была скомпрометирована тестовым набором, что привело к ненадежным прогнозам.

Таким образом, данные в нашем примере масштабируются следующим образом:

scaler = MinMaxScaler(feature_range=(0, 1))
train = scaler.fit_transform(train)
train
test = scaler.fit_transform(test)
test

Конфигурация модели LSTM

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

После проб и ошибок период ретроспективного анализа 5 показал самое низкое среднеквадратичное значение при прогнозировании.

lookback = 5
X_train, Y_train = create_dataset(train, lookback)
X_test, Y_test = create_dataset(test, lookback)

Затем входные данные изменяются в формате образцы, временные шаги, характеристики.

Сеть LSTM определена и обучена:

# Generate LSTM network
model = tf.keras.Sequential()
model.add(LSTM(4, input_shape=(1, lookback)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
history=model.fit(X_train, Y_train, validation_split=0.2, epochs=100, batch_size=1, verbose=2)

Вот график потери обучения и проверки:

Прогнозы генерируются, а затем преобразуются обратно в исходный масштаб (после предварительного преобразования с помощью MinMaxScaler):

trainpred = model.predict(X_train)
testpred = model.predict(X_test)
trainpred = scaler.inverse_transform(trainpred)
Y_train = scaler.inverse_transform([Y_train])
testpred = scaler.inverse_transform(testpred)
Y_test = scaler.inverse_transform([Y_test])
predictions = testpred

Теперь точность предсказания можно вычислить, сравнив предсказания с фактическими данными тестирования.

Во-первых, вот график прогнозируемых и фактических данных.

Рассчитывается значение RMSE.

>>> mse = mean_squared_error(Y_test, predictions)
>>> rmse = sqrt(mse)
>>> print('RMSE: %f' % rmse)
RMSE: 410.116102

Среднее значение по тестовой выборке составляет 3 909. Размер RMSE составляет 10% от среднего, что означает, что модель демонстрирует более высокую производительность, чем ARIMA, в прогнозировании тенденций потребления электроэнергии.

Из графика также следует отметить, что модель LSTM умела прогнозировать период, когда уровень потребления был ниже, чем обычно. Этого можно было бы ожидать, учитывая, что LSTM является одношаговой моделью прогнозирования, т.е. потребление киловатт в момент времени t нельзя прогнозировать, не имея значений за предыдущие пять недель - это не долгосрочный прогноз.

Тем не менее, модель LSTM оказалась более эффективной при учете волатильности ряда.

Заключение

В этом примере мы видели:

  • Как проводить манипуляции с данными с помощью панд
  • Настройка модели ARIMA для долгосрочных прогнозов
  • Прогнозирование на один шаг вперед с помощью модели LSTM
  • Как измерить точность прогнозов с помощью RMSE

Большое спасибо за ваше время, и соответствующий репозиторий GitHub с набором данных и примерами кода можно найти здесь.

Заявление об ограничении ответственности: эта статья написана на условиях «как есть» без каких-либо гарантий. Он был написан с целью предоставить обзор концепций науки о данных и не должен интерпретироваться как профессиональный совет. Выводы и интерпретации в этой статье принадлежат автору и не поддерживаются и не связаны с какими-либо третьими сторонами, упомянутыми в этой статье.

использованная литература