LSTM(long short term memory)을 이용한 월 단위 가스 사용량 예측

목표 : 단기 가스 사용량 예측 모델 개발

개요

  • 딥러닝(deep learning) 알고리즘 중에서 시계열 데이터 예측 및 분석에 유용한 RNN(recurrent neural network), LSTM(long short term memory)을 이용하여 가스 사용량(공급량)을 예측하는 모델을 개발
  • RNN은 입력에서 출력으로만 전개되는 다른 neural network와는 다르게 입력 ↔ 출력과 같은 순환적인 구조임
  • 과거의 상태를 저장하는 메모리를 지니고 있어서 순차적인 문제, 전체적인 흐름을 파악해야 하는 문제, 시계열 데이터 예측 문제에 적합하다.

데이터

주어진 데이터 표본

해당 데이터는 C사 산업문제 해결을 위해 제공 받은 데이터로 실제 공급량은 보안상 공개하지 않는다.

평균기온 세대수 공급량
1 -0.9 341,094 **,***,***
2 -0.9 341,094 **,***,***
3 7.6 341,094 **,***,***
4 14.0 341,094 **,***,***
5 18.1 341,094 **,***,***
6 21.1 341,094 **,***,***
  • 월: 2008년도 1월부터 2016년 12월까지 (총 108개월)
  • 평균기온: 해당 월의 평균기온
  • 세대수: "판매량 회귀분석_1,2월 샘플.xlsx"데이터에 있는 1월 세대수(세대수 는 연 단위로 변경)
  • 공급량: 월 가스 사용량의 합계(보안을 위해 미공개)

분석 방법

  • 사용한 독립변수는 , 평균기온, 세대수, 사용량 4가지 이다.
  • 현재를 기준으로 이전 4달 자료를 이용하여 앞으로 두 달 후 가스 사용량을 예측하는 모델을 설계했다.
  • 예를 들어서, 8월 2일 기준 4~7월의 평균기온, 세대수, 사용량과 8~10월 예상 세대수, 예상 평균기온을 이용하여 10월 사용량을 예측하는 모델이다. 현재(8월 2일) 기준으로 8~10월 사용량은 알 수 없기 때문에 0으로 처리했다.
  • 분석방법은 LSTM(long short term memory)을 사용하였으며 Multi cell의 갯수는 5개이다.

데이터 framework

평균기온 세대수 공급량 예측값
1 -0.9 341,094 **,***,***  
2 -0.9 341,094 **,***,***  
3 7.6 341,094 **,***,***  
4 14.0 341,094 **,***,***  
5 18.1 341,094 0  
6 21.1 341,094 0  
7 26.1 341,094 0 → 22,406,900
  • 주어진 데이터를 위 형태와 같이 변경해서 총 102개의 데이터셋을 제작했다.
  • 102개의 데이터 중에서 모델의 타당성 검증(validation)을 위해서 80%의 데이터를 학습에 사용하고 나머지 20%는 검증에 쓰였다.
  • 학습에 쓰인 데이터는 2008년도 7월부터 2015년도 3월까지 데이터고 검증에 쓰인 데이터는 2015년도 4월부터 2016년도 12월까지 데이터이다.

학습 결과

  • 위쪽 그림은 학습데이터 2008년도 7월부터 2015년도 3월의 결과를 보여주고 아래 그림은 테스트데이터인 2015년도 4월부터 2016년도 12월의 결과를 보여준다. 파란 선이 실제 가스 사용량이고 녹색 선이 LSTM으로 예측한 값이다.

비교

실제 공급량 추정값 오차
4 **,***,*** **,***,*** 165,978.8
5 **,***,*** **,***,*** -1,594,262.6
6 **,***,*** **,***,*** 54,296.0
7 **,***,*** **,***,*** -2,373,938.8
8 **,***,*** **,***,*** -3,344,758.9
9 **,***,*** **,***,*** -1,734,654.1
10 **,***,*** **,***,*** -8,226,366.1
11 **,***,*** **,***,*** -5,637,397.6
12 **,***,*** **,***,*** 2,179,351.1
1 ***,***,*** ***,***,*** 1,736,164.7
2 **,***,*** ***,***,*** -10,439,821.8
3 **,***,*** **,***,*** 1,427,850.3
4 **,***,*** **,***,*** -1,708,647.6
5 **,***,*** **,***,*** 2,264,750.1
6 **,***,*** **,***,*** -5,121,490.1
7 **,***,*** **,***,*** -674,244.2
8 **,***,*** **,***,*** -2,821,464.1
9 **,***,*** **,***,*** -190,412.5
10 **,***,*** **,***,*** 2,016,059.6
11 **,***,*** **,***,*** 4,987,706.6
12 **,***,*** **,***,*** 3,595,950.0

