티스토리 뷰

시계열 예측(Time Series Forecasting)

  • Licensed under the Apache License, Version 2.0 (the "License")
  • MIT License
  • https://www.tensorflow.org/tutorials/structured_data/time_series
  • RNN(Recurrent Neural Networks)을 사용한 시계열 예측에 대한 소개이다
  • 먼저 Univariate 시계열 값을 예측하고 이후 Multivariate 시계열 값을 예측할것입니다
  • Univariate : 하나의 특성을 사용, Multivariate : 여러개의 특성 사용
from __future__ import absolute_import, division, print_function, unicode_literals
try:
  # %tensorflow_version only exists in Colab.
  %tensorflow_version 2.x
except Exception:
  pass
import tensorflow as tf

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd

mpl.rcParams['figure.figsize'] = (8, 6)
mpl.rcParams['axes.grid'] = False

날씨 데이터 세트

zip_path = tf.keras.utils.get_file(
    origin='https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip',
    fname='jena_climate_2009_2016.csv.zip',
    extract=True)
csv_path, _ = os.path.splitext(zip_path)
https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip 
13574144/13568290 에서 데이터 다운로드 중 [===================== ==========]-1s 0us / step
df = pd.read_csv(csv_path)
df.head()
  • 데이터를 한 눈에 살펴봅니다

  • 데이터는 10분마다 기록됩니다, 한 시간 동안 6개, 하루에 144개의 관측치가 포함됩니다
  • 특정 시간이 주어졌을때 앞으로 6시간 동안의 온도를 예측한다고 가정해봅니다
    • 예측을 하기 위해 5일간의 데이터를 사용하도록 합니다
    • 모형을 학습하기 위해 720(5*144) 개의 관측값이 포함된 window를 만듭니다
    • 이러한 구성을 많이 만들수 있기 때문에 데이터 세트를 실험하기에 적합합니다
  • 아래 함수는 모델이 훈련 할 때 위에서 설명한 time window를 반환합니다
  • history_size : 과거 information window의 크기 입니다 (몇 개의 과거 데이터를 학습할것인지)
  • target_size : 예측해야하는 레이블 입니다. 얼마나 멀리있는 예측을 배워야 하는가이다.
def univariate_data(dataset, start_index, end_index, history_size, target_size):
  data = []
  labels = []

  start_index = start_index + history_size
  if end_index is None:
    end_index = len(dataset) - target_size

  for i in range(start_index, end_index):
    indices = range(i-history_size, i)
    # Reshape data from (history_size,) to (history_size, 1)
    data.append(np.reshape(dataset[indices], (history_size, 1)))
    labels.append(dataset[i+target_size])
  return np.array(data), np.array(labels)
  • 데이터의 처음 300,000개 행은 train dataset이고 나머지는 validation dataset입니다
  • 2100일 분량의 train data에 해당합니다
TRAIN_SPLIT = 300000
# 재현성을 보장하기 위해 시드 설정.
tf.random.set_seed(13)

1 부 : Univariate 시계열 예측

  • 단일 특성(온도)만 사용하여 모델을 학습하고 향후 해당 값을 예측하는 데 사용합니다
  • 데이터 세트에서 온도만 추출합니다
uni_data = df['T (degC)']
uni_data.index = df['Date Time']
uni_data.head()
날짜 시간 
01.01.2009 00:10:00 -8.02 
01.01.2009 00:20:00 -8.41 
01.01.2009 00:30:00 -8.51 
01.01.2009 00:40:00 -8.31 
01.01.2009 00:50:00 -8.27 
이름 : T (degC), dtype : float64
  • 시간에 따른 데이터를 관찰합니다
uni_data.plot(subplots=True)

uni_data = uni_data.values
  • 신경망을 훈련하기 전 기능을 확장하는 것이 중요하다
  • 표준화는 평균을 빼고 각 피처의 표준 편차로 나눔으로써 스케일링을 수행하는 일반적인 방법이다
  • tf.keras.utils.normalize값은 [0,1]범위로 재조정 하는 방법을 사용할 수도 있다
  • Note: 평균 및 표준 편차는 훈련 데이터만을 사용하여 계산해야합니다
uni_train_mean = uni_data[:TRAIN_SPLIT].mean()
uni_train_std = uni_data[:TRAIN_SPLIT].std()
# 데이터를 표준화합시다.
uni_data = (uni_data-uni_train_mean)/uni_train_std
  • Univariate 모델에 대한 데이터를 만듭니다
  • 1부에서는 모델에 마지막 20개의 온도 관측치가 제공되며 다음 단계에서 온도를 예측하는 방법을 배워야합니다
