🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

AR, MA, ARMA 모델 이해하기 - 슬라이드 1/9
A

AI Generated

2025. 12. 3. · 11 Views

AR, MA, ARMA 모델 이해하기

시계열 데이터 분석의 핵심인 AR, MA, ARMA 모델을 초급 개발자도 이해할 수 있도록 쉽게 설명합니다. 주식 가격 예측부터 판매량 분석까지, 실무에서 바로 활용할 수 있는 시계열 분석의 기초를 다룹니다.


목차

  1. 시계열_데이터란_무엇인가
  2. 정상성의_개념
  3. AR_모델_자기회귀
  4. MA_모델_이동평균
  5. ACF와_PACF_이해하기
  6. ARMA_모델_완성
  7. 모델_진단과_검증
  8. 실전_예측_수행하기

1. 시계열 데이터란 무엇인가

어느 날 김개발 씨는 쇼핑몰 운영팀으로부터 긴급한 요청을 받았습니다. "다음 달 판매량을 예측해주세요.

재고를 미리 준비해야 해서요." 김개발 씨는 고민에 빠졌습니다. 지난 1년간의 판매 데이터는 있는데, 이걸로 어떻게 미래를 예측할 수 있을까요?

시계열 데이터란 시간 순서에 따라 기록된 데이터를 말합니다. 마치 일기장처럼 매일매일 기록된 데이터가 쌓여서 하나의 흐름을 만드는 것입니다.

이 흐름을 분석하면 과거 패턴을 바탕으로 미래를 예측할 수 있습니다.

다음 코드를 살펴봅시다.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 시계열 데이터 생성 예시
dates = pd.date_range(start='2024-01-01', periods=365, freq='D')
# 기본 트렌드 + 계절성 + 노이즈
trend = np.linspace(100, 150, 365)
seasonality = 20 * np.sin(2 * np.pi * np.arange(365) / 30)
noise = np.random.normal(0, 5, 365)

sales = trend + seasonality + noise
ts_data = pd.Series(sales, index=dates)
print(ts_data.head(10))

김개발 씨는 입사 6개월 차 데이터 분석가입니다. 오늘 받은 미션은 쇼핑몰의 다음 달 판매량을 예측하는 것이었습니다.

엑셀 파일을 열어보니 지난 1년간 매일의 판매 기록이 빼곡히 적혀 있었습니다. 선배 개발자 박시니어 씨가 다가와 물었습니다.

"혹시 시계열 분석에 대해 들어본 적 있어요?" 김개발 씨가 고개를 갸웃거리자, 박시니어 씨가 설명을 시작했습니다. "시계열 데이터라는 건 쉽게 말해서 시간 순서대로 기록된 데이터예요.

우리가 매일 쓰는 일기장을 생각해보세요. 1월 1일, 1월 2일, 1월 3일...

이렇게 날짜별로 기록이 쌓이잖아요." 일기장의 비유는 정확했습니다. 시계열 데이터도 마찬가지로 시간이라는 축을 따라 데이터가 나열됩니다.

주식 가격, 기온 변화, 웹사이트 방문자 수, 그리고 쇼핑몰 판매량까지 모두 시계열 데이터입니다. 그렇다면 왜 시계열 데이터가 특별할까요?

일반적인 데이터 분석과 달리, 시계열 데이터는 순서가 매우 중요합니다. 오늘의 판매량은 어제의 판매량과 관련이 있고, 어제의 판매량은 그저께와 관련이 있습니다.

이런 시간적 연속성 때문에 특별한 분석 방법이 필요합니다. 위의 코드를 살펴보면, 먼저 1년치 날짜 데이터를 생성합니다.

그 다음 세 가지 요소를 합쳐서 가상의 판매 데이터를 만듭니다. 트렌드는 전체적인 상승 또는 하락 경향이고, 계절성은 반복되는 패턴이며, 노이즈는 예측 불가능한 무작위 변동입니다.

실제 현업에서는 어떨까요? 아마존이나 쿠팡 같은 이커머스 기업들은 시계열 분석을 통해 재고를 관리합니다.

