[ 오늘 배운 내용 ]
1. 시계열 분석 개요
- 시계열 분석과 시계열 데이터
- 시계열 모델링 종류
2. 시계열 전처리
3. 전통적 시계열 모델링
시계열 데이터란?
시계열 데이터 (Time Series data)
: 일정한 시간간격(등간격)의 연속된 흐름(순서)이 있는 데이터
Sequential data와 같이 쓰이긴 하지만 엄밀하게 말하면 Sequential data의 카테고리 안에 시계열 데이터가 있다고 할 수 있다.
Sequential data의 종류
- 음성
- 주가 데이터 (시계열)
- 문장 등
시계열 데이터 분석은 시간의 흐름에 따른 패턴을 분석하는 것이다.
시간의 흐름을(시계열 데이터를) 어떻게 정리하는지에 따라서 모델링 방식은
- 전통적 시계열 모델링
- 머신러닝 기반 시계열 모델링
- 딥러닝 기반 시계열 모델링
의 3가지로 나뉘어진다.
[ 전통적 시계열 모델링 ]
- y의 이전 시점 데이터들로부터 흐름의 패턴을 추출하여 예측 (y값의 흐름만 사용)
- x변수들은 사용하지 않음
[ 머신러닝 기반 시계열 모델링 ]
- 특정 시점 데이터들(1차원)과 예측대상시점( y^(t+1) )의 관계로부터 패턴을 추출하여 예측
- 시간의 흐름에 맞는 특정 시점에 대한 x변수를 추가 (Feature Engineering)
- 해당시점의 feature값들 + 특정시점의 feature값들 ==> 하나의 분석단위로
[ 딥러닝 기반 시계열 모델링 ]
- 특정 구간(timestep) 데이터들(2차원)과 예측대상시점( y^(t+1) )과의 관계로부터 패턴을 추출하여 예측
- 시간의 단위 흐름만큼 묶어서 컴퓨터에게 맡김
- 분석단위를 2차원으로 만드는 전처리 필요 (데이터셋은 3차원)
각 모델링 방법 별로 시간의 흐름을 어떻게 묶어서 정리하는지 그림으로 그려보았다.
시계열 모델링을 할때는 CRISP-DM 분석 방법론의 비즈니스 이해 (Business Understanding) 단계에서 다음의 사항들을 정리하고 갈 필요가 있다.
- 해결해야 할 비즈니스 문제는 무엇인가? (ex 주가예측을 해서 뭘 얻고자 하는건지?)
- 예측해야 할 것은 숫자인가, 숫자의 변화인가? (ex 주가 자체를 예측? 주가의 변동을 예측?)
[ 시계열 전처리 ]
시계열 데이터의 전처리 단계에서는 데이터가 일정하게 쌓여있는지 말고도 다음의 사항들을 확인해주어야 한다.
사전확인(Look-ahead) 오류
- 예측해야할 시점의 데이터가 현재 시점에 포함되어 분석 단위로 묶인 채로 분석 및 예측하는 오류
- 데이터를 통해서 예측해야하는 시점의 데이터를 이미 알아버리는 문제가 생겨서 말도 안되는 성능의 모델이 나오기 쉬움
- Feature들의 시점(t)과 Target의 시점(t+1)은 달라야 함
NaN조치
시계열 데이터는 데이터의 순서가 매우 중요하기 때문에 아무 값으로 NaN값을 채울 수 없다. NaN값을 조치할 때는 다음과 같은 방법으로 채워주어야 한다.
- 이전 값으로 채우기(ffill)
- 이후 값으로 채우기(bfill)
- 사이 값으로 채우기(.interpolate)
시계열 데이터의 train, val 분할
train_test_split()의 다음 옵션을 주어서 순서를 유지한 채로 train, validation 분할이 가능하다.
- test_size : 소수-비율, 자연수-갯수 로 분할
- shuffle=False : 섞지 않고 데이터 끝에서 test_size개수만큼 자름
예시 코드 - 맨 뒤의 30개 데이터를 validation set으로 분할
from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(x, y, test_size = 30, shuffle = False)
시계열 데이터의 K-fold cross validation
TimeSeriesSplit 사용
- Fold의 수와 Validation 사이즈를 결정하여 사용
- n_splits : fold수 (기본값 5)
from sklearn.model_selection import TimeSeriesSplit
참조파일 보고 공부하기
모델링 절차
시계열 데이터의 모델링 절차는 다음과 같다.
- y값 분석
- 모델 생성
- Train_err (잔차) 분석
- 검증(예측)
- 검증(평가) : 평가지표, val_err(잔차) 분석
모델을 생성한 뒤, 혹은 모델 평가 단계에서 train에 대한 오차, val에 대한 오차를 분석한 뒤 다시 모델을 튜닝할 수 있는데, 앞서 말한 train에 대한 오차, val에 대한 오차를 잔차 라고 한다.
모델을 기술적으로 분석할 때는 기존에 알던 RMSE, MAE와 같은 평가지표 말고도 잔차 분석을 수행해 줄 수 있는데, 시계열 모델링에서는 잔차 분석을 수행해주는 것이 중요하다.
잔차 분석에 대해 알아보자
잔차 분석
{ 실제값 = 모델 + 오차 }
XGBoost와 같은 모델들은 남아 있는 오차를 가지고 모델을 추가해준다. 이 때, 오차를 가지고 모델을 추가할 수 있다면 그것은 오차에 뭔가 패턴이 남아있다는 것을 말한다.
만약 모델이 잘 만들어 졌다면 잔차는 White Noise에 가까워야 한다.
우리가 하는 잔차 분석은 바로 남아 있는 오차(잔차) 안에 패턴이 남아있는지를 분석하는 것이다.
※ White Noise
- 시간의 흐름에 따라, 아무런 패턴이 없는 의미 없는 값들의 연속
- 더이상 무언가를 분석해낼 수 없는 값들 (패턴이 없는 값들)
White Noise의 특징 = @@잔차분석의 목적@@
- 정규분포
- 평균은 0 혹은 상수, 분산은 일정함
- 값들 간의 상관성이 없음 (ACF, PCAF == 0 )
잔차 분석 시에는 다음의 내용들을 수행한다.
- 잔차에 대한 우리의 기대 : White Noise (어떠한 패턴도 남아있지 X)
- 자기상관성 없음 : ACF, PACF 그래프
- 정규분포 : Shapiro-Wilk 검정
- 평균과 분산이 일정(Stationary) : ADF 검정
- 만약 White Noise가 아니라면
- 더 찾아내야 할 패턴이 있다는 것 (모델링을 더 할 필요가 있음)
ACF (자기상관함수)
- 특정 시점(yt)과 다른 이전 시점(yt-n) 간의 상관성
- 시간 단위n이 커질수록 ACF는 0에 근접
ACF 그래프를 그려보았을 때 가장 왼쪽에 있는 값은 자기 자신의 시점이기 때문에 상관계수가 1이 나온다.
다른 값들은 모두 다른 시점들의 상관계수이고, 파란색 경계영역(임계값) 안에 있는 값들은 자기상관성이 없다고 볼 수 있고, 영역을 벗어나는 값들은 잔차에 패턴이 남아있기 때문에 자기상관성이 있다고 볼 수 있다.
따라서 우리는 이 흐름을 벗어나는 값들을 찾아서 흐름 안으로 집어넣어주는 것을 목표로 해야 한다.
PACF (편자기상관함수)
- 특정 시점(yt)과 다른 이전 시점(yt-n) 간의 순수한 상관관계
- 다른 요인의 영향을 제거한 채로 상관관계를 구한 것
[ ACF(자기상관함수), PACF(편자기상관함수) 그래프 그리기 ]
plot_acf(), plot_pacf()를 사용해서 ACF, PACF의 자기상관함수 그래프를 그릴 수 있다.
먼저 학습한 모델의 잔차를 model.resid 로 구해준다.
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
residuals = model.resid # 잔차들 (train의 오차들)
- ACF 그래프
# ACF
plot_acf(residuals, lags = 20)
plt.show()
- PACF 그래프
# PACF
plot_pacf(residuals, lags = 20)
plt.show()
[ 정상성 (Stationary) ]
시간의 흐름에 따라서
- 평균 일정
- 분산 일정
- 특정 두 시점 간의 공분산 일정
정상(stationary) 데이터
- 평균과 분산이 상수이고
- ACF, PACF = 0 (자기상관성이 없는) 데이터
잔차 분석 - 검정
- 필요 모듈 임포트
import scipy.stats as spst
import statsmodels.api as sm
[ 정규성 검정 (Shapiro-wilk Test) ]
- 귀무가설 : 정규분포이다. (p-value > 0.05)
- 대립가설 : 정규분포가 아니다.
spst.shapiro(잔차)[1]로 p-value 확인
# 정규성 검정
spst.shapiro(residuals)[1]
# 0.006275390740483999
[ 정상성 검정 (ADF Test) ]
- 귀무가설 : 비정상(Non-Stationary) 데이터이다.
- 대립가설 : 정상(Stationary) 데이터이다. (p-value < 0.05)
# 정상성 검정
sm.tsa.stattools.adfuller(residuals)[1]
# 3.2372816266121326e-05
[ 전통적 시계열 모델링 - y의 흐름만으로 예측 ]
y의 흐름만으로 예측을 수행하는 전통적 시계열 모델링의 방법은
- AR, MA
- ARMA (AR + MA)
- ARIMA
- SARIMA
- SARIMAX (SARIMA + Linear Regression)
가 있다.
모두 y값만 사용하는 방법이지만 이를 더 개선하기 위해 Linear Regression을 SRAIMA 모델과 결합한 것이 SARIMAX 모델이다.
AR (Auto Regressive)
- 자기 자신을 target변수 y_t로 하고, 이전 시점의 데이터 y_t-1, y_t-2, ...를 feature변수로 갖는 모델
- 전제조건 : y가 Stationary(평균일정, 분산일정, 공분산일정)해야 함
- 하이퍼파라미터 p : 몇번째 이전 시점의 y까지 포함할지
MA (Moving Average)
- 자기 자신을 target변수 y_t로 하고, 해당 시점과 그 과거의 예측 오차들을 feature변수로 갖는 모델
- 전체 평균에다 오차를 기반으로 가중치를 곱해서 예측하는 방식임
- 전제조건 : y가 Stationary해야 함
- 하이퍼파라미터 q : 몇번째 이전 시점의 오차까지 포함할지
ARMA : AR + MA
- AR모델과 MA모델을 결합한 모델
- 전제조건 : y가 Stationary해야 함
ARIMA (Integration : 차분)
- ARMA에 데이터 차분을 포함시킨 모델
- 전제조건 : y가 Stationary해야 함 (차분 활용)
- 하이퍼파라미터 d : 몇 번 차분할지 (보통 1 혹은 2)
※ 차분 = 변화량
Stationary한 데이터를 사용하기 위해 차분 (변화량)으로 예측한다.
일반적으로 차분(변화량) 데이터는 Stationary함
[ ARIMA 모델링 ]
- sm.tsa.SARIMAX(train, order=( p,d,q )).fit() 로 모델링 할 수 있으며, order=(p,d,q)로 각각의 하이퍼파라미터를 지정해 줄 수 있다.
- d=0으로 지정할 경우 ARMA모델링과 같다.
import statsmodels.api as sm
m1_1 = sm.tsa.SARIMAX(y_train, order=(1,0,1)).fit() # d=0 ==> ARMA 모델링
m1_2 = sm.tsa.SARIMAX(y_train, order=(1,1,1)).fit() # ARIMA 모델링
- 각 모델의 잔차를 구하고 이를 사용해서 정규성, 정상성 검정과 자기상관성을 확인해보았다.
# 잔차 구하기
residuals = m1_1.resid
residuals = m1_2.resid
- AIC(아카이케 통계량)도 확인해보기
- AIC값은 작을수록 좋은 모델
- model.aic 로 구할 수 있다.
print('model1 AIC :', m1_1.aic)
print('model2 AIC :', m1_2.aic)
# model1 AIC : 5464.670363960708
# model2 AIC : 5442.769868773823
[ 예측 및 평가 ]
- .predict(n) : train 기간에 대한 예측
- .forecaset(n) : train 기간 이후에 대한 예측
- SARIMAX로 모델링했을 땐 .predict()가 아니라 .forecast()로 예측을 수행해준다.
pred = m1_1.forecast(30) # 예측하고자 하는 기간 : 30
print('MAE :', mean_absolute_error(y_val, pred))
print('MAPE:', mean_absolute_percentage_error(y_val, pred))
# MAE : 12.918460959652306
# MAPE: 0.12228691428354797
pred = m1_2.forecast(30)
print('MAE :', mean_absolute_error(y_val, pred))
print('MAPE:', mean_absolute_percentage_error(y_val, pred))
# MAE : 13.123421572150058
# MAPE: 0.12539084122967378
- train 데이터(y_train)에 대한 예측 결과는 .predict()로 확인 가능하다.
m1_1.predict() # y_train에 대해 예측한 결과 확인 가능
[ 예측결과 시각화 ]
예측 결과를 시각화해보면 그냥 평균 모델로 예측한것과 거의 비슷한 결과가 나온다.
따라서 하이퍼파라미터를 튜닝해줄 필요가 있다.
[ 하이퍼파라미터 튜닝 ]
원래 정석적인 방법은
- ACF가 선형적으로 감소하는 형태라면 ==> d를 1혹은 2로 (거의 1)
- PACF가 p+1차항부터 절단모양(급격히 0에 수렴)이면 ==> p=해당차수
- ACF가 q+1차항부터 절단모양(급격히 0에 수렴)이면 ==> q=해당차수
와 같은 식으로 튜닝을 하지만 실제로는 잘 안된다고 강사님이 말씀하셨다.
따라서 아래의 방법으로 하이퍼파라미터를 튜닝해보자
- y에 대해서 ACF, PACF를 그리고
- AR, MA의 하이퍼파라미터 차수를 추측 (시작은 작게)
- (초기)모델 생성 ==> order=(1,1,1), order=(1,0,1) 등
- 잔차 분석
- 하이퍼파라미터 (조금씩) 조정 ==> 3.번 과정으로 이동하여 반복
- 적절한 결과가 나오면 멈춤
SARIMAX()로 만든 모델은 GridSearchCV()로 튜닝할 수 없기 때문에 수동으로 p,d,q값을 여러 조합으로 넣어보면서 그리드서치와 유사하게 튜닝 해주어야 한다.
Auto ARIMA라는 함수로 그리드서치와 유사한 과정을 자동화할 수 있다고 하는데 잘 안된다고 함
(코드는 5주차 18과파일 참고)
튜닝한 모델로 다시 확인해보았더니
훨씬 나아진 예측 결과를 볼 수 있다.
잔차의 패턴은 많이 사라졌지만 7일 주기로 튀는 값들이 여전히 조금씩 남아 있기 때문에 이를 해결해주어야 한다.
7일 주기와 같은 사이클을 Seasonality(계절성) 이라고 한다.
이러한 계절성(=주기가 있는) 데이터를 제대로 모델링 하기 위해 Seasonality의 S를 ARIMA에 담아준 모델이 바로 SARIMA이다.
SARIMA (Seasonality : 계절성)
- 주로 Trend를 모델링하는 ARIMA의 한계를 개선시키기 위해 ARIMA에 계절성을 포함시킨 모델
- 하이퍼파라미터 (P, D, Q)m : P,D,Q ==> m(주기단위)에 따른 p,d,q
※ 주기성이 없게 튀는 값은 p,q로 해결
※ 주기성이 있게 튀는 값은 P,Q로 해결
[ SARIMA 모델링 ]
- 기존의 ARIMA 모델링과 동일한데 seasonal_order=(P,D,Q,m) 으로 SARIMA의 계절성 관련 하이퍼파라미터를 추가해준다.
- sm.tsa.SARIMAX(y_train, order=(p,d,q), seasonal_order=(P,D,Q,m)).fit()
# SARIMA 모델링
m2_1 = sm.tsa.SARIMAX(y_train, order=(3,1,3), seasonal_order=(1,1,1,7)).fit() # seasonal_order=(P,D,Q,m) m:주기
# AIC 통계량 확인
print('model2_0 AIC :', m2_1.aic)
# model2_0 AIC : 4846.302440142703
# Validation
pred = m2_1.forecast(30)
print('MAE :', mean_absolute_error(y_val, pred))
print('MAPE:', mean_absolute_percentage_error(y_val, pred))
# MAE : 7.942958528277967
# MAPE: 0.0733998184034363
모델링 후 잔차분석을 수행해보면 주기성이 많이 사라지고, 결과 모양도 더 나아진 것을 볼 수 있다.
[ SARIMA 모델 튜닝 ]
- ARIMA의 최적 p,d,q값을 찾고
- ACF, PACF에서 주기를 확인(그래프 사용해야 함)하고 m 결정
- p,d,q의 최적화와 유사한 방식으로 P,D,Q 최적화
위의 방법과 동일하게 P,D,Q의 튜닝을 해준 뒤, mae와 aic의 결과를 확인해보았더니
mae는 (3,1,1)일 때
aic는 (1,1,1)일 때
가장 작은 값이 나왔다.
둘 중 어느 조합을 써도 상관은 없지만 만약 차수가 너무 커질 경우 과적합의 위험이 있다는 것을 알아두자.
과적합을 확인하기 위해 AIC값을 확인해준다. (aic값이 가장 작은 지점 사용)
p,d,q와 P,D,Q 6개의 하이퍼파라미터를 한꺼번에 조정하는 것은 오래 걸리기 때문에
ARIMA를 먼저 튜닝 ==> SARIMA를 튜닝 해주는 절차를 밟아주자.
[ 튜닝 결과 ]
더 정교한 모델링을 하기 위해 ==> X변수를 추가한 SARIMAX 모델 사용
SARIMAX (X : features ==> Linear Regression 결합)
- SARIMA 모형에서 Linear Regression을 결합한 모델
- X변수들도 사용한다.
- 앙상블 모델이라고 볼 수 있다.
[ SARIMAX 모델링 ]
- 학습 : sm.tsa.SARIMAX(y_train, order=(p,d,q), seasonal_order=(P,D,Q,m), exog=x_train).fit()
- 예측 : model.forecast(val_size, exog=x_val)
# SARIMAX 모델링
m3_1 = sm.tsa.SARIMAX(y_train, order=(4,1,4), seasonal_order=(1,1,1,7), exog=x_train).fit()
# AIC 통계량 확인
print('m3_1 AIC :', m3_1.aic)
# m3_1 AIC : 4822.819382800159
# Validation
pred = m3_1.forecast(30, exog=x_val)
print('MAE :', mean_absolute_error(y_val, pred))
print('MAPE:', mean_absolute_percentage_error(y_val, pred))
# MAE : 7.790412607901317
# MAPE: 0.07225423363030757
'KT AIVLE School' 카테고리의 다른 글
(9주차 - 22.09.13) 딥러닝1 - Tensorflow + Keras (선형회귀, 로지스틱회귀, 멀티클래스분류) (0) | 2022.09.13 |
---|---|
(7주차 - 22.09.05 ~ 22.09.06) AI모델 해석/평가 (0) | 2022.09.05 |
(5주차 - 22.08.26) 머신러닝5 - 비지도학습 (0) | 2022.08.26 |
(5주차 - 22.08.25) 머신러닝4 - 모델 성능 향상, 앙상블 (0) | 2022.08.26 |
(5주차 - 22.08.24) 머신러닝3 - 결정트리,SVM,모델성능튜닝 (0) | 2022.08.25 |