univariate_past_history = 20
univariate_future_target = 0

x_train_uni, y_train_uni = univariate_data(uni_data, 0, TRAIN_SPLIT,
                                           univariate_past_history,
                                           univariate_future_target)
x_val_uni, y_val_uni = univariate_data(uni_data, TRAIN_SPLIT, None,
                                       univariate_past_history,
                                       univariate_future_target)
  • Univariate_data 함수가 반환하는 것입니다
print ('Single window of past history')
print (x_train_uni[0])
print ('\n Target temperature to predict')
print (y_train_uni[0])
Single window of past history
[[-1.99766294]
 [-2.04281897]
 [-2.05439744]
 [-2.0312405]
 [-2.02660912]
 [-2.00113649]
 [-1.95134907]
 [-1.95134907]
 [-1.98492663]
 [-2.04513467]
 [-2.08334362]
 [-2.09723778]
 [-2.09376424]
 [-2.09144854]
 [-2.07176515]
 [-2.07176515]
 [-2.07639653]
 [-2.08913285]
 [-2.09260639]
 [-2.10418486]]

Target temperature to predict
-2.1041848598100876
  • 네트워크에서 제공되는 정보는 파란색으로 표시되며 붉은 X에서 값을 예측해야 합니다
def create_time_steps(length):
  return list(range(-length, 0))
def show_plot(plot_data, delta, title):
  labels = ['History', 'True Future', 'Model Prediction']
  marker = ['.-', 'rx', 'go']
  time_steps = create_time_steps(plot_data[0].shape[0])
  if delta:
    future = delta
  else:
    future = 0

  plt.title(title)
  for i, x in enumerate(plot_data):
    if i:
      plt.plot(future, plot_data[i], marker[i], markersize=10,
               label=labels[i])
    else:
      plt.plot(time_steps, plot_data[i].flatten(), marker[i], label=labels[i])
  plt.legend()
  plt.xlim([time_steps[0], (future+5)*2])
  plt.xlabel('Time-Step')
  return plt
show_plot([x_train_uni[0], y_train_uni[0]], 0, 'Sample Example')

Baseline

  • 모델 학습을 진행하기 전 기준을 설정하겠습니다
  • 입력 지점이 주어지면 모든 기록을보고 다음 지점이 마지막 20개 관측치의 평균이 될 것으로 예측합니다
def baseline(history):
  return np.mean(history)
show_plot([x_train_uni[0], y_train_uni[0], baseline(x_train_uni[0])], 0,
           'Baseline Prediction Example')

  • RNN을 사용하여 Baseline을 이길 수 있는지 봅니다

Recurrent Neural network

  • RNN(Recurrent Neural Network)은 시계열 데이터에 적합한 신경 네트워크 유형입니다

  • RNN은 시계열을 단계별로 처리하여 지금까지 본 정보를 요약하여 내부 상태를 유지합니다

  • LSTM이라고 불리는 RNN의 Layer을 사용합니다

  • tf.data 데이터 세트를 셔플, 배치 및 캐시하는 데 사용하겠습니다

BATCH_SIZE = 256
BUFFER_SIZE = 10000

train_univariate = tf.data.Dataset.from_tensor_slices((x_train_uni, y_train_uni))
train_univariate = train_univariate.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat()

val_univariate = tf.data.Dataset.from_tensor_slices((x_val_uni, y_val_uni))
val_univariate = val_univariate.batch(BATCH_SIZE).repeat()
  • 다음 이미지는 배치 후 데이터가 표시되는 방식을 이해하는 데 도움이됩니다

  • LSTM에 데이터의 입력 형태가 필요하다는 것을 알 수 있습니다
simple_lstm_model = tf.keras.models.Sequential([
      # x_train_uni.shape = (299980, 20, 1)
    tf.keras.layers.LSTM(8, input_shape=x_train_uni.shape[-2:]),
    tf.keras.layers.Dense(1)
])

simple_lstm_model.compile(optimizer='adam', loss='mae')
  • 모델의 출력을 확인하기 위해 샘플 예측을 만들어 봅니다
for x, y in val_univariate.take(1):
    print(simple_lstm_model.predict(x).shape)
(256, 1)
  • 모델을 훈련시킵니다
  • 데이터 세트의 크기 때문에 시간 절약을 위해 각 epoch는 200step만 실행됩니다