블랙프라이데이 시즌에 얼마나 많은 물건이 팔릴지 미리 예측해서 창고에 물건을 쌓아두는 것입니다. 시계열 분석에서 주의할 점도 있습니다.

데이터에 빈 날짜가 있거나, 시간 간격이 불규칙하면 분석 결과가 왜곡될 수 있습니다. 따라서 데이터 전처리 단계에서 이런 문제를 먼저 해결해야 합니다.

박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. 이제 시계열이 무엇인지 알았으니, 다음 단계는 이 데이터를 분석하는 방법을 배우는 것입니다.

실전 팁

💡 - 시계열 데이터는 반드시 시간 순서대로 정렬되어 있어야 합니다

  • 결측치가 있으면 보간법으로 채우거나 해당 구간을 제외해야 합니다
  • 데이터 시각화를 먼저 해보면 패턴을 직관적으로 파악할 수 있습니다

2. 정상성의 개념

김개발 씨가 시계열 데이터를 그래프로 그려보았습니다. 그런데 박시니어 씨가 그래프를 보더니 한숨을 쉬었습니다.

"이 데이터는 아직 분석할 준비가 안 됐어요. 먼저 정상성을 확인해야 해요." 정상성이라니, 그게 대체 무엇일까요?

정상성이란 시계열 데이터의 통계적 특성이 시간에 따라 변하지 않는 성질을 말합니다. 마치 고요한 호수처럼 전체적인 수준이 일정하게 유지되어야 합니다.

AR, MA, ARMA 모델은 정상성을 가진 데이터에서만 제대로 작동합니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.stattools import adfuller
import pandas as pd
import numpy as np

# 비정상 시계열 (추세가 있는 데이터)
non_stationary = np.cumsum(np.random.randn(100)) + 50

# ADF 검정으로 정상성 확인
result = adfuller(non_stationary)
print(f'ADF 통계량: {result[0]:.4f}')
print(f'p-value: {result[1]:.4f}')

# p-value가 0.05보다 크면 비정상 시계열
if result[1] > 0.05:
    print("비정상 시계열입니다. 차분이 필요합니다.")
else:
    print("정상 시계열입니다.")

김개발 씨는 궁금해졌습니다. 왜 굳이 정상성이라는 것을 확인해야 할까요?

박시니어 씨가 칠판에 그림을 그리며 설명했습니다. "호수를 상상해보세요.

고요한 호수는 수면의 높이가 대체로 일정해요. 바람이 불면 잔물결이 생기지만, 전체적인 수준은 변하지 않죠.

이게 바로 정상 시계열이에요." 반면 계속 물이 차오르는 댐을 생각해보면 어떨까요? 수면의 높이가 계속 올라가기 때문에, 어제 관측한 패턴으로 내일을 예측하기가 어렵습니다.

이것이 비정상 시계열입니다. 정상성의 조건은 세 가지입니다.

첫째, 평균이 시간에 따라 일정해야 합니다. 둘째, 분산도 일정해야 합니다.

셋째, 자기공분산은 시간 간격에만 의존해야 합니다. 실무에서 만나는 대부분의 데이터는 비정상 시계열입니다.

주식 가격은 계속 오르거나 내리고, 회사의 매출은 성장하거나 감소합니다. 이런 데이터를 그대로 모델에 넣으면 엉뚱한 결과가 나옵니다.

위의 코드에서는 ADF 검정을 사용합니다. ADF는 Augmented Dickey-Fuller의 약자로, 시계열이 정상성을 가지는지 통계적으로 검증하는 방법입니다.

검정 결과에서 p-value가 0.05보다 작으면 정상 시계열로 판단합니다. 반대로 0.05보다 크면 비정상 시계열이므로 차분이라는 전처리가 필요합니다.

차분이란 현재 값에서 이전 값을 빼는 것입니다. 원래 데이터가 100, 105, 108이었다면, 차분 후에는 5, 3이 됩니다.

