본문 바로가기
인공지능 (기본 딥러닝)/딥러닝 사이드 Project

[LSTM] 예제 코드 설명 (시계열 데이터 예측)

by 애플파ol 2022. 8. 20.

들어가기 전에->  1. LSTM의 기본 개념은 타 블로그 글을 참고하면 될거같습니다.

                               2 . 개념은 알지만 코드를 짜는 부분에 있어서 햇갈리는 분들을 위한 글 입니다.

                               3.window Size 만드는 방법이 메인이 되는 게시글 입니다.

 

 

1. Window Size 만드는 방법.

   ( 그렇다 전처리는 중요한 과정이지만 사실상 전처리를 하는 방법은 자신의 판단에 의해 하는 것이고

     원하는 전처리는 인터넷에 찾아보면 상당히 많은 글들이 있다.

     즉,  window size를 만드는 방법에 대해서 설명을 하겠다.)

 

# 데이터 셋을 만드는 함수
def make_dataset(data, label, window_size):
    feature_list = []
    label_list = []
    for i in range(len(data) - window_size):                           
        feature_list.append(np.array(data.iloc[i:i+window_size]))     
        label_list.append(np.array(label.iloc[i+window_size]))
    return np.array(feature_list), np.array(label_list)

<설명>   

(line별로 설명하겠습니다.)

 

 

line 1: 함수의 입력 인자로는  data ,label,window_size 가 들어감.

 

          data :   data 의 형식은 pandas.DataFrame의 형태로 들어와야하고 feature (=attribute =x값)가

                     입력되는 곳.

 

         label:   label 의 형식은 pandas.DataFrame의 형태로 들어와야하고 Class(=y값) 가 입력되어야 하는 곳.

 

         window_size: 본인이 설정하고 싶은 window_size 

 

 

line 2,3 :  비어있는 feature 리스트와 , 비어있는 label 리스트.

 

line 4    :for 문을 통해서 비어있는 리스트 안에 테이터를 넣기 위함 입니다.

              (설명이 좀 난해하니 뒤에 까지 읽어보면 이해 되실겁니다.)

              (솔직히 line4 이해 못해도 그닥(?) 상관없음.)

 

line 5 : 비어있는 feature_list에 window size만큼 자른후 np.array형태로 변환후,

           뭉텅이씩 리스트에 넣어(append)주는 작업입니다.

 

 ( ☞ 이해를 돕기위해 자료를 직접 보시죵_이렇게 추가가 되는구나 느낌만 아시면 됩니다.)

           

 

 

     1.현재 데이터의 모습 

        (저의 데이터는 8열이 label , 9열이 feature 입니다. (feature 한개입니다.))

DODI_C_20_5의 데이터

     2.  DODI_C_20_5데이터의 1행(=파이썬0행)부터 20행(=파이썬19행)까지의 모습입니다.

     3. feature와 label 이라는 데이터로 분리 해줌.

    

     4. 현재 window_size =5 

                (window_size에 맞게 잘라서 5개씩 묶어서 다음꺼 하나를 예측할것입니다.)

          [91]= 빈리스트

          [92] = window_size =5 , i=0일떄의 모습

          [93] = window_size =5 , i=1일떄의 모습

              (2번의 사진과 비교해서 숫자를 보면 이해가 편합니다.)

     5. 함수의 return 형태 (3차원임.)

line 6 : 비어있는 label_list에 window size만큼 자른후 np.array형태로 변환후,

           뭉텅이씩 리스트에 넣어(append)주는 작업입니다.

            (line5를 이해했다면 쉽게 이해할 수 있습니다.) ,(2차원임)

 

 

2. Window Size 결론.

9행에 보이는것처럼 window_size 만큼으로 묶어서 학습을 시키는것이다.

(과거의 5개(window_size)의 데이터를 가지고 예측을 함.)  -> 과거5일치로 6일치(다음날)를 예측함. 

 

