Data/Deep Learning

[DL] GRU, LSTM 모델로 시계열 분석하기

쿡국 2024. 12. 27. 11:43

오늘은 GRU와 LSTM 모델을 활용해 간단한 유통데이터 시계열 분석을 진행해보자.

 

1. 라이브러리 호출 및 데이터 불러오기

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, GRU, Dense
from sklearn.metrics import mean_squared_error, mean_absolute_error

df_filtered=pd.read_excel('데이터1_필터링_24추가.xlsx')

df_filtered

 

위 데이터는 모델링 전 상관분석을 진행하여 주요 변수로만 추린 테이블이다. 변수 종류는 아래와 같다.

#데이터셋 변수 확인
print(df_filtered.columns.tolist())
['판매일', '판매수량', '잡화', '평균 발주 일자', '경제성장률(실질GDP성장률)', '기준금리', '총 발주건수', '과자,씨리얼,초코릿,빵류', '소비자물가지수', '생활물가지수', '소비자심리지수']

 

2. 인덱스 처리 및 스케일링

# 판매일 인덱스 처리
df = df_filtered.copy()
df['판매일'] = pd.to_datetime(df['판매일'])

df.set_index('판매일', inplace=True)

# 독립변수, 종속 변수 지정
X = df.drop(columns=['판매수량'])
y = df['판매수량']

# 독립변수 스케일링
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)

 

시계열 데이터이기 때문에 판매일을 인덱스로 처리한 뒤, 독립변수 스케일링을 진행하였다.

 

3. 시퀀스 데이터 생성 및 데이터 분할

# 시계열 데이터 예측을 위한 생성 함수
def create_sequences(X, y, time_steps=4):
    Xs, ys = [], []
    for i in range(len(X) - time_steps):
        Xs.append(X[i:i + time_steps])
        ys.append(y[i + time_steps])
    return np.array(Xs), np.array(ys)

# 시퀀스 데이터 생성 (4주 단위)
time_steps = 4
X_seq, y_seq = create_sequences(X_scaled, y.values, time_steps)
 
# 학습 데이터와 테스트 데이터 분리 (2024년 1월 이전까지는 학습, 이후는 테스트)
split_index = int(len(X_seq) * 0.8)
X_train, X_test = X_seq[:split_index], X_seq[split_index:]
y_train, y_test = y_seq[:split_index], y_seq[split_index:]

 

4. 모델 함수 생성

# LSTM 모델 구축
def build_lstm_model(units=50):
    model = Sequential()
    model.add(LSTM(units, activation='relu', input_shape=(X_train.shape[1], X_train.shape[2])))
    model.add(Dense(1))
    model.compile(optimizer='adam', loss='mse')
    return model

# GRU 모델 구축
def build_gru_model(units=50):
    model = Sequential()
    model.add(GRU(units, activation='relu', input_shape=(X_train.shape[1], X_train.shape[2])))
    model.add(Dense(1))
    model.compile(optimizer='adam', loss='mse')
    return model

 

5. 모델 학습 및 성능 평가

def train_and_evaluate_model(model, X_train, y_train, X_test, y_test):
    model.fit(X_train, y_train, epochs=50, batch_size=16, verbose=0)
    y_pred = model.predict(X_test)
    rmse = np.sqrt(mean_squared_error(y_test, y_pred))
    mae = mean_absolute_error(y_test, y_pred)
    return y_pred, rmse, mae

# LSTM 모델 학습 및 평가
lstm_model = build_lstm_model()
y_pred_lstm, rmse_lstm, mae_lstm = train_and_evaluate_model(lstm_model, X_train, y_train, X_test, y_test)

# GRU 모델 학습 및 평가
gru_model = build_gru_model()
y_pred_gru, rmse_gru, mae_gru = train_and_evaluate_model(gru_model, X_train, y_train, X_test, y_test)

print(f"LSTM RMSE: {rmse_lstm}, MAE: {mae_lstm}")
print(f"GRU RMSE: {rmse_gru}, MAE: {mae_gru}")

성능 평가 결과

 

6. 실제값, 예측값 비교

# 판매일 인덱스 생성
pred_dates = df.index[-len(y_test):]  # 테스트 데이터의 판매일 인덱스

# 실제값, LSTM 예측값, GRU 예측값으로 데이터프레임 생성
results = pd.DataFrame({
    '판매일': pred_dates,
    '실제값': y_test,
    'GRU 예측값': y_pred_gru.flatten(),
    'LSTM 예측값': y_pred_lstm.flatten()
})

# 인덱스를 판매일로 설정
results.set_index('판매일', inplace=True)

# 결과 데이터프레임 출력
results

실제 vs 예측 비교 테이블 일부