이렇게 하면 추세가 제거되어 정상 시계열로 변환됩니다. 김개발 씨가 자신의 판매 데이터에 ADF 검정을 적용해보았습니다.

예상대로 p-value가 0.3으로 나왔습니다. 비정상 시계열이었던 것입니다.

"걱정 마세요. 차분을 한 번 하면 대부분 정상성을 얻을 수 있어요." 박시니어 씨의 조언에 김개발 씨는 안심했습니다.

실전 팁

💡 - ADF 검정의 p-value가 0.05 미만이면 정상 시계열입니다

  • 비정상 시계열은 차분을 통해 정상 시계열로 변환할 수 있습니다
  • 시각적으로 평균선이 수평에 가까우면 정상성을 의심해볼 수 있습니다

3. AR 모델 자기회귀

김개발 씨가 드디어 본격적인 시계열 모델을 배우기 시작했습니다. 박시니어 씨가 첫 번째로 소개한 것은 AR 모델이었습니다.

"오늘 판매량이 궁금해요? 어제랑 그저께 판매량을 보면 알 수 있어요." 과거의 나 자신이 미래의 나를 설명한다니, 신기한 개념이었습니다.

AR 모델은 Auto-Regressive의 약자로, 과거 자기 자신의 값으로 현재 값을 예측하는 모델입니다. 마치 어제의 기분이 오늘의 기분에 영향을 주는 것처럼, 시계열 데이터도 과거 값이 현재 값에 영향을 줍니다.

AR(p) 모델에서 p는 몇 시점 전까지 참고할지를 나타냅니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.ar_model import AutoReg
import numpy as np
import pandas as pd

# 샘플 데이터 생성 (AR(2) 과정)
np.random.seed(42)
n = 200
data = [0, 0]
for i in range(2, n):
    # Y_t = 0.7*Y_{t-1} + 0.2*Y_{t-2} + noise
    value = 0.7 * data[i-1] + 0.2 * data[i-2] + np.random.randn()
    data.append(value)

# AR 모델 학습 (lag=2)
model = AutoReg(data, lags=2)
fitted = model.fit()
print(fitted.summary())

# 향후 5개 시점 예측
forecast = fitted.predict(start=len(data), end=len(data)+4)
print(f"\n예측값: {forecast.values}")

박시니어 씨가 흥미로운 질문을 던졌습니다. "김개발 씨, 오늘 컨디션이 어때요?" "음, 어제 야근해서 좀 피곤하네요." "맞아요.

오늘의 컨디션은 어제의 상태와 관련이 있죠. 이게 바로 자기회귀의 핵심이에요." AR 모델, 즉 자기회귀 모델은 과거의 나 자신이 현재의 나를 설명한다는 아이디어에서 출발합니다.

시계열 데이터에서 현재 시점의 값은 이전 시점들의 값에 의해 영향을 받습니다. 수학적으로 표현하면 이렇습니다.

AR(1) 모델은 바로 직전 값 하나만 사용하고, AR(2) 모델은 직전 두 개의 값을 사용합니다. 여기서 괄호 안의 숫자 p를 차수라고 부릅니다.

코드를 살펴보면, 먼저 AR(2) 과정을 따르는 가상의 데이터를 생성합니다. 현재 값이 직전 값의 0.7배와 그 전 값의 0.2배, 그리고 약간의 노이즈로 구성됩니다.

AutoReg 함수에 lags=2를 전달하면 AR(2) 모델이 학습됩니다. 학습된 모델은 과거 패턴을 기억하고, 이를 바탕으로 미래를 예측합니다.

실무에서 AR 모델은 언제 유용할까요? 관성이 있는 데이터에 적합합니다.

예를 들어 체온은 급격히 변하지 않고 서서히 변합니다. 이런 경우 어제 체온이 오늘 체온을 예측하는 데 좋은 지표가 됩니다.

하지만 AR 모델에도 한계가 있습니다. 외부 충격에 대한 반응을 모델링하기 어렵습니다.

