ARIMA(Autoregressive Integrated Moving Average)
비정상 시계열 데이터를 분석하여 미래 값을 예측하는데 효과적이며 추세 및 계절성 패턴을 내재적으로 처리할 수 있다는 장점이 있습니다.
3가지 구성
- AR 모형: 과거 p시점까지 자신의 값에 의존한다고 가정, 차수 p를 결정
- I(Integrated): 비정상을 정상으로 만들기 위해 차분을 하는 횟수(d)를 결정
- MA 모형: 현재 시점의 예측오차가 과거 q 시점 까지의 예측오차에 의존한다고 가정 , 차수 q를 결정
- 각 모형에서의 차수를 인수로 ARIMA(p, d, q) 모형을 생성
ARIMA 모형은 차분을 통해 비정상을 정상시계열로 변환하고 AR 및 MA 성분으로 시계열 데이터의 고유한 패턴(자기상관성, 과거오차의 영향)을 모델링합니다.
모형 구축단계
- 정상성확인 : 비정상인 경우 차분을 통해 정상화합니다.
- 차수 p,d,q를 결정 (auto_arima와 같은 자동 차수 결정함수를 활용할 수 있음)
- ARIMA 모형 추정
- 잔차분석 등을 통해 모형의 적합성을 평가, 잔차 백색잡음(평균이 0, 일정한 분산으로 자시 상관이 없음)의 성질을 가지는지를 확인
- ACF, PACF, 히스토그램, QQ 플롯 등을 통해 확인할 수 있음
- Ljung-Box test과 같은 통계적 검정을 사용하여 잔차에 자기 상관 검정
- 예측
- 이상치 및 예측치 못한 이벤트에 의해 예측성능이 저하될 수 있음
- 과거패턴을 기반으로 함으로서 장기예측의 정확도는 떨어질 수 있음
- 명시적인 계절성을 다루는데 한계가 있음. 계절성 ARIMA(SARIMA) 모형 사용
정상성 검정
- 데이터의 추세가 없음
- ACF 플롯은 빠르게 0으로 수렴하는 형태
- 단위근 검정(통계적 검정)
- ADF (Augmented Dickey-Fuller) 검정, KPSS
- (Kwiatkowski-Phillips-Schmidt-Shin) 검정 등
p, d, q의 특성
- 데이터의 정상화를 위해 차분하는 횟수가 d
- ACF
- MA(q): q차 이후 급격히 0으로 떨어짐
- AR(p): 점차적으로 감소
- PACF
- AR(p): p차 이후 급격히 0으로 떨어짐
- MA(q): 점진적 감소
ACF와 PACF 플롯 해석은 주관적일 수 있으며, 명확한 패턴이 나타나지 않는 경우도 많습니다. 여러 후보 모형을 고려해야 합니다. ARIMA(p, d, q) 모형의 AIC/BIC등의 정보기준(Information Criteria)를 비교하여 최적 모형을 선택해야 합니다. 일반적으로 AIC는 단기예측에 적합한 모형, BIC는 장기예측 및 간결한 모형을 선택하는 경향이 있습니다.
import numpy as np import pandas as pd import FinanceDataReader as fdr import matplotlib.pyplot as plt from statsmodels.tsa.stattools import acf, pacf from statsmodels.graphics.tsaplots import plot_acf, plot_pacf from sklearn.metrics import mean_squared_error from statsmodels.tsa.seasonal import seasonal_decompose from statsmodels.tsa.stattools import adfuller, kpss #정상성 검정 from statsmodels.tsa.ar_model import AutoReg #AR모형 from statsmodels.graphics.tsaplots import plot_acf, plot_pacf from statsmodels.tsa.arima.model import ARIMA from pmdarima import auto_arima from statsmodels.stats.diagnostic import acorr_ljungbox #잔차의 자기상관 검정
st=pd.Timestamp(2024,9, 1) et=pd.Timestamp(2025, 5,7) trgnme="000660" trg=fdr.DataReader(trgnme, st, et)[["Open", "High", "Low", "Close", "Volume"]] trg.tail(3)
Open | High | Low | Close | Volume | |
---|---|---|---|---|---|
Date | |||||
2025-04-30 | 179100 | 180000 | 176700 | 177500 | 2354473 |
2025-05-02 | 179400 | 186200 | 178400 | 186000 | 3886874 |
2025-05-07 | 187700 | 191500 | 185900 | 190800 | 3830097 |
시계열 데이터의 경우 날짜 인덱스에 일정한 주기를 가져야 합니다. 그러므로 다음과 같이 위 자료의 인덱스에 주기 "B"를 지정합니다. "B"는 business day를 의미합니다.
close=trg["Close"] close=close.asfreq('B') close.index
DatetimeIndex(['2024-01-02', '2024-01-03', '2024-01-04', '2024-01-05', '2024-01-08', '2024-01-09', '2024-01-10', '2024-01-11', '2024-01-12', '2024-01-15', ... '2025-04-21', '2025-04-22', '2025-04-23', '2025-04-24', '2025-04-25', '2025-04-28', '2025-04-29', '2025-04-30', '2025-05-01', '2025-05-02'], dtype='datetime64[ns]', name='Date', length=349, freq='B')
다음은 자료에 null 값의 포함여부를 조사합니다.
close=close.ffill() close.isnull().sum()
0
위 자료를 시각화 합니다.
plt.figure(figsize=(10, 3)) plt.plot(close) plt.xlabel("date") plt.ylabel("price") plt.grid(True) plt.show()
위 자료의 정상화를 검정하기 위해 ADF 검정을 실시합니다.
cl_station=adfuller(close, autolag="AIC") cl_station[1] #p-value
0.141527029642237
위 결과에서 p-value가 0.05 보다 크므로 귀무가설(단위근을 갖음)기각 할 수 없음. 즉 정상시계열이 아니므로 1차차분을 실행합니다.
close_diff = close.diff().dropna() plt.figure(figsize=(10, 3)) plt.plot(close_diff) plt.xlabel("date") plt.ylabel("price") plt.grid(True) plt.show()
adfuller(close_diff, autolag="AIC")[1]
4.1330149937903725e-24
위 결과에 의하면 p-value가 0.05보다 매우 작습니다. 즉, 귀무가설을 기각할 수 있으므로 1차차분된 데이터는 정상 시계열이라 할 수 있습니다.
차분된 데이터의 p, q 값을 결정하기 위해 PACF와 ACF 그래프를 작성합니다.
f,axs=plt.subplots(1,2, figsize=(10, 3)) plot_acf(close_diff, lags=20, ax=axs[0], title="ACF") plot_pacf(close_diff, lags=20, ax=axs[1], title="PACF") plt.show()
ACF는 1차 이후 0에 수렴함을 보이므로 MA(q)의 q를 0, PACF는 1차 이후 0에 수렴함을 보이므로 AR(p)의 p를 0 으로 결정할 수 있습니다. p, q를 모두 0으로 지정할 경우 랜덤워크 모형입니다. 즉, AR, MA 모형이 필요없음을 의미합니다. 그러나 실제 시계열이 랜덤워크 모델에 완전히 적합하지 않기 때문에 AIC 또는 BIC를 기준으로 p, q를 결정할 수 있습니다. 즉, arima(0,1,0)에 근접한 AIC등의 정보를 제공하는 차수를 지정합니다. auto_arima()
함수를 적용합니다.
model=auto_arima(close, d=1, start_P=0, start_q=0, max_p=5, max_q=5, stepwise=True, trace=True, error_action='ignore', suppress_warnings=True) print(model.summary())
Performing stepwise search to minimize aic ARIMA(2,1,0)(0,0,0)[0] intercept : AIC=3581.635, Time=0.08 sec ARIMA(0,1,0)(0,0,0)[0] intercept : AIC=3583.557, Time=0.01 sec ARIMA(1,1,0)(0,0,0)[0] intercept : AIC=3584.987, Time=0.02 sec ARIMA(0,1,1)(0,0,0)[0] intercept : AIC=3584.924, Time=0.02 sec ARIMA(0,1,0)(0,0,0)[0] : AIC=3581.604, Time=0.01 sec ARIMA(1,1,1)(0,0,0)[0] intercept : AIC=3584.391, Time=0.05 sec Best model: ARIMA(0,1,0)(0,0,0)[0] Total fit time: 0.205 seconds SARIMAX Results ============================================================================== Dep. Variable: y No. Observations: 178 Model: SARIMAX(0, 1, 0) Log Likelihood -1789.802 Date: Thu, 08 May 2025 AIC 3581.604 Time: 14:59:31 BIC 3584.781 Sample: 09-02-2024 HQIC 3582.893 - 05-07-2025 Covariance Type: opg ============================================================================== coef std err z P>|z| [0.025 0.975] ------------------------------------------------------------------------------ sigma2 3.533e+07 2.97e+06 11.909 0.000 2.95e+07 4.11e+07 =================================================================================== Ljung-Box (L1) (Q): 0.09 Jarque-Bera (JB): 10.16 Prob(Q): 0.76 Prob(JB): 0.01 Heteroskedasticity (H): 0.91 Skew: -0.03 Prob(H) (two-sided): 0.73 Kurtosis: 4.17 =================================================================================== Warnings: [1] Covariance matrix calculated using the outer product of gradients (complex-step).
위 결과로 부터 arima(2,1,0) 모형을 선택합니다.
mod=ARIMA(close, order=(2,1,0)).fit() residuals=mod.resid f, axs=plt.subplots(1,2, figsize=(10, 3)) plot_acf(residuals, lags=20, ax=axs[0], title="residual ACF") plot_pacf(residuals, lags=20, ax=axs[1], title="residual PACF") plt.show()
lb_test=acorr_ljungbox(residuals, lags=[10]) lb_test
lb_stat | lb_pvalue | |
---|---|---|
10 | 0.671066 | 0.999973 |
위 잔차의 ACF, PACF 모두 유의미한 상관이 나타나지 않았음 , 륭-박스 검정에서 p-value는 유의수준(0.05) 보다 크므로 귀무가설(백색잡음임)을 기각 할 수 없습니다. 그러므로 위 모형은 적절하게 적합되었다고 할 수 있습니다.
pre_data=mod.predict(start=0, end=len(close)-1) pre_data
Date 2024-09-02 0.000000 2024-09-03 169880.708340 2024-09-04 156210.649009 2024-09-05 155564.960370 2024-09-06 160256.618422 ... 2025-05-01 177673.002310 2025-05-02 177738.760729 2025-05-05 185778.020627 2025-05-06 185385.010244 2025-05-07 186000.000000 Freq: B, Name: predicted_mean, Length: 178, dtype: float64
plt.figure(figsize=(10, 3)) plt.plot(close, label="orignal") plt.plot(pre_data[1:], label="predict") plt.grid(True) plt.show()
mod.forecast(steps=5)
2025-05-08 190674.646942 2025-05-09 190330.632232 2025-05-12 190348.685764 2025-05-13 190373.104353 2025-05-14 190371.160452 Freq: B, Name: predicted_mean, dtype: float64
mod.predict(start=len(close), end=len(close)+5)
2025-05-08 190674.646942 2025-05-09 190330.632232 2025-05-12 190348.685764 2025-05-13 190373.104353 2025-05-14 190371.160452 2025-05-15 190369.444490 Freq: B, Name: predicted_mean, dtype: float64
댓글
댓글 쓰기