본문 바로가기
Data Science/Examples

[LSTM] 시계열 데이터셋을 활용한 기온 예측 문제

by titaniumm 2020. 7. 29.

1. 문제 정의 & 데이터 다운

-독일 예나 시에 있는 막스 플랑크 생물지구화학 연구소의 지상 관측소 수집 데이터

-14개의 관측치 데이터가 10분마다 기록되어 있음(2009~2016 데이터를 활용)

#데이터 살펴보기
import os

data_dir = 'C:/Users/82109/Desktop/example' #다운받은 폴더 경로 설정
fname = os.path.join(data_dir, 'jena_climate_2009_2016.csv') #파일 경로 설정

f = open(fname) # r, w, a 모드가 존재
data = f.read()
f.close()

print(type(data)) #str 형식으로 데이터가 저장되어 있다. 

#CSV 파일 형식 행은 "콤마" 로 열을 "\n"으로 나눠서 저장되어있다.
lines = data.split('\n')
header = lines[0].split(',')
lines = lines[1:]

print(header) 
# ['"Date Time"', '"p (mbar)"', '"T (degC)"', '"Tpot (K)"', '"Tdew (degC)"', '"rh (%)"', 
#'"VPmax (mbar)"', '"VPact (mbar)"', '"VPdef (mbar)"', '"sh (g/kg)"', '"H2OC (mmol/mol)"', '"rho (g/m**3)"', '"wv (m/s)"', '"max. wv (m/s)"', '"wd (deg)"']
print(len(lines))
#420551

csv파일을 열고 데이터 구조를 파악할 필요가 있다.  

연산속도를 빠르게 하기 위해서 numpy로 변환해준다.

 

2. NUMPY로 변환해주기 & 살펴보기

import numpy as np

float_data = np.zeros((len(lines), len(header) - 1)) #빈 어레이 형성
for i, line in enumerate(lines):
    values = [float(x) for x in line.split(',')[1:]] #값 저장
    float_data[i, :] = values #이렇게도 되네..

numpy로 변환시켜줄 때, 열을 한번에 바꿔주면 이중포문보다 훨씬 시간이 적게 소요 될것 같다.

 

from matplotlib import pyplot as plt
temp = float_data[:, 5]  # 온도(섭씨)
plt.plot(range(len(temp)), temp)
plt.show()

float_data[ : , 숫자] 에서 숫자를 바꿔주면 각각 변수에 대한 그래프를 확인 할 수 있다.

주기성을 갖는 것을 볼 수 있다. 이후에, 크기를 줄여서 하루 데이터 이런식으로 볼 수 있는데, 코드는 생략하겠다.

 

3. 데이터 준비하기

사전작업으로 두가지를 진행합니다.

 

첫 번째는 데이터 정규화 입니다. 이미 숫자 형태의 넘파이로 바꿔서, 형변환은 필요하지 않지만, 각 변수들마다 편차가 심해 비슷한 크기로 정규화를 진행합니다. (평균을 빼고 표준편차로 나누는 작업으로 진행합니다)

mean = float_data[:200000].mean(axis=0)
float_data -= mean
std = float_data[:200000].std(axis=0)
float_data /= std

print(float_data)

-1 ~ 1 비슷한 숫자들로 정규화 된것을 확인 할 수 있다.

 

두번쨰는 파이썬 제너레이터 생성 입니다. yield를 이용하여 튜플 형식으로 반복전으로 return 한다고 볼 수 있다.

sample 에는 고려하는 다양한 파라미터 데이터들, target에는 목표로 하는 온도가 들어가 있다.

#제너레이터 형성
def generator(data, lookback, delay, min_index, max_index,
              shuffle=False, batch_size=128, step=6):
    if max_index is None:
        max_index = len(data) - delay - 1 #max_index에 대한 정보가 없으면 끝을 max로 설정
    i = min_index + lookback 
    while 1: #반복적으로 yield출력
        if shuffle: #범위 안에서 배치 수 만큼 임의 추출
            rows = np.random.randint(min_index + lookback, max_index, size=batch_size) 
        else:
            #max넘어가면 처음으로 돌리는 if문
            if i + batch_size >= max_index:
                i = min_index + lookback 
            #순서대로 rows에 batch_Size만큼 채워넣기
            rows = np.arange(i, min(i + batch_size, max_index))
            i += len(rows)
        #sample은 (128,240,14) = (배치사이즈, 고려하는 타임스탭의 수 ,파라미터 수)
        samples = np.zeros((len(rows),
                           lookback // step,
                           data.shape[-1]))
        #targets 는 배치 사이즈
        targets = np.zeros((len(rows),))
        for j, row in enumerate(rows):
            indices = range(rows[j] - lookback, rows[j], step)
            samples[j] = data[indices]
            targets[j] = data[rows[j] + delay][1] #온도 변수
        yield samples, targets

4. 초기값 설정 및 생성

lookback = 1440 #10전 데이터를 활용하겠다는 의미
step = 6
delay = 144
batch_size = 128

train_gen = generator(float_data,
                      lookback=lookback,
                      delay=delay,
                      min_index=0,
                      max_index=200000,
                      shuffle=True,
                      step=step, 
                      batch_size=batch_size)
val_gen = generator(float_data,
                    lookback=lookback,
                    delay=delay,
                    min_index=200001,
                    max_index=300000,
                    step=step,
                    batch_size=batch_size)
test_gen = generator(float_data,
                     lookback=lookback,
                     delay=delay,
                     min_index=300001, #끝을 모를 수 도 있으니까 사용
                     max_index=None,
                     step=step,
                     batch_size=batch_size)

# 전체 검증 세트를 순회하기 위해 val_gen에서 추출할 횟수
val_steps = (300000 - 200001 - lookback) // batch_size

# 전체 테스트 세트를 순회하기 위해 test_gen에서 추출할 횟수
test_steps = (len(float_data) - 300001 - lookback) // batch_size

5. 기본 모델 생성 및 실행

from keras.models import Sequential
from keras import layers
from keras.optimizers import RMSprop

model = Sequential()
model.add(layers.GRU(32, input_shape=(None, float_data.shape[-1])))
model.add(layers.Dense(1))

model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen,
                              steps_per_epoch=500,
                              epochs=20,
                              validation_data=val_gen,
                              validation_steps=val_steps)

 

케라스 창시자에게 배우는 딥러닝의 예제이다. LSTM을 공부할때 input shape에 3가지에 대해서 감을 잡기 좋은

예제 인것 같다. 

https://github.com/gilbutITbook/006975/blob/master/6.3-advanced-usage-of-recurrent-neural-networks.ipynb

 

gilbutITbook/006975

케라스 창시자에게 배우는 딥러닝. Contribute to gilbutITbook/006975 development by creating an account on GitHub.

github.com

 

댓글