본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 3. · 13 Views
실전 실습 ARIMA로 판매량 예측하기
시계열 분석의 대표 주자 ARIMA 모델을 활용하여 실제 판매량 데이터를 예측하는 방법을 학습합니다. 데이터 전처리부터 모델 구축, 예측까지 전 과정을 실습합니다.
목차
- 시계열_데이터_이해하기
- 정상성_검정하기
- 차분으로_정상성_만들기
- ACF와_PACF로_파라미터_찾기
- ARIMA_모델_구축하기
- 미래_판매량_예측하기
- 모델_진단_및_검증
- auto_arima로_자동화하기
- 실무_적용_전체_파이프라인
1. 시계열 데이터 이해하기
어느 날 김개발 씨는 회사에서 긴급한 업무를 받았습니다. "다음 분기 판매량을 예측해서 보고서를 만들어 주세요." 엑셀로 그래프를 그려보니 판매량이 오르락내리락하는데, 도대체 어떻게 미래를 예측할 수 있을까요?
시계열 데이터란 시간 순서에 따라 기록된 데이터를 말합니다. 마치 일기장에 매일매일의 기록을 남기듯, 시간의 흐름에 따라 변화하는 값들을 담고 있습니다.
이런 데이터에는 추세, 계절성, 불규칙 변동이라는 세 가지 요소가 숨어 있습니다.
다음 코드를 살펴봅시다.
import pandas as pd
import matplotlib.pyplot as plt
# 판매 데이터 불러오기
sales_data = pd.read_csv('sales.csv', parse_dates=['date'])
sales_data.set_index('date', inplace=True)
# 시계열 데이터 시각화
plt.figure(figsize=(12, 6))
plt.plot(sales_data['quantity'], label='판매량')
plt.title('월별 판매량 추이')
plt.xlabel('날짜')
plt.ylabel('판매량')
plt.legend()
plt.show()
김개발 씨는 입사 6개월 차 데이터 분석가입니다. 오늘 팀장님이 불쑥 다가와 이렇게 말했습니다.
"김개발 씨, 우리 회사 제품 판매량을 예측해 볼 수 있겠어요? 다음 분기 재고 계획을 세워야 하거든요." 김개발 씨는 당황했습니다.
판매량 데이터는 있는데, 이걸로 어떻게 미래를 예측한다는 걸까요? 옆자리의 선배 박시니어 씨가 조용히 다가와 모니터를 살펴봅니다.
"아, 이건 시계열 분석을 해야 하는 거네요." 그렇다면 시계열 데이터란 정확히 무엇일까요? 쉽게 비유하자면, 시계열 데이터는 마치 성장 앨범과 같습니다.
아이가 태어나서 자라는 모습을 매년 사진으로 기록하면, 시간이 흐름에 따라 키가 커지는 추세를 볼 수 있습니다. 계절마다 입는 옷이 달라지는 패턴도 보이고, 갑자기 감기에 걸려 아파 보이는 날도 있습니다.
판매량 데이터도 마찬가지입니다. 시간의 흐름에 따라 전체적으로 증가하거나 감소하는 추세가 있습니다.
여름에는 에어컨이 잘 팔리고 겨울에는 히터가 잘 팔리는 계절성도 있습니다. 그리고 갑작스러운 이벤트나 예측할 수 없는 불규칙 변동도 존재합니다.
이 세 가지 요소를 분리해서 이해하는 것이 시계열 분석의 첫걸음입니다. 위 코드를 살펴보면, 먼저 pandas를 사용해 CSV 파일을 불러옵니다.
여기서 중요한 것은 parse_dates 옵션으로 날짜 컬럼을 날짜 형식으로 변환하는 것입니다. 그리고 set_index로 날짜를 인덱스로 설정합니다.
이렇게 해야 시계열 분석을 제대로 수행할 수 있습니다. 실제 현업에서는 이 단계가 매우 중요합니다.
데이터를 처음 받으면 항상 시각화부터 해봐야 합니다. 그래프를 보면 데이터에 어떤 패턴이 숨어 있는지 한눈에 파악할 수 있기 때문입니다.
주의할 점이 있습니다. 시계열 데이터는 반드시 시간 순서가 유지되어야 합니다.
데이터가 섞여 있으면 분석 결과가 엉망이 됩니다. 또한 결측치가 있으면 나중에 모델이 제대로 작동하지 않으니 미리 확인해야 합니다.
김개발 씨는 데이터를 시각화해보고 나서야 상황을 이해했습니다. "아, 확실히 매년 비슷한 시기에 판매량이 올라가는 패턴이 있네요!"
실전 팁
💡 - 시계열 데이터를 받으면 항상 시각화부터 해보세요
- 결측치와 이상치를 먼저 확인하는 습관을 들이세요
2. 정상성 검정하기
박시니어 씨가 김개발 씨에게 물었습니다. "혹시 이 데이터가 정상성을 만족하는지 확인해봤어요?" 김개발 씨는 고개를 갸웃거렸습니다.
정상성이 대체 뭘까요? 왜 그게 중요한 걸까요?
정상성이란 시계열 데이터의 통계적 특성이 시간에 따라 변하지 않는 것을 의미합니다. 마치 잔잔한 호수처럼 평균과 분산이 일정해야 ARIMA 모델을 적용할 수 있습니다.
ADF 검정을 통해 정상성 여부를 확인합니다.
다음 코드를 살펴봅시다.
from statsmodels.tsa.stattools import adfuller
# ADF 검정 수행
def check_stationarity(data):
result = adfuller(data.dropna())
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('결론: 차분이 필요합니다')
check_stationarity(sales_data['quantity'])
김개발 씨는 정상성이라는 단어를 처음 들었습니다. 박시니어 씨가 화이트보드 앞으로 가서 설명을 시작했습니다.
"시계열 분석에서 정상성은 정말 중요한 개념이에요. 쉽게 말해서, 데이터가 시간이 지나도 비슷한 패턴을 유지하는지를 보는 거예요." 비유를 들어보겠습니다.
정상성은 마치 수영장 물결과 같습니다. 잔잔한 수영장에서는 물결의 높낮이가 일정합니다.
평균 수면 높이도 변하지 않고, 출렁이는 정도도 비슷합니다. 이런 상태가 바로 정상성입니다.
반면, 바다의 파도를 생각해보세요. 밀물과 썰물에 따라 수면 높이가 계속 변합니다.
태풍이 오면 파도가 엄청나게 커지기도 합니다. 이런 데이터는 정상성을 만족하지 않습니다.
왜 정상성이 중요할까요? ARIMA 모델은 과거 패턴이 미래에도 유지된다는 가정 하에 예측을 수행합니다.
만약 데이터의 특성이 시간마다 달라진다면, 과거를 기반으로 미래를 예측하는 것 자체가 불가능해집니다. 위 코드에서 사용한 ADF 검정(Augmented Dickey-Fuller test)은 정상성을 검사하는 대표적인 방법입니다.
검정 결과에서 p-value가 0.05보다 작으면 "정상성을 만족한다"고 판단합니다. 코드를 자세히 살펴보면, adfuller 함수가 검정을 수행합니다.
결과값 중 첫 번째가 ADF 통계량이고, 두 번째가 p-value입니다. 이 값을 기준으로 정상성 여부를 판단합니다.
실무에서 흔히 하는 실수가 있습니다. 검정 결과를 확인하지 않고 바로 모델을 만드는 것입니다.
정상성을 만족하지 않는 데이터로 ARIMA를 돌리면 예측 결과가 엉망이 됩니다. 만약 정상성을 만족하지 않는다면 어떻게 해야 할까요?
바로 차분이라는 기법을 사용합니다. 이건 다음 카드에서 자세히 알아보겠습니다.
김개발 씨가 코드를 실행해보니 p-value가 0.15로 나왔습니다. "아, 정상성을 만족하지 않네요.
차분을 해야겠군요!"
실전 팁
💡 - p-value 0.05는 절대적인 기준이 아니니 상황에 따라 유연하게 판단하세요
- 시각적으로도 데이터를 확인해서 검정 결과와 비교해보세요
3. 차분으로 정상성 만들기
ADF 검정 결과, 김개발 씨의 데이터는 정상성을 만족하지 않았습니다. 박시니어 씨가 말했습니다.
"걱정 마세요. 차분을 하면 대부분 해결됩니다." 차분이란 도대체 무엇이고, 어떻게 데이터를 변환하는 걸까요?
차분은 현재 값에서 이전 값을 빼는 연산입니다. 마치 계단을 오를 때 각 계단의 높이 차이만 기록하는 것과 같습니다.
차분을 통해 추세를 제거하고 정상성을 확보할 수 있습니다. ARIMA의 d 파라미터가 바로 차분 횟수를 의미합니다.
다음 코드를 살펴봅시다.
# 1차 차분 수행
sales_diff = sales_data['quantity'].diff().dropna()
# 차분 전후 비교 시각화
fig, axes = plt.subplots(2, 1, figsize=(12, 8))
axes[0].plot(sales_data['quantity'])
axes[0].set_title('원본 데이터')
axes[1].plot(sales_diff)
axes[1].set_title('1차 차분 후 데이터')
plt.tight_layout()
plt.show()
# 차분 후 정상성 재검정
check_stationarity(sales_diff)
박시니어 씨가 간단한 예시를 들어 설명했습니다. "차분을 이해하려면 계단을 생각해보세요.
1층은 0m, 2층은 3m, 3층은 6m, 4층은 9m 높이에 있다고 해봅시다. 이 숫자들은 계속 증가하는 추세가 있죠?" 김개발 씨가 고개를 끄덕였습니다.
"이제 각 층 사이의 높이 차이만 기록해보세요. 1층에서 2층은 3m, 2층에서 3층도 3m, 3층에서 4층도 3m.
차이값은 모두 3으로 일정합니다. 이게 바로 차분이에요." 차분의 핵심은 변화량에 집중하는 것입니다.
원본 데이터에서 추세를 제거하고, 순수한 변동만 남깁니다. 이렇게 하면 대부분의 시계열 데이터가 정상성을 만족하게 됩니다.
pandas에서는 diff() 함수 하나로 차분을 수행할 수 있습니다. 정말 간단하죠?
다만 주의할 점이 있습니다. 차분을 하면 첫 번째 값이 NaN이 됩니다.
이전 값이 없으니 차이를 계산할 수 없기 때문입니다. 그래서 dropna()로 결측치를 제거해야 합니다.
위 코드를 실행하면 원본 데이터와 차분 후 데이터를 비교할 수 있습니다. 원본 데이터에서는 우상향하는 추세가 보이지만, 차분 후에는 0을 중심으로 오르락내리락하는 모습을 볼 수 있습니다.
한 번의 차분으로 정상성이 확보되지 않으면 어떻게 할까요? 2차 차분을 수행합니다.
diff().diff()처럼 연속으로 적용하면 됩니다. 하지만 대부분의 경우 1차 또는 2차 차분이면 충분합니다.
ARIMA 모델에서 d 파라미터가 바로 이 차분 횟수를 의미합니다. d=1이면 1차 차분, d=2면 2차 차분을 적용한다는 뜻입니다.
김개발 씨가 차분 후 ADF 검정을 다시 해보니 p-value가 0.001로 나왔습니다. "이제 정상성을 만족하네요!
드디어 모델을 만들 수 있겠어요."
실전 팁
💡 - 보통 1~2번의 차분으로 정상성을 확보할 수 있습니다
- 차분 횟수가 너무 많으면 데이터의 중요한 정보가 손실될 수 있으니 주의하세요
4. ACF와 PACF로 파라미터 찾기
정상성을 확보한 김개발 씨 앞에 새로운 과제가 생겼습니다. ARIMA 모델에는 p, d, q라는 세 가지 파라미터가 필요한데, 이 값들을 어떻게 정해야 할까요?
박시니어 씨가 ACF와 PACF 그래프를 보여주며 설명을 시작했습니다.
ACF(자기상관함수)와 PACF(부분자기상관함수)는 시계열 데이터의 자기상관 패턴을 보여주는 도구입니다. 마치 가족 관계도처럼, 현재 값이 과거 값들과 얼마나 관련되어 있는지 시각적으로 파악할 수 있습니다.
이를 통해 ARIMA의 p와 q 파라미터를 결정합니다.
다음 코드를 살펴봅시다.
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# ACF, PACF 그래프 그리기
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# ACF: q 파라미터 결정에 사용
plot_acf(sales_diff, ax=axes[0], lags=20)
axes[0].set_title('ACF (자기상관함수)')
# PACF: p 파라미터 결정에 사용
plot_pacf(sales_diff, ax=axes[1], lags=20)
axes[1].set_title('PACF (부분자기상관함수)')
plt.tight_layout()
plt.show()
박시니어 씨가 화이트보드에 두 개의 그래프를 그렸습니다. "ARIMA에서 p는 AR(자기회귀) 차수, q는 MA(이동평균) 차수를 의미해요.
이 값들을 어떻게 정하느냐에 따라 모델의 성능이 크게 달라집니다." 자기상관이란 무엇일까요? 쉽게 비유하면, 가족 관계와 비슷합니다.
아들은 아버지와 닮았고, 아버지는 할아버지와 닮았습니다. 시계열 데이터도 마찬가지로, 오늘의 값은 어제의 값과 관련이 있고, 어제의 값은 그제의 값과 관련이 있습니다.
ACF(자기상관함수)는 현재 값과 과거 값들 사이의 상관관계를 보여줍니다. lag 1은 1시점 전, lag 2는 2시점 전과의 상관관계입니다.
그래프에서 파란 영역을 벗어나는 막대가 있으면 해당 시점까지 유의미한 상관관계가 있다는 뜻입니다. PACF(부분자기상관함수)는 중간 단계를 제외한 직접적인 상관관계만 보여줍니다.
아들과 할아버지의 닮은 정도를 볼 때, 아버지의 영향을 제외하고 순수하게 둘만의 유사성을 보는 것과 같습니다. 실무에서 파라미터를 결정하는 규칙은 다음과 같습니다.
PACF가 급격히 떨어지는 지점이 p 값이 됩니다. ACF가 급격히 떨어지는 지점이 q 값이 됩니다.
그리고 d는 앞서 수행한 차분 횟수입니다. 위 코드에서 plot_acf와 plot_pacf 함수를 사용하면 쉽게 그래프를 그릴 수 있습니다.
lags=20은 20시점까지 확인한다는 의미입니다. 김개발 씨가 그래프를 보니 PACF는 lag 2에서, ACF는 lag 1에서 파란 영역 안으로 들어왔습니다.
"그러면 p=2, d=1, q=1로 설정하면 되겠네요!" 하지만 주의할 점이 있습니다. 이 방법은 어디까지나 경험적인 가이드라인입니다.
실제로는 여러 파라미터 조합을 시도해보고 가장 좋은 결과를 선택하는 것이 좋습니다.
실전 팁
💡 - ACF/PACF 해석이 어려우면 auto_arima를 사용해 자동으로 파라미터를 찾을 수 있습니다
- 파란 영역(신뢰구간)을 벗어나는 첫 번째 지점을 주목하세요
5. ARIMA 모델 구축하기
드디어 본격적인 모델 구축 단계입니다. 김개발 씨는 지금까지 배운 내용을 바탕으로 p=2, d=1, q=1로 파라미터를 설정했습니다.
이제 statsmodels 라이브러리를 사용해 ARIMA 모델을 만들어 보겠습니다.
ARIMA 모델은 AR(자기회귀), I(차분), MA(이동평균)의 세 요소를 결합한 시계열 예측 모델입니다. 마치 요리사가 재료를 배합하듯, p, d, q 세 가지 파라미터를 조합하여 최적의 예측 모델을 만듭니다.
statsmodels 라이브러리로 손쉽게 구현할 수 있습니다.
다음 코드를 살펴봅시다.
from statsmodels.tsa.arima.model import ARIMA
# ARIMA 모델 생성 및 학습
model = ARIMA(sales_data['quantity'], order=(2, 1, 1))
fitted_model = model.fit()
# 모델 요약 정보 출력
print(fitted_model.summary())
# 모델 성능 지표 확인
print(f'\nAIC: {fitted_model.aic:.2f}')
print(f'BIC: {fitted_model.bic:.2f}')
김개발 씨가 드디어 ARIMA 모델을 만들 차례가 되었습니다. 그동안 배운 정상성 검정, 차분, ACF/PACF 분석이 모두 이 순간을 위한 준비였습니다.
ARIMA라는 이름의 의미를 다시 짚어보겠습니다. AR(AutoRegressive)은 자기회귀로, 과거의 자기 자신 값을 사용합니다.
I(Integrated)는 차분을 의미합니다. MA(Moving Average)는 이동평균으로, 과거의 예측 오차를 사용합니다.
비유하자면, ARIMA는 노련한 주식 투자자와 같습니다. 과거 주가 흐름을 보고(AR), 전반적인 추세를 파악하며(I), 자신의 과거 예측이 얼마나 빗나갔는지도 고려합니다(MA).
이 세 가지를 종합해서 미래를 예측하는 것입니다. 코드를 살펴보면, ARIMA 클래스에 원본 데이터와 order=(2, 1, 1)을 전달합니다.
이 순서는 항상 **(p, d, q)**입니다. 그리고 fit() 메서드로 모델을 학습시킵니다.
모델이 학습되면 summary() 메서드로 상세한 정보를 확인할 수 있습니다. 여기서 주목해야 할 것이 AIC와 BIC 값입니다.
이 값들은 모델의 적합도를 나타내며, 낮을수록 좋은 모델입니다. 여러 파라미터 조합을 시도할 때 AIC와 BIC를 비교 기준으로 사용합니다.
예를 들어 (2,1,1)과 (1,1,2)를 비교해서 AIC가 더 낮은 쪽을 선택하는 식입니다. summary 결과에는 각 계수의 p-value도 나옵니다.
p-value가 0.05보다 크면 해당 항은 통계적으로 유의하지 않을 수 있습니다. 이런 경우 파라미터를 조정해볼 필요가 있습니다.
박시니어 씨가 조언했습니다. "처음에는 여러 조합을 시도해보는 게 좋아요.
(1,1,1), (2,1,1), (1,1,2) 같은 조합들을 비교해보세요." 김개발 씨는 여러 조합을 시도해본 결과, (2,1,1)이 가장 낮은 AIC를 보여주는 것을 확인했습니다. "이제 이 모델로 예측을 해볼까요?"
실전 팁
💡 - AIC와 BIC가 서로 다른 모델을 추천할 경우, 일반적으로 AIC를 우선시합니다
- pmdarima 라이브러리의 auto_arima를 사용하면 최적 파라미터를 자동으로 찾아줍니다
6. 미래 판매량 예측하기
모델 학습이 완료되었습니다. 이제 팀장님이 요청한 다음 분기 판매량 예측을 수행할 차례입니다.
김개발 씨는 설레는 마음으로 예측 코드를 작성하기 시작했습니다. 과연 ARIMA 모델은 어떤 미래를 보여줄까요?
학습된 ARIMA 모델로 미래 값을 예측하는 것은 forecast 메서드 하나면 충분합니다. 마치 일기예보처럼, 모델은 과거 패턴을 바탕으로 미래의 값과 함께 신뢰구간도 제공합니다.
이 신뢰구간은 예측의 불확실성을 나타냅니다.
다음 코드를 살펴봅시다.
# 향후 12개월 예측
forecast_result = fitted_model.get_forecast(steps=12)
forecast_values = forecast_result.predicted_mean
confidence_intervals = forecast_result.conf_int()
# 예측 결과 시각화
plt.figure(figsize=(14, 7))
plt.plot(sales_data['quantity'], label='실제 데이터', color='blue')
plt.plot(forecast_values, label='예측값', color='red')
plt.fill_between(confidence_intervals.index,
confidence_intervals.iloc[:, 0],
confidence_intervals.iloc[:, 1],
alpha=0.3, color='red', label='95% 신뢰구간')
plt.legend()
plt.title('ARIMA 판매량 예측')
plt.show()
드디어 예측의 순간이 왔습니다. 김개발 씨는 떨리는 마음으로 코드를 실행했습니다.
예측에는 get_forecast 메서드를 사용합니다. steps=12는 12개 시점을 예측한다는 의미입니다.
월별 데이터라면 12개월, 일별 데이터라면 12일을 예측하는 것입니다. 예측 결과에서 중요한 것이 두 가지 있습니다.
첫 번째는 predicted_mean으로, 예측된 값 자체입니다. 두 번째는 conf_int로, 신뢰구간을 나타냅니다.
신뢰구간이란 무엇일까요? 비유하자면, 일기예보의 강수확률과 비슷합니다.
"내일 비가 올 확률이 70%"라고 할 때, 100% 확신하는 것이 아니라 불확실성이 있다는 뜻입니다. 마찬가지로 95% 신뢰구간은 "실제 값이 이 범위 안에 있을 확률이 95%"라는 의미입니다.
시각화 코드를 보면, 파란색 선이 실제 데이터이고, 빨간색 선이 예측값입니다. 그리고 빨간색 음영 영역이 신뢰구간입니다.
미래로 갈수록 신뢰구간이 넓어지는 것을 볼 수 있습니다. 이는 당연한 현상입니다.
먼 미래일수록 불확실성이 커지기 때문입니다. 실무에서 이 신뢰구간은 매우 중요합니다.
예측값만 보고 의사결정을 하면 위험할 수 있습니다. 신뢰구간의 상한과 하한을 고려해서 최악의 시나리오와 최선의 시나리오를 모두 대비해야 합니다.
김개발 씨가 예측 결과를 팀장님께 보여드렸습니다. "다음 분기 예상 판매량은 1,200개이고, 95% 신뢰구간은 1,000~1,400개입니다." 팀장님이 고개를 끄덕였습니다.
"좋아요. 그러면 재고는 최대치인 1,400개를 기준으로 준비하고, 예산은 평균인 1,200개를 기준으로 세우면 되겠네요."
실전 팁
💡 - 예측값만이 아니라 신뢰구간도 함께 보고해야 실무적으로 유용합니다
- 장기 예측보다 단기 예측이 더 정확하니, 가능하면 예측 기간을 짧게 가져가세요
7. 모델 진단 및 검증
예측까지 완료했지만, 박시니어 씨가 한 가지를 더 확인하라고 했습니다. "모델이 제대로 학습됐는지 잔차 분석을 해봐야 해요." 잔차란 무엇이고, 왜 분석해야 할까요?
잔차는 실제 값과 모델 예측값의 차이입니다. 마치 시험을 보고 나서 오답을 분석하듯, 잔차를 분석하면 모델이 놓친 패턴이 있는지 확인할 수 있습니다.
좋은 모델의 잔차는 백색잡음처럼 무작위해야 합니다.
다음 코드를 살펴봅시다.
from statsmodels.stats.diagnostic import acorr_ljungbox
# 잔차 추출
residuals = fitted_model.resid
# 잔차 진단 플롯
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 잔차 시계열
axes[0, 0].plot(residuals)
axes[0, 0].set_title('잔차 시계열')
# 잔차 히스토그램
axes[0, 1].hist(residuals, bins=20, edgecolor='black')
axes[0, 1].set_title('잔차 분포')
# 잔차 ACF
plot_acf(residuals, ax=axes[1, 0])
axes[1, 0].set_title('잔차 ACF')
# Ljung-Box 검정
lb_test = acorr_ljungbox(residuals, lags=10)
print(f'Ljung-Box p-value: {lb_test["lb_pvalue"].values[-1]:.4f}')
박시니어 씨가 중요한 점을 짚었습니다. "모델을 만들었다고 끝이 아니에요.
잔차 분석을 통해 모델이 제대로 작동하는지 검증해야 합니다." 잔차란 실제 값에서 모델이 예측한 값을 뺀 것입니다. 쉽게 말해 오차입니다.
시험에서 틀린 문제를 분석하면 자신의 약점을 알 수 있듯이, 잔차를 분석하면 모델의 한계를 파악할 수 있습니다. 좋은 모델의 잔차는 백색잡음처럼 보여야 합니다.
백색잡음이란 완전히 무작위한 신호를 말합니다. 텔레비전의 지직거리는 잡음처럼, 어떤 패턴도 없이 무작위로 흩어져 있어야 합니다.
만약 잔차에 패턴이 보인다면? 그건 모델이 데이터의 어떤 구조를 놓쳤다는 뜻입니다.
파라미터를 조정하거나, 다른 모델을 시도해봐야 합니다. 위 코드의 진단 플롯을 살펴보겠습니다.
첫 번째 그래프는 잔차의 시계열입니다. 특별한 추세나 패턴 없이 0 주변에서 무작위로 흩어져 있어야 합니다.
두 번째는 잔차의 히스토그램입니다. 정규분포 모양에 가까울수록 좋습니다.
세 번째는 잔차의 ACF입니다. 여기서 중요한 것은 모든 lag에서 신뢰구간 안에 있어야 한다는 것입니다.
만약 특정 lag에서 벗어나면, 해당 시점의 자기상관을 모델이 포착하지 못했다는 의미입니다. 마지막으로 Ljung-Box 검정이 있습니다.
이 검정의 p-value가 0.05보다 크면 "잔차에 유의미한 자기상관이 없다"고 판단합니다. 즉, 모델이 데이터의 패턴을 잘 잡아냈다는 뜻입니다.
김개발 씨가 분석을 완료했습니다. "잔차가 무작위하게 분포하고, Ljung-Box p-value도 0.23이네요.
모델이 잘 만들어진 것 같아요!"
실전 팁
💡 - 잔차에 패턴이 보이면 파라미터를 조정하거나 계절성 ARIMA(SARIMA)를 고려하세요
- 실무에서는 여러 지표를 종합적으로 판단해야 합니다
8. auto arima로 자동화하기
김개발 씨가 프로젝트를 마무리하고 있을 때, 박시니어 씨가 다가왔습니다. "수고했어요.
그런데 다음부터는 auto_arima를 써보는 건 어때요? 파라미터를 자동으로 찾아준답니다." 그동안의 수고가 물거품이 된 걸까요?
auto_arima는 pmdarima 라이브러리에서 제공하는 자동 파라미터 탐색 도구입니다. 마치 내비게이션이 최적 경로를 찾아주듯, 여러 조합을 자동으로 시도하고 가장 좋은 모델을 선택해줍니다.
하지만 원리를 이해하고 사용해야 더 효과적입니다.
다음 코드를 살펴봅시다.
from pmdarima import auto_arima
# 자동으로 최적 파라미터 탐색
auto_model = auto_arima(
sales_data['quantity'],
start_p=0, max_p=5, # AR 차수 범위
start_q=0, max_q=5, # MA 차수 범위
d=None, # 차분 차수 자동 결정
seasonal=False, # 계절성 모델 여부
trace=True, # 탐색 과정 출력
error_action='ignore',
suppress_warnings=True
)
print(f'\n최적 모델: ARIMA{auto_model.order}')
print(f'AIC: {auto_model.aic():.2f}')
박시니어 씨의 말에 김개발 씨는 조금 허탈했습니다. "그러면 처음부터 이걸 쓰면 되지 않나요?" 박시니어 씨가 웃으며 대답했습니다.
"물론 auto_arima가 편리하긴 해요. 하지만 원리를 모르고 쓰면 블랙박스가 됩니다.
결과가 이상할 때 어디가 문제인지 알 수 없어요. 오늘 배운 내용이 있어야 auto_arima의 결과도 제대로 해석할 수 있습니다." auto_arima는 pmdarima 라이브러리에서 제공합니다.
설치는 pip install pmdarima로 할 수 있습니다. 코드를 살펴보면, start_p와 max_p는 AR 차수의 탐색 범위입니다.
0부터 5까지 시도해본다는 뜻입니다. 마찬가지로 start_q와 max_q는 MA 차수의 범위입니다.
d=None으로 설정하면 차분 차수도 자동으로 결정합니다. 내부적으로 ADF 검정을 수행해서 정상성을 확보할 때까지 차분합니다.
trace=True를 설정하면 탐색 과정이 출력됩니다. 어떤 조합을 시도했고, 각각의 AIC가 얼마인지 볼 수 있습니다.
이 과정을 보면서 자동 탐색이 어떻게 이루어지는지 이해할 수 있습니다. seasonal=True로 설정하면 계절성 ARIMA인 SARIMA를 탐색합니다.
계절 패턴이 뚜렷한 데이터에는 이 옵션을 활성화하는 것이 좋습니다. auto_arima의 장점은 분명합니다.
시간을 절약할 수 있고, 사람이 놓칠 수 있는 조합을 찾아낼 수도 있습니다. 하지만 단점도 있습니다.
탐색 범위를 너무 넓게 잡으면 시간이 오래 걸립니다. 또한 데이터의 특성을 고려하지 않고 맹목적으로 사용하면 좋지 않은 결과가 나올 수 있습니다.
김개발 씨는 고개를 끄덕였습니다. "직접 해봤기 때문에 auto_arima가 어떤 과정을 거치는지 이해가 되네요.
다음 프로젝트에서는 auto_arima로 빠르게 탐색하고, 결과를 수동으로 검증해봐야겠어요."
실전 팁
💡 - 처음에는 수동으로 분석해보고, 익숙해지면 auto_arima를 활용하세요
- seasonal=True 옵션으로 계절성 모델도 함께 탐색할 수 있습니다
9. 실무 적용 전체 파이프라인
김개발 씨는 지금까지 배운 내용을 하나의 파이프라인으로 정리하고 싶었습니다. 앞으로 비슷한 프로젝트를 할 때 바로 활용할 수 있도록 말이죠.
박시니어 씨와 함께 실무에서 사용할 수 있는 완성된 코드를 작성해보았습니다.
실무에서는 데이터 로드부터 예측, 검증까지 일련의 과정을 파이프라인으로 구성합니다. 마치 공장의 조립라인처럼, 각 단계가 순서대로 연결되어 있어야 안정적으로 결과를 낼 수 있습니다.
재사용 가능한 함수로 구성하면 유지보수도 쉬워집니다.
다음 코드를 살펴봅시다.
def arima_forecast_pipeline(data, forecast_periods=12):
"""ARIMA 예측 파이프라인"""
# 1. 정상성 검정 및 차분
d = 0
temp_data = data.copy()
while adfuller(temp_data.dropna())[1] > 0.05 and d < 2:
temp_data = temp_data.diff().dropna()
d += 1
# 2. auto_arima로 최적 파라미터 탐색
model = auto_arima(data, d=d, seasonal=False,
suppress_warnings=True)
# 3. 예측 수행
forecast = model.predict(n_periods=forecast_periods,
return_conf_int=True)
return model, forecast[0], forecast[1]
# 파이프라인 실행
model, predictions, conf_int = arima_forecast_pipeline(
sales_data['quantity'])
박시니어 씨가 마지막 조언을 해주었습니다. "실무에서는 같은 분석을 여러 번 반복하게 돼요.
그래서 처음부터 재사용 가능한 코드로 작성하는 습관을 들이는 게 좋습니다." 위 코드는 지금까지 배운 모든 과정을 하나의 함수로 정리한 것입니다. 데이터만 넣으면 예측 결과가 나옵니다.
함수 내부를 살펴보겠습니다. 첫 번째 단계에서는 while 루프를 사용해 정상성을 만족할 때까지 차분을 수행합니다.
d < 2 조건으로 최대 2차 차분까지만 허용합니다. 보통 그 이상은 필요하지 않기 때문입니다.
두 번째 단계에서는 auto_arima를 사용해 최적의 p, q를 찾습니다. d는 첫 번째 단계에서 결정한 값을 사용합니다.
세 번째 단계에서 예측을 수행합니다. return_conf_int=True로 신뢰구간도 함께 반환받습니다.
이렇게 함수로 만들어두면 여러 장점이 있습니다. 다른 데이터에도 쉽게 적용할 수 있습니다.
코드를 수정할 때도 한 곳만 바꾸면 됩니다. 테스트도 쉬워집니다.
실무에서는 여기에 예외 처리, 로깅, 결과 저장 기능을 추가하면 더욱 완성도 높은 코드가 됩니다. 김개발 씨가 코드를 저장하며 말했습니다.
"이제 다음에 비슷한 업무가 들어와도 바로 처리할 수 있겠어요!" 박시니어 씨가 웃으며 대답했습니다. "잘했어요.
이제 기본기는 갖춰졌으니, 앞으로는 계절성 모델이나 딥러닝 기반 시계열 모델도 공부해보세요."
실전 팁
💡 - 파이프라인 함수에 예외 처리를 추가하면 더 안정적인 코드가 됩니다
- 결과를 파일로 저장하는 기능도 추가해보세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.