주요 개념
- Augmented Dickey-Fuller Test (ADF Test)
AR, MA, ARMA, ARIMA 모델을 적용하기 전, 우선 시계열 데이터를 정상성 데이터로 바꾼 후 사용하는 것이 바람직하다. 정상성을 띄기 위해선 시계열 데이터의 평균, 분산이 시간에 따라 일정해야 하고 lag에 따른 공분산이 일정해야 한다. 이를 위해 로그 변환을 해주거나 n차 차분을 적용해줄 수 있다. 시계열에 대한 자세한 사항은 여기를 참고하면 된다.
정상성에 대한 검증은 시각화를 하거나 상황에 대해 직관적인 판단을 통해 알 수 있지만 통계적인 정량적 방법으로 검증할 수 있는 방법을 사용하는 것이 데이터를 분석할 때 더 납득할 수 있는 방법이 될 것이다. 이를 위해 사용하는 방법 중 하나가 Augmented Dickey-Fuller Test (ADF Test)이다.
ADF test는 unit root test(단위근 테스트)방식으로 볼 수 있다. 보통 단위근 검정은 MA 모형과는 무관하고, AR이 포함된 모형과 연관이 있다. 단위근이란 시계열 데이터에는 시간에 따라 일정한 규칙을 가진다는 것을 가정하고 시작한다.
$$ y_t = a_1y_{t-1}+a_2y_{t-2}+a_3y_{t-3}+...+\epsilon_t $$
위 수식은 't시점의 확률변수는 t-1, t-2 시점의 확률변수와 관계를 가지면서 거기에 에러가 포함된 것'이라는 의미이다.
$$ m^p-m^{p-1}a_1-m^{p-2}a_2-...-a_p = 0 $$
여기서 m=1이 위 식의 근이 된다면 이때의 시계열 과정을 단위근을 가진다고 한다. 단위근 모형은 주로 복잡한 시계열 데이터를 단순하게나마 계산하려 할 때 사용된다. 이러한 단위근 검정은 차분의 차수를 구할 때 유용하게 이용될 수 있다.
AR에 관한 설명이 잠시 필요한데 여기선 간단하게 설명하고 넘어간다.
$$ X_t = \alpha X_{t-1}+a_t $$
위의 AR(1) 수식에서 \( \alpha \)가 단위근 1일 경우 비정상성을 띈다고 말한다. 따라서 1보다 작아야 정상성을 띈다 말할 수 있고 Dickey-Fuller Test도 이에 착안하여 수행된다. Dickey-Fuller Test는 다음 수식에서 귀무가설 \( (H0: \alpha=1) \) 을 통계적으로 검정하는 방법이다.
$$ y_t = c + \beta t + \alpha y_{t-1} + \phi \nabla y_{t-1} + e_t $$
\( c \)는 시계열 데이터의 레벨, \( \beta \)는 시계열 데이터의 추세항을 나타내며, 각 파라미터를 regression으로 추정하여 \( \alpha \)가 단위근을 가질 확률이 얼마나 되는지 검정하는 것이다. \( \alpha =1 \)이라면 단위근을 가지는 것이므로 stationary 하지 않다고 판단한다.
Augmented Dickey-Fuller Test는 Dickey-Fuller Test를 확장하여 \( p(Lag) \)의 차분만큼을 추가해 기존 test의 검정 능력을 더 강화한 것이다.
$$ y_t = c+\beta t+\alpha y_{t-1}-\pi_1∇y_{t−1}+...+\pi_p∇y_{t−p}+e_t $$
위의 DF Test에서 \( p(Lag) \)의 차분만큼 항이 추가된 것을 알 수 있고, DF Test와 귀무 가설은 똑같다. 즉, \( p(Lag) \)의 차분만큼 수식을 확장하여 \( \alpha \)의 여부를 판단한다. 따라서 \( t-p \)시점까지의 차분 경향성을 파악할 수 있으므로 주기를 가진 데이터에 대해서도 확장해서 정상성 여부를 판단할 수 있다. 귀무가설은 단위근이 존재(\( \alpha =1 )\)한다는 뜻이고, 이때 p-value가 5% 이하라면 귀무가설을 기각하고 대체가설을 선택할 수 있다.
아래는 python을 이용하여 ADF test를 진행한다. 이번에도 CO2 데이터를 이용하여 예제를 진행한다.
python의 statsmodels 라이브러리에서 adfuller를 이용하면 쉽게 구현할 수 있다. autolag 파라미터에서 AIC, BIC란 AIC나 BIC가 가장 낮게 나오는 \( p \)를 자동으로 설정하고 autolag를 이렇게 지정하였을 경우 maxlag에서 지정한 값이 무시된다. AIC, BIC는 likelihood(우도)와 관련이 있으므로 일단 존재 자체만 알고 넘어가자. autolag 파라미터를 비워두면 maxlag에서 지정한 값이 설정된다. maxlag 파라미터의 default는 \( 12*(nobs/100)^{1/4} \)이다. 자세한 내용은 관련 문서를 참고하기 바란다.
아래는 python을 이용한 ADF 구현이다.
from statsmodels.tsa.stattools import adfuller
## ADF
def ADF(data):
result = adfuller(data, autolag="AIC")
print("---- Adfuller ----")
print('ADF Statistic: %f' % result[0])
print('p-value: %1.10f' % result[1])
print('Lag: %d' % result[2])
print('observation: %d' % result[3])
print('Critical Values:')
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
ADF(data)
Original Data | 1차 차분 | |
ADF statistic | -1.877134 | -20.044668 |
p-value | 0.3428934189 | 0.0000000000 |
Lag | 1 | 0 |
observation | 498 | 498 |
Critical Values 1% | -3.444 | -3.444 |
Critical Values 5% | -2.867 | -2.867 |
Critical Values 10% | -2.570 | -2.570 |
확실히 그래프로도 확인이 되는 경우였고 ADF test 후 p-value값이 0.05이하이며, ADF statistic이 Critical Values보다 작으므로 정상성 시계열이 될 수 있다는 판단의 근거가 생겼다.
이번 경우에는 1차 차분 이후 뚜렷한 주기(cycle)가 보이지 않기 때문에 정상성을 나타내는 시계열로 사용할 수 있지만 간혹 차분 이후 test statistic과 p-value가 낮지만 주기를 띄는 경우가 있다. 의심이 된다면 ADF Test 수행 시 주기까지 Lag가 반영되지 않았을 수도 있으므로 adfuller의 maxlag 파라미터를 조정하여 테스트해볼 수 있다. 하지만 이런 시계열은 장기적으로 볼 때, 주기의 시작이나 끝은 예측할 수 없는 경우일 수 있으므로 해당 시계열 또한 정상성을 나타내는 시계열이라 판단할 수 있다.
아래는 전체 python 소스 코드이다.
import matplotlib.pyplot as plt
import pandas as pd
from statsmodels.tsa.stattools import adfuller
def draw_plot(data, data_diff):
plt.plot(data, label="Original")
plt.plot(data_diff, label="diff_1")
plt.suptitle("CO2", size=24)
plt.xlabel("Time")
plt.legend()
plt.show()
## ADF
def ADF(data):
result = adfuller(data, autolag="AIC")
print("---- Adfuller ----")
print('ADF Statistic: %f' % result[0])
print('p-value: %1.10f' % result[1])
print('Lag: %d' % result[2])
print('observation: %d' % result[3])
print('Critical Values:')
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
if __name__ == '__main__':
data = pd.DataFrame(pd.read_csv("co2_time_series.csv")["CO2"][:500])
data_diff = data.diff(axis=0).dropna()
draw_plot(data=data, data_diff=data_diff)
ADF(data_diff)
관련 포스트
2021.12.03 - [Data Science/Statistics] - [Python] 정상성(Stationarity)과 비정상성(Non-Stationary)
소스코드