갑자기 발생한 이벤트가 데이터에 미치는 영향은 AR만으로 설명하기 힘듭니다. 김개발 씨가 물었습니다.

"그럼 차수 p는 어떻게 정하나요?" "좋은 질문이에요. PACF, 즉 편자기상관함수 그래프를 그려보면 알 수 있어요.

그래프가 급격히 떨어지는 지점이 적절한 차수예요."

실전 팁

💡 - AR 모델의 차수 p는 PACF 그래프로 결정합니다

  • 데이터에 관성이 있을 때 AR 모델이 효과적입니다
  • 차수가 너무 높으면 과적합 위험이 있으니 주의하세요

4. MA 모델 이동평균

AR 모델을 배운 김개발 씨에게 박시니어 씨가 두 번째 모델을 소개했습니다. "AR이 과거의 값을 보는 거라면, MA는 과거의 실수를 본다고 생각하면 돼요." 과거의 실수라니, 무슨 의미일까요?

김개발 씨는 호기심이 생겼습니다.

MA 모델은 Moving Average의 약자로, 과거의 오차를 사용하여 현재 값을 예측합니다. 여기서 오차란 예측과 실제 값의 차이입니다.

마치 요리사가 간을 볼 때 어제 너무 짜게 했으면 오늘은 소금을 덜 넣는 것처럼, 과거의 실수를 보정하여 예측합니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.arima.model import ARIMA
import numpy as np

# 샘플 데이터 생성 (MA(2) 과정)
np.random.seed(42)
n = 200
errors = np.random.randn(n)
data = []

for i in range(n):
    if i == 0:
        value = errors[i]
    elif i == 1:
        value = errors[i] + 0.6 * errors[i-1]
    else:
        # Y_t = e_t + 0.6*e_{t-1} + 0.3*e_{t-2}
        value = errors[i] + 0.6*errors[i-1] + 0.3*errors[i-2]
    data.append(value)

# MA(2) 모델 학습 (ARIMA의 order=(0,0,2))
model = ARIMA(data, order=(0, 0, 2))
fitted = model.fit()
print(fitted.summary())

박시니어 씨가 재미있는 비유를 들었습니다. "요리를 한다고 생각해보세요.

어제 된장찌개를 끓였는데 너무 짰어요. 그래서 오늘은 소금을 덜 넣었죠.

이게 바로 MA의 원리예요." MA 모델에서 중요한 것은 오차, 즉 잔차입니다. 잔차란 우리가 예측한 값과 실제 값의 차이를 말합니다.

MA 모델은 이 잔차들의 패턴을 학습합니다. AR 모델이 "어제 판매량이 높았으니 오늘도 높겠지"라고 생각한다면, MA 모델은 "어제 예측이 빗나갔으니 오늘은 그만큼 보정해야지"라고 생각합니다.

MA(q) 모델에서 q는 몇 시점 전의 오차까지 고려할지를 나타냅니다. MA(1)은 직전 오차만, MA(2)는 직전 두 개의 오차를 사용합니다.

코드를 보면 ARIMA 함수를 사용합니다. ARIMA의 order 파라미터는 (p, d, q) 형태인데, 여기서 p=0, d=0, q=2로 설정하면 순수한 MA(2) 모델이 됩니다.

MA 모델은 언제 유용할까요? 갑작스러운 충격이 있을 때 효과적입니다.

예를 들어 광고를 시작했는데 효과가 예상보다 컸다면, 그 충격이 며칠간 영향을 미칩니다. MA 모델은 이런 충격의 여파를 잘 포착합니다.

반면 MA 모델의 단점도 있습니다. 데이터의 장기적인 패턴을 포착하기 어렵습니다.

천천히 변하는 트렌드보다는 갑작스러운 변동에 더 민감합니다. 김개발 씨가 질문했습니다.

"그럼 MA의 차수 q는 어떻게 정하나요?" "이번엔 ACF, 자기상관함수 그래프를 봐야 해요. AR은 PACF, MA는 ACF라고 기억하면 돼요."