EVALUATION_INTERVAL = 200
EPOCHS = 10

simple_lstm_model.fit(train_univariate, epochs=EPOCHS,
                      steps_per_epoch=EVALUATION_INTERVAL,
                      validation_data=val_univariate, validation_steps=50)
200 단계 훈련, 50 단계 검증
에포크 1/10
200/200 [=============================--2s 10ms / step-손실 : 0.4075-val_loss : 0.1351
에포크 2/10
200/200 [==============================-1s 4ms / step-손실 : 0.1118-val_loss : 0.0360
에포크 3/10
200/200 [==============================-1s 4ms / step-손실 : 0.0490-val_loss : 0.0289
에포크 4/10
200/200 [==============================-1s 4ms / step-손실 : 0.0444-val_loss : 0.0257
에포크 5/10
200/200 [==============================-1s 4ms / step-손실 : 0.0299-val_loss : 0.0235
에포크 6/10
200/200 [==============================-1s 4ms / step-손실 : 0.0317-val_loss : 0.0224
에포크 7/10
200/200 [==============================-1s 4ms / step-손실 : 0.0287-val_loss : 0.0206
에포크 8/10
200/200 [==============================-1s 4ms / step-손실 : 0.0263-val_loss : 0.0200
에포크 9/10
200/200 [==============================-1s 4ms / step-손실 : 0.0254-val_loss : 0.0182
에포크 10/10
200/200 [==============================-1s 4ms / step-손실 : 0.0228-val_loss : 0.0174

<tensorflow.python.keras.callbacks.History at 0x7f30b63dea90>

간단한 LSTM 모델 예측

  • 간단한 LSTM을 학습 했으므로 몇 가지 예측을 시도해 보겠습니다
for x, y in val_univariate.take(3):
  plot = show_plot([x[0].numpy(), y[0].numpy(),
                    simple_lstm_model.predict(x)[0]], 0, 'Simple LSTM model')
  plot.show()

  • 이것은 baseline보다 나아보입니다.
  • 기본 사항을 살펴 봤으니, multivariate 시계열을 다루는 2부로 넘어갑니다

2부 : Multivariate 시계열 예측

  • 원본 데이터 세트에는 14개의 특성이 있습니다. 간단하게하기 위해 14개 중 3개만 고려합니다.
  • 사용되는 특성은 대기 온도, 대기압, 공기 밀도입니다
  • 더 많은 특성을 사용하려면 해당 특성 이름을 목록에 추가하세요.
features_considered = ['p (mbar)', 'T (degC)', 'rho (g/m**3)']
features = df[features_considered]
features.index = df['Date Time']
features.head()

  • 시간에 따른 각 특성을 살펴 보겠습니다
features.plot(subplots=True)

  • 첫 단계는 훈련 데이터의 평균 및 표준 편차를 사용하여 데이터 세트를 표준화하는 것입니다
dataset = features.values
data_mean = dataset[:TRAIN_SPLIT].mean(axis=0)
data_std = dataset[:TRAIN_SPLIT].std(axis=0)
# 표준화
dataset = (dataset-data_mean)/data_std

Single step model

  • 모델은 제공된 일부 이력을 기반으로 미래의 단일 지점을 예측하는 방법을 학습합니다
  • 아래의 함수는 주어진 step_size를 기반으로 과거 관측치를 샘플링한다
def multivariate_data(dataset, target, start_index, end_index, history_size,
                      target_size, step, single_step=False):
  data = []
  labels = []

  start_index = start_index + history_size
  if end_index is None:
    end_index = len(dataset) - target_size

  for i in range(start_index, end_index):
    indices = range(i-history_size, i, step)
    data.append(dataset[indices])

    if single_step:
      labels.append(target[i+target_size])
    else:
      labels.append(target[i:i+target_size])

  return np.array(data), np.array(labels)
  • 네트워크에 지난 5일 동안의 데이터, 즉 매 시간마다 샘플링되는 720개의 관측치가 표시됩니다
  • 60분 내에 급격한 변화가 예상되지 않으므로 샘플링은 1시간마다 수행됩니다
  • 120개의 관측치는 지난 5일의 이력을 나타냅니다
  • Single step model의 경우 데이터 포인트의 레이블은 12 시간 뒤의 온도입니다. (12시간 뒤의 온도 예측)
    • 이를위한 레이블을 만들기 위해 72(12*6)관찰 후 온도가 사용됩니다
past_history = 720
future_target = 72
STEP = 6

x_train_single, y_train_single = multivariate_data(dataset, dataset[:, 1], 0,
                                                   TRAIN_SPLIT, past_history,
                                                   future_target, STEP,
                                                   single_step=True)
x_val_single, y_val_single = multivariate_data(dataset, dataset[:, 1],
                                               TRAIN_SPLIT, None, past_history,
                                               future_target, STEP,
                                               single_step=True)
print ('Single window of past history : {}'.format(x_train_single[0].shape))
Single window of past history : (120, 3)
--> 120 : 5일 * 24시간
--> 3 : 3개의 특성
train_data_single = tf.data.Dataset.from_tensor_slices((x_train_single, y_train_single))
train_data_single = train_data_single.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat()

val_data_single = tf.data.Dataset.from_tensor_slices((x_val_single, y_val_single))
val_data_single = val_data_single.batch(BATCH_SIZE).repeat()
single_step_model = tf.keras.models.Sequential()
single_step_model.add(tf.keras.layers.LSTM(32,
                                           input_shape=x_train_single.shape[-2:]))
single_step_model.add(tf.keras.layers.Dense(1))

single_step_model.compile(optimizer=tf.keras.optimizers.RMSprop(), loss='mae')
  • 샘플 예측을 확인합니다
for x, y in val_data_single.take(1):
  print(single_step_model.predict(x).shape)
(256, 1) 
--> 256 : 뭘 의미하지..?
--> 1 : 1개의 예측
single_step_history = single_step_model.fit(train_data_single, epochs=EPOCHS,
                                            steps_per_epoch=EVALUATION_INTERVAL,
                                            validation_data=val_data_single,
                                            validation_steps=50)
200 단계 훈련, 50 단계 검증
에포크 1/10
200/200 [==============================-3s 17ms / step-손실 : 0.3090-val_loss : 0.2646
에포크 2/10
200/200 [==============================-2s 8ms / step-손실 : 0.2624-val_loss : 0.2435
Epoch 3/10
200/200 [==============================] - 2s 8ms/step - loss: 0.2616 - val_loss: 0.2472
Epoch 4/10
200/200 [==============================] - 2s 8ms/step - loss: 0.2567 - val_loss: 0.2442
Epoch 5/10
200/200 [==============================] - 2s 8ms/step - loss: 0.2263 - val_loss: 0.2346
Epoch 6/10
200/200 [==============================] - 2s 8ms/step - loss: 0.2416 - val_loss: 0.2643
Epoch 7/10
200/200 [==============================] - 2s 8ms/step - loss: 0.2411 - val_loss: 0.2577
Epoch 8/10
200/200 [==============================] - 2s 8ms/step - loss: 0.2410 - val_loss: 0.2388
Epoch 9/10
200/200 [==============================] - 2s 8ms/step - loss: 0.2447 - val_loss: 0.2485
Epoch 10/10
200/200 [==============================] - 2s 8ms/step - loss: 0.2388 - val_loss: 0.2422
def plot_train_history(history, title):
  loss = history.history['loss']
  val_loss = history.history['val_loss']

  epochs = range(len(loss))

  plt.figure()

  plt.plot(epochs, loss, 'b', label='Training loss')
  plt.plot(epochs, val_loss, 'r', label='Validation loss')
  plt.title(title)
  plt.legend()

  plt.show()
plot_train_history(single_step_history,
                   'Single Step Training and validation loss')

Single step 예측

  • 모델이 학습되었으므로 몇 가지 샘플을 만듭니다
  • 온도를 예측하는 것이 목표이기 때문에 플롯은 과거 온도만 표시합니다
for x, y in val_data_single.take(3):
  plot = show_plot([x[0][:, 1].numpy(), y[0].numpy(),
                    single_step_model.predict(x)[0]], 12,
                   'Single Step Prediction')
  plot.show()

Multi step model

  • 모델은 과거 히스토리가 주어지면 미래의 값 범위를 예측하는 법을 배워야합니다

  • 하나의 미래 포인트만 예측하는 Single step model과 달리 Multi step model은 미래의 시퀀스를 예측합니다

  • Multi step model의 훈련 데이터는 다시 한 시간마다 샘플링 된 지난 5일 동안의 기록으로 구성됩니다

  • 12시간 동안의 온도를 예측하는 방법을 학습해야합니다

  • 10분마다 관측이 수행되므로 결과는 72(1x6x12)개의 예측입니다

  • 데이터 세트를 적절히 다시 준비해야합니다.

future_target = 72
x_train_multi, y_train_multi = multivariate_data(dataset, dataset[:, 1], 0,
                                                 TRAIN_SPLIT, past_history,
                                                 future_target, STEP)
x_val_multi, y_val_multi = multivariate_data(dataset, dataset[:, 1],
                                             TRAIN_SPLIT, None, past_history,
                                             future_target, STEP)
print ('Single window of past history : {}'.format(x_train_multi[0].shape))
print ('\n Target temperature to predict : {}'.format(y_train_multi[0].shape))
Single window of past history : (120, 3)
--> 120 : 5일 * 24시간
--> 3 : 3개의 특성
Target temperature to predict : (72,)
--> 72개의 예측 데이터
train_data_multi = tf.data.Dataset.from_tensor_slices((x_train_multi, y_train_multi))
train_data_multi = train_data_multi.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat()

val_data_multi = tf.data.Dataset.from_tensor_slices((x_val_multi, y_val_multi))
val_data_multi = val_data_multi.batch(BATCH_SIZE).repeat()
  • 샘플 데이터 포인트 플로팅
def multi_step_plot(history, true_future, prediction):
  plt.figure(figsize=(12, 6))
  num_in = create_time_steps(len(history))
  num_out = len(true_future)

  plt.plot(num_in, np.array(history[:, 1]), label='History')
  plt.plot(np.arange(num_out)/STEP, np.array(true_future), 'bo',
           label='True Future')
  if prediction.any():
    plt.plot(np.arange(num_out)/STEP, np.array(prediction), 'ro',
             label='Predicted Future')
  plt.legend(loc='upper left')
  plt.show()
for x, y in train_data_multi.take(1):
  multi_step_plot(x[0], y[0], np.array([0]))

  • 이전 작업보다 조금 더 복잡하기 때문에 모델을 두 개의 LSTM 계층으로 구성합니다
  • 마지막으로 72개의 예측이 이루어지므로, Dense layer는 72개의 예측을 출력합니다
multi_step_model = tf.keras.models.Sequential()
multi_step_model.add(tf.keras.layers.LSTM(32,
                                          return_sequences=True,
                                          input_shape=x_train_multi.shape[-2:]))
multi_step_model.add(tf.keras.layers.LSTM(16, activation='relu'))
multi_step_model.add(tf.keras.layers.Dense(72))

multi_step_model.compile(optimizer=tf.keras.optimizers.RMSprop(clipvalue=1.0), loss='mae')
  • 학습하기 전에 모델이 어떻게 예측하는지 봅시다
for x, y in val_data_multi.take(1):
  print (multi_step_model.predict(x).shape)
(256, 72)
--> 256 : ?
--> 72 : 72개의 예측 (6(한시간 여섯개) * 12시간)
multi_step_history = multi_step_model.fit(train_data_multi, epochs=EPOCHS,
                                          steps_per_epoch=EVALUATION_INTERVAL,
                                          validation_data=val_data_multi,
                                          validation_steps=50)
200 단계 훈련, 50 단계 검증
에포크 1/10
200/200 [=============================-20s 98ms / step-손실 : 0.4963-val_loss : 0.3021
에포크 2/10
200/200 [==============================-17s 85ms / step-손실 : 0.3463-val_loss : 0.2880
에포크 3/10
200/200 [==============================-17s 85ms / step-손실 : 0.3288-val_loss : 0.2408
에포크 4/10
200/200 [==============================-17s 84ms / step-손실 : 0.2429-val_loss : 0.2074
에포크 5/10
200/200 [=============================-17s 84ms / step-손실 : 0.1973-val_loss : 0.1987
에포크 6/10
200/200 [=============================-17s 84ms / step-손실 : 0.2062-val_loss : 0.2080
에포크 7/10
200/200 [=============================]-17s 84ms / step-손실 : 0.1979-val_loss : 0.2071
에포크 8/10
200/200 [=============================]-18s 88ms / step-손실 : 0.1958-val_loss : 0.1954
에포크 9/10
200/200 [=============================]-18s 91ms / step-손실 : 0.1975-val_loss : 0.1873
에포크 10/10
200/200 [=============================-18s 88ms / step-손실 : 0.1892-val_loss : 0.1817
plot_train_history(multi_step_history, 'Multi-Step Training and validation loss')

Multi step 예측

for x, y in val_data_multi.take(3):
  multi_step_plot(x[0], y[0], multi_step_model.predict(x)[0])

다음 단계

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함