ADP/실기

시계열 분해, ARIMA 모델

hyerimir 2024. 1. 28. 17:39

 

# 시계열 분해
# 시계열 분해(time series decomposition)는 시계열 자료를 추세(trend), 계절성(seasonality), 잔차(residual)로 분해하는 기법
# 추세변동 : x 값인 시간에 따라, y인 종속변수 값이 달라진다는 것
# 계절변동 : 특정 주기별
# 순환변동 : 추세변동 + 계절변동
# 불규칙변동 : 잔차

# 시계열 분해 방법
# 데이터를 보고, 시계열의 주기적 반복/계절성이 있는지 확인
# 가법모형과 승법모형 중 무엇이 더 적합할 지 판단

# 시계열에서 추세를 뽑아내기 위해, 중심이동평균(centered moving average)을 이용
# 원자료에서 추세 분해값을 빼줍니다(detrend)
# 그러면 계절요인과 불규칙 요인만 남게 됨

# 계절주기로 detrend 이후 남은 값의 합을 나누어 계절평균(average seasonality)을 구하기

# 원래의 값에서 추세와 계절성 분해 값을 빼주면 불규칙요인(random irregular factor)이 남게됨
# 시계열 분해 후에 추세와 계절성을 제외한 잔차는 특정한 패턴없이 무작위 분포를 띠고 작은 값이면
# 추세와 계절성으로 모형화가 잘 이루어진 데이터임
# 이는 시계열 자료의 특성을 이해하고 예측하는데 활용 가능

# 만약 시계열 분해 후의 잔차에 특정 패턴이 존재하면 잔차에 대해서만 다른 모형을 추가로 적합
import pandas as pd
data = pd.read_csv('../data/arima_data.csv', names = ['day', 'price'])
data.info()
# 이때 날짜 데이터의 형식이 object형으로 확인됨

data['day'] = pd.to_datetime(data['day'], format = '%Y-%m-%d')
# 날짜 데이터를 index로 지정해야함
data.set_index('day', inplace = True)

from statsmodels.tsa.seasonal import seasonal_decompose
import matplotlib.pyplot as plt

ts = data
result = seasonal_decompose(ts, model = 'additive')

plt.rcParams['figure.figsize'] = [12,8]
result.plot()
plt.show()
# Arima 분석
# Autoregressive integrated MovingAverage
# 과거의 데이터를 사용하는 것 넘어 과거의 데이터가 지니고 있었던 추세까지 반영함

# AR(자기상관) : 이전의 값이 이후의 값에 영향을 미치고 있는 상황 -> p
# MA(이동평균) : 랜덤 변수의 평균값이 지속적으로 증가하거나 감소하는 추세 -> q
# 차분 : 비정상성을 정상성으로 만들기 위해, 관측값들의 차이를 계산 -> d

import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv('../data/arima_data.csv'), names = ['day', 'price'])
data['day'] = pd.to_datetime(data['day'], format = '%Y-%m-%d')
data.set_index('day', inplace = True)
# train, test 데이터 구분
train_len = int(len(data) * 0.8)
training = data[:train_len]
test = data.drop(training.index)

# 시계열 데이터 확인하기
training.plot()
plt.show()
# 추세도 있고, 계절성도 있는 것으로 보임

from statsmodels.tsa.stattools import adfuller
adf = adfuller(data, regression = 'ct')

# adf statistic
print(adf[0])

# p-value
print(adf[1])

# 이때 정상성이 아님을 확인
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

diff_data = training.diff(1) # 차분, d = 1
diff_data = diff_data.dropna()

diff_data.plot()

from statsmodels.tsa.stattools import adfuller
adf = adfuller(diff_data, regression = 'ct')

# adf statistic
print(adf[0])

# p-value
print(adf[1])

# 차분하고 정상성을 갖춤
# ARIMA(p, d, q)의 파라미터 정하기
# ACF plot과 PACF plot을 통해 AR 및 MA의 모수를 추정함

# ACF : Lag에 따른 관측치들 사이의 관련성을 측정하는 함수
# PACF : k 이외의 모든 다른 시점 관측치의 영향력을 배제한 후, 두 관측치의 관련성을 측정하는 함수

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

plot_pacf(diff_data) # AR(p) 값 확인 가능

plot_acf(diff_data) # MA(q) 값 확인 가능

plt.show()
# 모형 만들기 ARIMA
trainig.price.values # 배열 형태로

from statsmodels.tsa.arima.model import ARIMA
import statsmodels.api as sm

model = ARIMA(training.price.values, order = (2,1,2), trend = 'ct')
res = model.fit()
res.summary()
# summary()를 통해 평가하기 어려움

plt.plot(res.predict())
plt.plot(training.price.values)

forecast_data = res.forecast(steps = len(test), alpha = 0.1)
# test 데이터 길이만큼 예측

pred_y = forecast_data
test_y = test.values

plt.plot(pred_y, color = 'gold')
plt.plot(test_y, color = 'green')
plt.show()
from sklearn.metrics import r2_score
r2_score(pred_y, test_y)

regid = pred_y - test_y

import numpy as np
np.sqrt(np.sum(regid**2)/len(test_y))