실전 팁

💡 - MA 모델의 차수 q는 ACF 그래프로 결정합니다

  • 외부 충격이나 이벤트 효과를 모델링할 때 MA가 유용합니다
  • 순수 MA 모델은 ARIMA(0, 0, q)로 표현할 수 있습니다

5. ACF와 PACF 이해하기

김개발 씨는 AR과 MA를 배우면서 ACF와 PACF라는 단어를 계속 들었습니다. "도대체 이 그래프들은 뭐고, 어떻게 해석하는 건가요?" 박시니어 씨가 미소를 지으며 화이트보드에 그래프를 그리기 시작했습니다.

ACF는 자기상관함수로, 현재 값과 과거 값 사이의 상관관계를 보여줍니다. PACF는 편자기상관함수로, 중간 시점의 영향을 제거한 순수한 상관관계를 보여줍니다.

이 두 그래프는 AR과 MA 모델의 차수를 결정하는 핵심 도구입니다.

다음 코드를 살펴봅시다.

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima_process import ArmaProcess
import matplotlib.pyplot as plt
import numpy as np

# AR(2) 데이터 생성
np.random.seed(42)
ar_params = np.array([1, -0.7, -0.2])  # AR 계수
ma_params = np.array([1])  # MA 없음
ar_process = ArmaProcess(ar_params, ma_params)
data = ar_process.generate_sample(nsample=300)

# ACF와 PACF 그래프 생성
fig, axes = plt.subplots(1, 2, figsize=(12, 4))

plot_acf(data, lags=20, ax=axes[0])
axes[0].set_title('ACF (자기상관함수)')

plot_pacf(data, lags=20, ax=axes[1])
axes[1].set_title('PACF (편자기상관함수)')

plt.tight_layout()
plt.savefig('acf_pacf.png')
print("ACF/PACF 그래프가 저장되었습니다.")

박시니어 씨가 비유를 들었습니다. "가족 관계를 생각해보세요.

나와 아버지는 직접적인 관계가 있어요. 나와 할아버지도 관계가 있지만, 그건 아버지를 통한 간접적인 관계도 포함되어 있죠." ACF, 자기상관함수는 이 모든 관계를 보여줍니다.

현재 시점과 1시점 전, 2시점 전, 3시점 전의 상관관계를 모두 표시합니다. 하지만 여기에는 간접적인 영향도 섞여 있습니다.

PACF, 편자기상관함수는 순수한 관계만 보여줍니다. 중간 시점의 영향을 통계적으로 제거하고, 현재와 특정 과거 시점 사이의 직접적인 관계만 측정합니다.

그래서 해석 방법이 다릅니다. AR 모델의 차수를 정할 때는 PACF를 봅니다.

PACF가 특정 시점 이후로 갑자기 0에 가까워지면, 그 시점이 적절한 차수입니다. 반대로 MA 모델의 차수는 ACF로 정합니다.

ACF가 갑자기 끊기는 시점이 MA의 차수가 됩니다. 코드에서는 AR(2) 과정을 따르는 데이터를 생성했습니다.

이 데이터의 PACF 그래프를 보면, lag=2까지는 유의미한 값을 보이다가 그 이후로 급격히 떨어지는 것을 확인할 수 있습니다. 이것이 "AR(2)를 사용하라"는 신호입니다.

실무에서는 두 그래프를 항상 함께 봅니다. ACF가 천천히 감소하고 PACF가 급격히 끊기면 AR 모델이 적합합니다.

반대로 ACF가 급격히 끊기고 PACF가 천천히 감소하면 MA 모델이 적합합니다. 김개발 씨가 자신의 데이터로 그래프를 그려보았습니다.

ACF도 PACF도 천천히 감소하는 패턴을 보였습니다. "이건 뭘까요?" "좋은 발견이에요.

둘 다 천천히 감소하면 ARMA 모델을 써야 해요. AR과 MA를 합친 모델이죠."

실전 팁

