ARIMA
AutoRegressive Integrated Moving Average
전통적 시계열 예측 모델. 정상성 가정.
AutoRegressive Integrated Moving Average
전통적 시계열 예측 모델. 정상성 가정.
ARIMA(AutoRegressive Integrated Moving Average)는 시계열 데이터의 패턴을 분석하고 미래 값을 예측하는 통계 모델입니다. ARIMA(p, d, q)에서 p는 자기회귀(AR) 차수, d는 차분(Differencing) 횟수, q는 이동평균(MA) 차수를 나타냅니다. 주가, 매출, 기온 등 시간에 따라 변하는 데이터 예측에 널리 사용됩니다.
ARIMA는 1970년대 Box와 Jenkins가 체계화하여 "Box-Jenkins 방법론"으로도 불립니다. 당시 경제 예측과 품질 관리 분야에서 혁신적인 방법론으로 자리잡았으며, 50년이 지난 지금도 시계열 분석의 기본 도구로 사용됩니다. 딥러닝 기반 시계열 모델(LSTM, Transformer)이 등장했지만, 데이터가 적거나 해석 가능성이 중요할 때는 여전히 ARIMA가 선호됩니다.
ARIMA 모델링의 핵심 단계는 정상성(Stationarity) 확보입니다. 시계열이 트렌드나 계절성을 가지면 차분을 통해 정상 시계열로 변환합니다. ADF(Augmented Dickey-Fuller) 검정으로 정상성을 확인하고, ACF/PACF 그래프로 p, q 값을 추정합니다. 계절성이 있으면 SARIMA(Seasonal ARIMA)를 사용합니다.
실무에서 ARIMA는 단기 수요 예측, 재고 관리, 금융 리스크 분석에 활용됩니다. 장점은 해석 가능하고 신뢰구간을 제공하며 적은 데이터로도 작동한다는 것입니다. 단점은 비선형 패턴 포착이 어렵고, 외부 변수(휴일, 이벤트)를 직접 반영하기 어렵습니다. 이를 보완하려면 ARIMAX나 Prophet 같은 확장 모델을 검토하세요.
"""
ARIMA 시계열 예측 예제
statsmodels와 pmdarima를 활용한 자동 파라미터 선택 및 예측
"""
import numpy as np
import pandas as pd
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.stattools import adfuller
import pmdarima as pm
import warnings
warnings.filterwarnings('ignore')
# 샘플 데이터 생성 (월별 매출 데이터 시뮬레이션)
np.random.seed(42)
dates = pd.date_range(start='2020-01-01', periods=48, freq='M')
trend = np.linspace(100, 200, 48)
seasonality = 20 * np.sin(np.linspace(0, 8*np.pi, 48))
noise = np.random.normal(0, 10, 48)
sales = trend + seasonality + noise
df = pd.DataFrame({'date': dates, 'sales': sales})
df.set_index('date', inplace=True)
print("=== 시계열 데이터 ===")
print(df.tail())
# 1. 정상성 검정 (ADF Test)
def check_stationarity(series):
result = adfuller(series)
print(f"\nADF Statistic: {result[0]:.4f}")
print(f"p-value: {result[1]:.4f}")
if result[1] < 0.05:
print("결론: 정상 시계열 (p < 0.05)")
return True
else:
print("결론: 비정상 시계열 - 차분 필요")
return False
print("\n=== 정상성 검정 ===")
is_stationary = check_stationarity(df['sales'])
# 2. Auto ARIMA로 최적 파라미터 자동 탐색
print("\n=== Auto ARIMA 파라미터 탐색 ===")
auto_model = pm.auto_arima(
df['sales'],
start_p=0, max_p=5,
start_q=0, max_q=5,
d=None, # 자동으로 차분 횟수 결정
seasonal=True, m=12, # 12개월 주기 계절성
start_P=0, max_P=2,
start_Q=0, max_Q=2,
trace=False,
error_action='ignore',
suppress_warnings=True,
stepwise=True
)
print(f"최적 모델: ARIMA{auto_model.order} x SARIMA{auto_model.seasonal_order}")
print(f"AIC: {auto_model.aic():.2f}")
# 3. 모델 학습 및 예측
train = df['sales'][:-6] # 마지막 6개월을 테스트로
test = df['sales'][-6:]
model = ARIMA(train, order=auto_model.order,
seasonal_order=auto_model.seasonal_order)
fitted = model.fit()
# 예측 (6개월)
forecast = fitted.get_forecast(steps=6)
predictions = forecast.predicted_mean
conf_int = forecast.conf_int()
print("\n=== 예측 결과 ===")
results = pd.DataFrame({
'실제값': test.values,
'예측값': predictions.values,
'하한(95%)': conf_int.iloc[:, 0].values,
'상한(95%)': conf_int.iloc[:, 1].values
}, index=test.index)
print(results.round(2))
# 4. 성능 평가
from sklearn.metrics import mean_absolute_error, mean_squared_error
mae = mean_absolute_error(test, predictions)
rmse = np.sqrt(mean_squared_error(test, predictions))
mape = np.mean(np.abs((test - predictions) / test)) * 100
print(f"\n=== 성능 지표 ===")
print(f"MAE: {mae:.2f}")
print(f"RMSE: {rmse:.2f}")
print(f"MAPE: {mape:.2f}%")
"월별 매출 데이터가 3년치 있으니 ARIMA로 시작해봅시다. 먼저 ADF 테스트로 정상성을 확인하고, ACF/PACF 분석으로 p, q를 추정합니다. 계절성이 뚜렷하면 SARIMA(p,d,q)(P,D,Q,12)로 확장해야 합니다."
"ARIMA의 한계는 선형성 가정과 외부 변수 반영 어려움입니다. 프로모션, 휴일 효과를 반영하려면 ARIMAX를 쓰거나, 요즘은 Prophet이 더 직관적입니다. 하지만 ARIMA의 장점은 신뢰구간 해석이 통계적으로 엄밀하다는 것입니다."
"현재 ARIMA 모델의 MAPE가 15%인데, 비즈니스 요구사항은 10% 이하입니다. 잔차 분석을 보면 특정 시점에 큰 오차가 있는데, 프로모션 기간과 일치합니다. 외생 변수를 추가하거나 하이브리드 모델을 검토해봅시다."
비정상 시계열에 ARIMA를 그대로 적용하면 spurious regression(가짜 관계)이 발생합니다. 반드시 ADF 검정으로 정상성을 확인하고, 필요시 차분을 적용하세요.
p, d, q 값을 너무 높게 설정하면 과적합됩니다. AIC, BIC 같은 정보 기준으로 모델을 비교하고, 잔차가 백색잡음인지 Ljung-Box 검정으로 확인하세요.
ARIMA는 단기 예측에 적합합니다. 예측 기간이 길어질수록 신뢰구간이 급격히 넓어지며 예측력이 떨어집니다. 12개월 이상 예측 시 다른 방법론을 병행하세요.