결론

  • 학습데이터가 부족하고 정확하지 않은 상태임에도 불구하고 공급량의 추세를 잘 분석한 것으로 보임
  • 보다 정확한 세대수 반영 및 해당 월의 휴일 이나 주말 수와 같은 새로운 독립변수를 추가 하면 더 좋은 예측값이 나올 것으로 기대
  • 현재 예측 모델은 전체 데이터의 80%를 학습해서 남은 20%(2015년~2016년) 부분을 예측했는데 실제로 모델을 사용할 때는 두 달 후 한 값만 예측 하는 것이기 때문에 더 정확한 예측이 가능 할 것으로 기대

기타

Python Code

Based on Python = 3.6.2, Tensorflow = 1.2.1

#라이브러리 불러오기

import tensorflow as tf
from tensorflow.contrib import rnn
import matplotlib.pyplot as plt
import pandas as pd

#데이터 불러오기

data_frame = pd.read_excel("Data/Month_data.xlsx", sheet = 1)

#최고기온, 최저기온 변수 제거 

del data_frame["Max_temperature"]
del data_frame["Min_temperature"]

#하이퍼 파라미터 설정

timesteps = seq_length = 6
data_dim = 4
hidden_dim = 4
output_dim = 1
learing_rate = 0.0005
iterations = 50_000

#데이터 조절

data_frame["Population"] /= 1e5
data_frame["Supply"] /= 1e7

#Framework 제작

x = data_frame.values
y = data_frame["Supply"].values  

dataX = []
dataY = []
for i in range(0, len(y) - seq_length):
    _x = np.copy(x[i:i + seq_length + 1])
    _x[timesteps-2][data_dim-1] = 0
    _x[timesteps-1][data_dim-1] = 0
    _x[timesteps][data_dim-1] = 0
    _y = [y[i + seq_length]]
    dataX.append(_x)
    dataY.append(_y)

#학습데이터와 테스트데이터 분류

train_size = int(len(dataY) * 0.8)
test_size = len(dataY) - train_size 

trainX = np.array(dataX[:train_size])
testX = np.array(dataX[train_size : ])

trainY = np.array(dataY[:train_size])
testY = np.array(dataY[train_size : ])


#LSTM모델 구축

X = tf.placeholder(tf.float32, [None, seq_length+1, data_dim])
Y = tf.placeholder(tf.float32, [None, 1])

def lstm_cell(): 
    cell = rnn.BasicLSTMCell(hidden_dim, state_is_tuple=True) 
    return cell 


multi_cells = rnn.MultiRNNCell([lstm_cell() for _ in range(5)], state_is_tuple=True)


outputs, _states = tf.nn.dynamic_rnn(multi_cells, X, dtype=tf.float32)

Y_pred = tf.contrib.layers.fully_connected(outputs[:, -1], output_dim, activation_fn=None)

loss = tf.reduce_sum(tf.square(Y_pred - Y))  
train = tf.train.RMSPropOptimizer(learing_rate).minimize(loss)

sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)

for i in range(iterations):
    _  , cost = sess.run([train ,loss], feed_dict={X: trainX, Y: trainY})
    if (i+1) % (iterations/10) == 0:
        print("[step: {}] loss: {}".format(i+1, cost))


#예측값 불러오기
train_predict = sess.run(Y_pred, feed_dict={X: trainX})
test_predict = sess.run(Y_pred, feed_dict={X: testX})

분석 실패 사례

실제 공급량과 예측값 비교

  • 위 그림은 데이터 framework, hypter parameter, 학습 횟수(iterations) 등 을 변화시켜서 LSTM으로 학습한 결과를 보여준다. 학습데이터의 실제 공급량과 예측값의 차이가 보이지 않을 정도로 학습이 진행되었지만 테스트데이터에 대해서는 실제 공급량을 예측하지 못하였다. 즉, 학습데이터에 대한 과적합(overfitting)이 발생하였다.

Reference

  • Team AI Korea RNN Tutorial - Part 1
  • https://github.com/hunkim/DeepLearningZeroToAll