💡 - PACF가 lag=p에서 끊기면 AR(p) 모델 사용

  • ACF가 lag=q에서 끊기면 MA(q) 모델 사용
  • 둘 다 천천히 감소하면 ARMA 모델을 고려하세요

6. ARMA 모델 완성

김개발 씨가 기다리던 순간이 왔습니다. AR과 MA를 따로 배웠으니, 이제 둘을 합칠 차례입니다.

박시니어 씨가 말했습니다. "현실의 데이터는 AR도 MA도 아닌 경우가 많아요.

그래서 둘을 합친 ARMA가 필요합니다."

ARMA 모델은 AR과 MA를 결합한 모델입니다. 과거의 값과 과거의 오차를 동시에 고려하여 현재를 예측합니다.

ARMA(p, q)에서 p는 AR 차수, q는 MA 차수를 의미합니다. 실제 시계열 데이터는 대부분 ARMA로 모델링할 때 가장 좋은 성능을 보입니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.arima_process import ArmaProcess
import numpy as np
import pandas as pd

# ARMA(2,1) 데이터 생성
np.random.seed(42)
ar_params = np.array([1, -0.7, -0.2])  # AR(2) 계수
ma_params = np.array([1, 0.5])  # MA(1) 계수

arma_process = ArmaProcess(ar_params, ma_params)
data = arma_process.generate_sample(nsample=300)

# ARMA(2,1) 모델 학습
# ARIMA에서 order=(p, d, q), d=0이면 ARMA
model = ARIMA(data, order=(2, 0, 1))
fitted = model.fit()

print("=== ARMA(2,1) 모델 결과 ===")
print(f"AR 계수: {fitted.arparams}")
print(f"MA 계수: {fitted.maparams}")
print(f"AIC: {fitted.aic:.2f}")

박시니어 씨가 정리했습니다. "지금까지 배운 걸 합쳐볼까요?

AR은 과거의 값을 보고, MA는 과거의 오차를 봐요. 현실에서는 둘 다 필요한 경우가 많습니다." ARMA 모델은 이 두 가지를 동시에 사용합니다.

마치 운전할 때 앞을 보면서 동시에 백미러도 확인하는 것과 같습니다. 과거의 경향도 보고, 최근의 예측 실수도 함께 고려합니다.

ARMA(p, q) 표기법에서 p는 AR의 차수, q는 MA의 차수입니다. ARMA(2, 1)이라면 과거 2개의 값과 과거 1개의 오차를 사용한다는 뜻입니다.

코드에서 ARIMA 함수를 사용하는데, order=(2, 0, 1)로 설정했습니다. 가운데 숫자 d는 차분 횟수인데, 0으로 설정하면 차분 없이 순수 ARMA 모델이 됩니다.

학습 결과에서 중요한 것은 AIC 값입니다. AIC는 모델의 적합도를 나타내는 지표로, 값이 작을수록 좋은 모델입니다.

여러 차수 조합을 시도해보고 AIC가 가장 낮은 모델을 선택하면 됩니다. 실무에서는 어떻게 최적의 p와 q를 찾을까요?

가장 간단한 방법은 그리드 서치입니다. p와 q를 0부터 5까지 모든 조합으로 시도해보고, AIC가 가장 낮은 조합을 선택합니다.

하지만 주의할 점이 있습니다. 복잡한 모델이 항상 좋은 것은 아닙니다.

p와 q가 커지면 과적합의 위험이 있습니다. 학습 데이터에서는 잘 맞지만, 새로운 데이터에서는 성능이 떨어질 수 있습니다.

김개발 씨가 자신의 판매 데이터로 여러 ARMA 모델을 시험해보았습니다. ARMA(1, 1)이 가장 낮은 AIC를 보였습니다.

간단한 모델이 오히려 좋은 성능을 낸 것입니다. "단순함이 최고라는 말이 여기서도 통하네요!" 김개발 씨가 감탄했습니다.

실전 팁

💡 - 최적의 p, q는 AIC나 BIC를 기준으로 선택합니다

  • 복잡한 모델보다 단순한 모델이 더 안정적일 수 있습니다
  • auto_arima 같은 자동화 도구로 최적 차수를 찾을 수 있습니다