(window_size=5일때 모습 , 9열=feature ,8행=label ,(현재 feature는 9행 한개임) 

 

(나는 머리가 안좋은가... 이렇게 글로 쓰다보니 생각보다 어렵지 않다는게 확 와닫는다.. window_size 설코드찼던...고생했던기억이..)

 

 

3. 전체코드  

  1. 모듈 필요한거 쓰자. (자세한 전처리 과정은 코드에서 생략합니다.)

import pandas as pd                                          # pandas 모듈
import numpy as np                                           # numpy 모듈

from sklearn.model_selection import train_test_split         # 훈련데이터 테스트 데이터 분류
from keras.layers import Dense, Conv1D ,Dropout , MaxPool1D ,LSTM
from keras.models import Sequential
from keras.callbacks import EarlyStopping, ModelCheckpoint

  2. 엑셀 데이터 및 약간의 전처리 방법은 생략함. (랩실 과제이며 파일명 수정하고 등등의 이유..)

  

  3.  데이터 셋을 만드는 함수 

# 데이터 셋을 만드는 함수
def make_dataset(data, label, window_size):
    feature_list = []
    label_list = []
    for i in range(len(data) - window_size):                           # for i in range(0:3712)
        feature_list.append(np.array(data.iloc[i:i+window_size]))      # np.array=values= pd dataframe을 np형식으로 바꿔줌.
        label_list.append(np.array(label.iloc[i+window_size]))
    return np.array(feature_list), np.array(label_list)

  4. Train 데이터의 데이터셋을 만들고

       feature와 label을 분류 하고

       overfitting을 방지해보자.

## ' DODI_C_20_5 ' = Train DATA 

# feaure, label 분류
## train_test_split 사용 (overfitting 방지)

DODI_C_20_5=np.array(DODI_C_20_5)   #슬라이싱을 하기위해 np.array 형식으로 바꿈.

DODI_C_20_5_feature=pd.DataFrame(DODI_C_20_5[:,1])    # feature 열 추출
DODI_C_20_5_label=pd.DataFrame(DODI_C_20_5[:,0])      # label 열 추출


DODI_C_20_5_feature, DODI_C_20_5_label=make_dataset(DODI_C_20_5_feature,DODI_C_20_5_label,5)  #window_size=5 설정

x_train, x_valid, y_train, y_valid = train_test_split(DODI_C_20_5_feature,DODI_C_20_5_label, test_size=0.2 , random_state=34)  
x_train.shape, x_valid.shape, 


(2981, 5, 1), (746, 5, 1)

x_train 의 모습

   5. TEST 데이터의 데이터셋을 만들고

       feature와 label을 분류 하자

     

#### ' DODI_C_20_6 ' = TEST DATA


DODI_C_20_6=np.array(DODI_C_20_6)  #슬라이싱을 하기위해 np.array 형식으로 바꿈.

DODI_C_20_6_feature = pd.DataFrame(DODI_C_20_6[:,1])
DODI_C_20_6_label = pd.DataFrame(DODI_C_20_6[:,0])

DODI_C_20_6_feature.shape 
test_feature, test_label = make_dataset(DODI_C_20_6_feature, DODI_C_20_6_label, 5)
test_feature.shape, test_label.shape



(3711, 20, 1), (3711, 1)

6. model 설계. (LSTM의 activation 함수는 tanh가 되어야함.!! 어떤 예시들은 relu쓰던데.....)

        -> LSTM의 input_shape=(time_step=window_size ,feature 개수)

model = Sequential()
                # LSTM의 hidden layer가 16개 생김.
model.add(LSTM(16, 
               input_shape=(DODI_C_20_5_feature.shape[1], DODI_C_20_5_feature.shape[2]),   #input shape=(time_step=windowsize,featrue개수)
               activation='tanh', 
               return_sequences=False)
          )

model.add(Dense(1))
model.summary()

7. model 컴파일

model.compile(loss='mean_squared_error', optimizer='adam',metrics="accuracy")
early_stop = EarlyStopping(monitor='val_loss', patience=100)


model.fit(x_train, y_train,
            epochs=1000,batch_size=100,
            validation_data=(x_valid, y_valid), 
            callbacks=[early_stop])

8. 시각화로 비교해보기

import matplotlib.pyplot as plt

pred = model.predict(test_feature)

plt.figure(figsize=(12, 9))
plt.plot(test_label, label = 'actual')
plt.plot(pred, label = 'prediction')
plt.legend()
plt.show()

이러한 결과가 나온다는것을 알 수 있다...

 

 

 

<햇갈릴것 같은 부분 예상.>

☞ 내가 LSTM을 구현하면 햇갈렸던 부분은 shape 였는데 왜이렇게 햇갈려했지...

 

1. LSTM layer에 들어가는

input_shape =(time_step ,feature 개수)   이고

input_shape =(window_size ,feature 개수) 와 동일한 의미이다.

 

2. feature 데이터 가공은 3차원으로 reshape 되어야 한다.

     label 데이터 가공은 2차원으로 reshape되어야 한다.

    즉 model.predict( ) 에서 ( ) 안에 들어가는 데이터는 3차원으로 reshape을 하여 가공하여 들어가야한다.

    즉. model.fit(x_train, y_train  ,....)  이 될텐데. x_train 은 3차원 y_train 은 2차원 이 되어야한다.

 

 

※  ex1)     x_train.shape = (2981,5,1)  y_train.shape = (2981,1)

                input_shape(5,1)

           

    ex2)     x_train.shape = (4030,20,4)  y_train.shape = (4030,4)

                input_shape(20,4)          

 

              

    ex3)     x_train.shape = (n,a,b)  y_train.shape = (n,b)

                input_shape(a,b)

 

  ->쉽게 말하면 feature데이터 가공한것(=x_train)의 1,2번 인덱스 값이 들어가면 된다.

            

 

 3. 학습시킬 데이터들의 길이가 다르다면 패딩 또는 제거를 통해 길이를 맞춰주어야 합니다.