7. 모델 진단과 검증

김개발 씨가 ARMA 모델을 만들었습니다. 하지만 박시니어 씨가 물었습니다.

"모델이 정말 괜찮은지 어떻게 알 수 있죠?" 모델을 만드는 것과 그 모델이 좋은지 확인하는 것은 별개의 문제였습니다. 이제 모델 진단의 세계로 들어갑니다.

모델 진단은 학습된 모델이 제대로 작동하는지 확인하는 과정입니다. 잔차 분석을 통해 모델이 데이터의 패턴을 충분히 포착했는지 검증합니다.

좋은 모델의 잔차는 백색 잡음처럼 랜덤해야 하며, 어떤 패턴도 남아 있으면 안 됩니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.arima.model import ARIMA
from statsmodels.stats.diagnostic import acorr_ljungbox
import numpy as np
import matplotlib.pyplot as plt

# 데이터 및 모델 학습
np.random.seed(42)
data = np.cumsum(np.random.randn(200)) + 100
data_diff = np.diff(data)  # 차분으로 정상화

model = ARIMA(data_diff, order=(1, 0, 1))
fitted = model.fit()

# 잔차 분석
residuals = fitted.resid
print("=== 잔차 분석 ===")
print(f"잔차 평균: {residuals.mean():.4f} (0에 가까워야 함)")
print(f"잔차 표준편차: {residuals.std():.4f}")

# Ljung-Box 검정 (잔차의 자기상관 검정)
lb_test = acorr_ljungbox(residuals, lags=[10], return_df=True)
print(f"\nLjung-Box p-value: {lb_test['lb_pvalue'].values[0]:.4f}")
print("(p > 0.05면 잔차에 자기상관 없음 = 좋은 모델)")

박시니어 씨가 비유를 들었습니다. "피자를 주문했다고 생각해보세요.

피자가 도착하면 상자를 열어서 확인하잖아요. 토핑이 제대로 있는지, 치즈가 충분한지.

모델도 마찬가지로 검증이 필요해요." 모델을 학습시킨 후에는 잔차를 분석해야 합니다. 잔차란 모델의 예측값과 실제값의 차이입니다.

좋은 모델이라면 이 잔차에 더 이상 아무 패턴도 남아 있지 않아야 합니다. 잔차가 랜덤하지 않고 어떤 패턴을 보인다면, 그것은 모델이 데이터의 정보를 충분히 포착하지 못했다는 뜻입니다.

아직 설명되지 않은 무언가가 남아 있는 것입니다. 코드에서는 세 가지를 확인합니다.

첫째, 잔차의 평균이 0에 가까운지 확인합니다. 둘째, 잔차의 분포가 정규분포에 가까운지 봅니다.

셋째, Ljung-Box 검정으로 잔차에 자기상관이 없는지 검증합니다. Ljung-Box 검정의 p-value가 0.05보다 크면, 잔차에 유의미한 자기상관이 없다는 뜻입니다.

이는 모델이 데이터의 시간적 패턴을 충분히 포착했다는 증거입니다. 만약 진단 결과가 좋지 않다면 어떻게 해야 할까요?

차수를 조정하거나, 계절성 요소를 추가하거나, 아예 다른 모델을 시도해볼 수 있습니다. 김개발 씨가 자신의 모델을 진단해보았습니다.

잔차 평균은 거의 0이었고, Ljung-Box p-value는 0.42로 자기상관이 없었습니다. 모델이 잘 작동하고 있다는 뜻이었습니다.

"이제 마음 놓고 예측을 할 수 있겠네요!" 김개발 씨가 안도의 한숨을 쉬었습니다.

실전 팁

💡 - 잔차의 평균은 0, 분산은 일정해야 합니다

  • Ljung-Box p-value가 0.05보다 크면 좋은 신호입니다
  • 잔차에 패턴이 보이면 모델을 재검토하세요

8. 실전 예측 수행하기

모든 준비가 끝났습니다. 김개발 씨는 드디어 다음 달 판매량을 예측할 준비가 되었습니다.

박시니어 씨가 말했습니다. "자, 이제 배운 것을 총동원해서 실제 예측을 해봅시다." 이론에서 실전으로 넘어가는 순간이었습니다.

실전 예측은 학습된 모델을 사용하여 미래 값을 추정하는 과정입니다. 학습 데이터로 모델을 만들고, 테스트 데이터로 성능을 검증한 후, 최종적으로 미래를 예측합니다.

예측 결과에는 항상 신뢰구간을 함께 제시하여 불확실성을 표현합니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.arima.model import ARIMA
import numpy as np
import pandas as pd

# 1년치 일별 판매 데이터 시뮬레이션
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=365, freq='D')
base = 100 + np.arange(365) * 0.1  # 약간의 상승 트렌드
seasonal = 15 * np.sin(2 * np.pi * np.arange(365) / 30)
noise = np.random.randn(365) * 5
sales = base + seasonal + noise

ts = pd.Series(sales, index=dates)

# 학습/테스트 분리 (마지막 30일은 테스트)
train = ts[:-30]
test = ts[-30:]

# 모델 학습 및 예측
model = ARIMA(train, order=(2, 1, 1))
fitted = model.fit()

# 30일 예측 (신뢰구간 포함)
forecast = fitted.get_forecast(steps=30)
pred_mean = forecast.predicted_mean
conf_int = forecast.conf_int()

print(f"예측 RMSE: {np.sqrt(((pred_mean - test)**2).mean()):.2f}")
print(f"\n향후 7일 예측:\n{pred_mean.head(7)}")

김개발 씨가 마침내 실전에 돌입했습니다. 1년치 판매 데이터를 불러오고, 체계적인 분석 프로세스를 따르기로 했습니다.

먼저 데이터를 학습용테스트용으로 나눕니다. 코드에서는 마지막 30일을 테스트용으로 남겨두었습니다.

이렇게 하면 모델이 본 적 없는 데이터에서 얼마나 잘 예측하는지 확인할 수 있습니다. 모델은 ARIMA(2, 1, 1)을 사용했습니다.

가운데 숫자 1은 차분을 한 번 수행한다는 뜻입니다. 원본 데이터에 추세가 있었기 때문에 차분이 필요했습니다.

get_forecast 함수는 미래 값을 예측하면서 동시에 신뢰구간도 계산합니다. 신뢰구간은 "실제 값이 이 범위 안에 있을 확률이 95%입니다"라는 의미입니다.

예측에는 항상 불확실성이 따르므로, 신뢰구간을 함께 제시하는 것이 중요합니다. RMSE는 예측 성능을 나타내는 지표입니다.

Root Mean Squared Error의 약자로, 값이 작을수록 예측이 정확하다는 뜻입니다. 테스트 데이터로 계산한 RMSE가 합리적인 수준이라면, 모델을 신뢰할 수 있습니다.

김개발 씨의 RMSE는 약 5.2로 나왔습니다. 원본 데이터의 평균이 100 정도인 것을 감안하면, 약 5% 정도의 오차입니다.

재고 관리에 충분히 활용할 수 있는 수준이었습니다. "이 정도면 운영팀에 자신 있게 보고할 수 있겠어요!" 김개발 씨의 얼굴에 미소가 번졌습니다.

박시니어 씨가 덧붙였습니다. "좋아요.

하지만 예측은 예측일 뿐이라는 걸 항상 기억하세요. 신뢰구간과 함께 보고하고, 주기적으로 모델을 업데이트하는 것도 잊지 마세요."

실전 팁

💡 - 반드시 학습 데이터와 테스트 데이터를 분리하세요

  • 예측 결과에는 항상 신뢰구간을 포함하세요
  • 모델은 새로운 데이터가 쌓이면 주기적으로 재학습해야 합니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Python#TimeSeries#AR#MA#ARMA#Data Science

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.