🤖

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

⚠️

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

이미지 로딩 중...

Exponential Smoothing ETS 모델 완벽 가이드 - 슬라이드 1/9
A

AI Generated

2025. 12. 3. · 14 Views

Exponential Smoothing ETS 모델 완벽 가이드

시계열 예측의 핵심인 지수평활법(ETS)을 초급자도 이해할 수 있도록 설명합니다. 과거 데이터에 가중치를 부여하여 미래를 예측하는 기법을 실무 예제와 함께 배워봅니다.


목차

  1. 지수평활법의_기본_원리
  2. ETS_모델의_구성요소
  3. 가법_모델과_승법_모델
  4. Holt_Winters_방법
  5. 감쇠_추세와_장기_예측
  6. 자동_모델_선택
  7. 예측_성능_평가
  8. 실무_예측_파이프라인

1. 지수평활법의 기본 원리

어느 날 김개발 씨는 회사에서 다음 달 매출을 예측해달라는 요청을 받았습니다. 엑셀로 평균을 내보았지만, 최근 급증한 매출이 제대로 반영되지 않았습니다.

"최근 데이터에 더 비중을 두는 방법이 없을까요?" 선배 박시니어 씨가 웃으며 말했습니다. "지수평활법을 써보세요."

**지수평활법(Exponential Smoothing)**은 한마디로 최근 데이터에 더 큰 가중치를 부여하여 미래를 예측하는 기법입니다. 마치 사람의 기억과 같습니다.

어제 일은 생생하게 기억하지만, 1년 전 일은 희미하게 기억하는 것처럼요. 이 방법을 사용하면 시계열 데이터의 최신 추세를 효과적으로 반영할 수 있습니다.

다음 코드를 살펴봅시다.

import pandas as pd
from statsmodels.tsa.holtwinters import SimpleExpSmoothing

# 월별 매출 데이터 (단위: 억원)
sales = [10, 12, 15, 14, 18, 20, 22, 25, 24, 28]
series = pd.Series(sales)

# 단순 지수평활 모델 생성
# smoothing_level(alpha): 0에 가까우면 과거 중시, 1에 가까우면 최근 중시
model = SimpleExpSmoothing(series)
fitted = model.fit(smoothing_level=0.3)

# 다음 3개월 예측
forecast = fitted.forecast(3)
print(f"예측 매출: {forecast.values}")

김개발 씨는 입사 6개월 차 데이터 분석가입니다. 오늘 상사로부터 긴급한 요청이 들어왔습니다.

"다음 분기 매출을 예측해서 보고서에 넣어줘요." 막막했습니다. 단순히 평균을 내자니 최근의 성장세가 반영되지 않을 것 같았습니다.

선배 박시니어 씨가 커피를 건네며 다가왔습니다. "고민이 많아 보이네요.

혹시 지수평활법은 들어보셨어요?" 그렇다면 지수평활법이란 정확히 무엇일까요? 쉽게 비유하자면, 지수평활법은 마치 우리의 기억력과 같습니다.

어제 먹은 점심은 또렷이 기억나지만, 한 달 전 점심은 희미하게만 떠오릅니다. 지수평활법도 마찬가지입니다.

최근 데이터는 선명하게, 오래된 데이터는 희미하게 반영하여 예측값을 계산합니다. 지수평활법이 없던 시절에는 어땠을까요?

개발자들은 단순 이동평균을 사용했습니다. 모든 과거 데이터에 동일한 가중치를 부여하는 방식이었습니다.

하지만 이 방법은 치명적인 문제가 있었습니다. 급격한 트렌드 변화에 둔감했고, 예측이 항상 실제보다 뒤처졌습니다.

바로 이런 문제를 해결하기 위해 지수평활법이 등장했습니다. 지수평활법의 핵심은 **평활 계수(alpha)**입니다.

이 값은 0과 1 사이의 숫자로, 최근 데이터에 얼마나 비중을 둘지 결정합니다. alpha가 0.9라면 최근 데이터를 매우 중요하게, 0.1이라면 과거 데이터를 더 중요하게 반영합니다.

위의 코드를 한 줄씩 살펴보겠습니다. 먼저 월별 매출 데이터를 리스트로 준비합니다.

이것이 우리가 예측에 사용할 시계열 데이터입니다. 다음으로 SimpleExpSmoothing 클래스로 모델을 생성합니다.

smoothing_level을 0.3으로 설정했는데, 이는 과거와 현재를 적절히 균형있게 반영하겠다는 의미입니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 이커머스 회사에서 재고 관리를 한다고 가정해봅시다. 지수평활법으로 다음 주 판매량을 예측하면, 재고 부족이나 과잉을 방지할 수 있습니다.

배달의민족, 쿠팡 같은 기업들이 이런 기법을 적극 활용하고 있습니다. 하지만 주의할 점도 있습니다.

초보자들이 흔히 하는 실수 중 하나는 alpha 값을 무작정 높게 설정하는 것입니다. alpha가 너무 높으면 노이즈에 민감해져 예측이 불안정해집니다.

반대로 너무 낮으면 트렌드 변화에 둔감해집니다. 적절한 균형점을 찾는 것이 중요합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.

"아, 그래서 단순 평균보다 더 정확하게 예측할 수 있군요!" 지수평활법을 제대로 이해하면 시계열 예측의 기초를 탄탄하게 다질 수 있습니다. 여러분도 실제 데이터에 적용해 보세요.

실전 팁

💡 - alpha 값은 보통 0.1~0.3 사이에서 시작하여 교차검증으로 최적값을 찾으세요

  • 데이터에 명확한 추세나 계절성이 있다면 단순 지수평활 대신 Holt-Winters 방법을 고려하세요

2. ETS 모델의 구성요소

김개발 씨가 단순 지수평활법을 적용해보니 예측이 조금 나아졌습니다. 하지만 여전히 뭔가 부족했습니다.

매출은 연말에 항상 오르고, 매년 조금씩 성장하는 추세가 있는데 이게 반영이 안 되는 것 같았습니다. "혹시 더 정교한 방법이 있나요?" 박시니어 씨가 답했습니다.

"ETS 모델을 배워볼 때가 됐네요."

ETS 모델은 Error(오차), Trend(추세), Seasonality(계절성)의 약자로, 시계열의 세 가지 핵심 구성요소를 모델링합니다. 마치 요리사가 음식의 맛, 향, 식감을 각각 조절하듯이, ETS는 데이터의 세 가지 특성을 개별적으로 다룹니다.

이를 통해 복잡한 시계열 패턴도 정확하게 예측할 수 있습니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.holtwinters import ExponentialSmoothing
import pandas as pd
import numpy as np

# 2년간 월별 매출 데이터 (계절성 포함)
np.random.seed(42)
months = pd.date_range('2022-01-01', periods=24, freq='M')
# 기본 추세 + 계절성 + 노이즈
sales = 100 + np.arange(24) * 2 + 10 * np.sin(np.arange(24) * np.pi / 6)
series = pd.Series(sales, index=months)

# ETS 모델: 추세(add)와 계절성(add) 모두 적용
model = ExponentialSmoothing(
    series,
    trend='add',        # 가법적 추세
    seasonal='add',     # 가법적 계절성
    seasonal_periods=12 # 12개월 주기
)
fitted = model.fit()
forecast = fitted.forecast(6)
print(f"향후 6개월 예측:\n{forecast}")

김개발 씨는 첫 번째 예측 보고서를 제출했습니다. 하지만 상사의 반응은 시원치 않았습니다.

"이 예측에는 연말 대목이 반영되지 않은 것 같은데요?" 김개발 씨는 당황했습니다. 분명히 지수평활법을 썼는데 무엇이 부족했던 걸까요?

박시니어 씨가 화면을 보며 설명을 시작했습니다. "단순 지수평활법은 수준만 고려해요.

하지만 실제 비즈니스 데이터에는 추세계절성이 있죠." 그렇다면 ETS의 세 가지 구성요소는 무엇일까요? 첫 번째는 **Error(오차)**입니다.

모든 예측에는 오차가 있습니다. 이 오차가 일정한지, 아니면 데이터 크기에 비례하는지에 따라 가법적(additive) 또는 승법적(multiplicative)으로 모델링합니다.

두 번째는 **Trend(추세)**입니다. 데이터가 시간에 따라 증가하거나 감소하는 경향입니다.

매출이 매년 10%씩 성장한다면, 이것이 바로 추세입니다. 세 번째는 **Seasonality(계절성)**입니다.

일정한 주기로 반복되는 패턴입니다. 여름에 에어컨 판매가 늘고, 겨울에 줄어드는 것이 대표적인 계절성입니다.

마치 날씨를 예측할 때를 생각해보세요. 기온이 점점 올라가는 추세가 있고, 여름이면 덥고 겨울이면 추운 계절성이 있습니다.

그리고 예측할 수 없는 일일 변동이 오차입니다. ETS 모델은 이 세 가지를 분리하여 각각 학습합니다.

위 코드에서 trend='add'는 추세를 가법적으로 모델링한다는 의미입니다. 매달 일정한 양만큼 증가한다고 가정하는 것이죠.

seasonal='add'도 마찬가지입니다. seasonal_periods=12는 12개월 주기로 계절성이 반복된다는 설정입니다.

실제 현업에서 이 설정을 어떻게 결정할까요? 데이터의 특성을 시각화해서 판단합니다.

변동폭이 시간에 따라 일정하면 가법적(add), 데이터 크기에 비례해서 커지면 승법적(mul)을 선택합니다. 예를 들어 매출이 10억일 때 1억 변동하고, 100억일 때도 1억 변동한다면 가법적입니다.

하지만 10억일 때 1억, 100억일 때 10억 변동한다면 승법적입니다. 주의할 점이 있습니다.

계절성 주기를 잘못 설정하면 예측이 크게 빗나갑니다. 월별 데이터인데 주간 계절성으로 설정하거나, 그 반대의 경우가 흔한 실수입니다.

데이터를 충분히 탐색한 후 적절한 주기를 설정해야 합니다. 김개발 씨는 ETS 모델로 다시 예측을 수행했습니다.

이번에는 연말 매출 증가가 정확히 반영되었습니다. 상사가 만족스러운 표정을 지었습니다.

"이번 예측은 훨씬 현실적이네요!"

실전 팁

💡 - trend와 seasonal 옵션은 None, 'add', 'mul' 중 선택할 수 있습니다

  • 최소 2주기 이상의 데이터가 있어야 계절성을 안정적으로 추정할 수 있습니다

3. 가법 모델과 승법 모델

김개발 씨가 ETS 모델을 적용하는데, 자꾸 trend='add'와 trend='mul' 사이에서 고민이 됩니다. 둘 다 해보니 결과가 다르게 나왔습니다.

"도대체 언제 add를 쓰고 언제 mul을 써야 하나요?" 박시니어 씨가 노트를 꺼내며 말했습니다. "비율로 변하면 곱하기, 양으로 변하면 더하기예요."

**가법 모델(Additive)**은 구성요소들을 더해서 결합하고, **승법 모델(Multiplicative)**은 곱해서 결합합니다. 마치 월급 인상을 이야기할 때 "50만원 인상"은 가법적이고, "5% 인상"은 승법적인 것과 같습니다.

데이터의 변동 패턴을 보고 적절한 모델을 선택해야 합니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.holtwinters import ExponentialSmoothing
import pandas as pd
import numpy as np

# 24개월 데이터 생성
months = pd.date_range('2022-01-01', periods=24, freq='M')
base = 100 * (1.05 ** np.arange(24))  # 월 5% 성장
seasonal_factor = 1 + 0.2 * np.sin(np.arange(24) * np.pi / 6)
sales = base * seasonal_factor  # 승법적 계절성
series = pd.Series(sales, index=months)

# 승법 모델 (변동폭이 데이터 크기에 비례)
model_mul = ExponentialSmoothing(
    series, trend='mul', seasonal='mul', seasonal_periods=12
)
# 가법 모델 (변동폭이 일정)
model_add = ExponentialSmoothing(
    series, trend='add', seasonal='add', seasonal_periods=12
)

fit_mul = model_mul.fit()
fit_add = model_add.fit()
print(f"승법 모델 AIC: {fit_mul.aic:.2f}")
print(f"가법 모델 AIC: {fit_add.aic:.2f}")

김개발 씨는 두 가지 모델의 예측 결과를 비교해보았습니다. 가법 모델은 미래로 갈수록 예측이 이상해 보였고, 승법 모델은 그럴듯해 보였습니다.

하지만 왜 그런지 이해할 수 없었습니다. 박시니어 씨가 칠판에 그림을 그리기 시작했습니다.

"쉽게 설명해드릴게요." 가법 모델을 월급에 비유해봅시다. 매달 10만원씩 월급이 오른다고 가정합니다.

처음 월급이 100만원이면, 다음 달은 110만원, 그 다음 달은 120만원입니다. 인상 금액이 항상 10만원으로 일정합니다.

반면 승법 모델은 매달 10%씩 오르는 경우입니다. 처음 월급이 100만원이면, 다음 달은 110만원, 그 다음 달은 121만원입니다.

인상 금액이 10만원에서 11만원으로 점점 커집니다. 시계열 데이터에서 이 차이는 매우 중요합니다.

가법 모델에서는 수준, 추세, 계절성을 모두 더합니다. 수식으로 표현하면 Y = Level + Trend + Seasonal + Error입니다.

매출이 100억이든 1000억이든 계절적 변동이 동일하게 20억이라면 가법 모델이 적합합니다. 승법 모델에서는 곱합니다.

Y = Level x Trend x Seasonal x Error입니다. 매출이 100억일 때 계절 변동이 20%, 1000억일 때도 20%라면 승법 모델이 적합합니다.

위 코드에서 AIC(Akaike Information Criterion)를 출력했습니다. 이것은 모델의 적합도를 나타내는 지표입니다.

AIC가 낮을수록 데이터를 더 잘 설명하는 모델입니다. 두 모델의 AIC를 비교하여 더 적합한 모델을 선택할 수 있습니다.

실무에서 어떻게 판단할까요? 가장 좋은 방법은 시각화입니다.

데이터를 시간에 따라 그래프로 그려보세요. 변동폭이 점점 커지는지, 일정한지 눈으로 확인할 수 있습니다.

주식 가격, 인구 증가, 복리 이자 등은 보통 승법적입니다. 온도 변화, 습도 등은 보통 가법적입니다.

주의할 점이 있습니다. 승법 모델은 0이나 음수 값을 처리할 수 없습니다.

데이터에 0이 포함되어 있다면 가법 모델을 사용하거나, 데이터를 변환해야 합니다. 김개발 씨가 고개를 끄덕였습니다.

"아, 우리 매출은 성장하면서 변동폭도 커지니까 승법 모델이 맞겠네요!" 박시니어 씨가 미소를 지었습니다. "맞아요.

데이터를 이해하면 모델 선택이 쉬워져요."

실전 팁

💡 - 데이터를 로그 변환하면 승법적 패턴을 가법적으로 바꿀 수 있습니다

  • 확신이 없다면 둘 다 시도해보고 AIC나 교차검증 결과로 판단하세요

4. Holt Winters 방법

김개발 씨가 ETS 모델을 잘 활용하게 되었습니다. 그런데 문서를 읽다 보니 Holt-Winters라는 용어가 자꾸 등장합니다.

"ETS랑 Holt-Winters는 다른 건가요?" 박시니어 씨가 웃으며 답했습니다. "같은 가족이에요.

Holt-Winters는 ETS의 특별한 경우죠."

Holt-Winters 방법은 추세와 계절성을 모두 고려하는 지수평활법의 확장입니다. Charles Holt가 추세를 추가하고, Peter Winters가 계절성을 추가하여 이름이 붙었습니다.

마치 자전거에 보조바퀴를 달아 안정성을 높이듯, 기본 지수평활법에 추세와 계절성이라는 두 개의 보조바퀴를 단 것입니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.holtwinters import ExponentialSmoothing
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')

# 3년간 분기별 매출 데이터
quarters = pd.date_range('2021-01-01', periods=12, freq='Q')
sales = [100, 120, 90, 150,  # 2021년
         110, 130, 100, 165, # 2022년
         120, 145, 110, 180] # 2023년
series = pd.Series(sales, index=quarters)

# Holt-Winters 삼중 지수평활법
model = ExponentialSmoothing(
    series,
    trend='add',
    seasonal='add',
    seasonal_periods=4,  # 분기별 = 4
    initialization_method='estimated'
)
fitted = model.fit(optimized=True)  # 최적 파라미터 자동 추정

# 2024년 예측
forecast = fitted.forecast(4)
print("2024년 분기별 예측:")
for date, value in forecast.items():
    print(f"  {date.strftime('%Y Q%q')}: {value:.1f}")

김개발 씨는 역사를 알면 이해가 깊어진다는 말을 떠올렸습니다. 지수평활법의 역사는 어떻게 될까요?

1957년, Charles Holt라는 연구자가 단순 지수평활법에 추세 개념을 추가했습니다. 데이터가 오르거나 내리는 경향을 예측에 반영한 것이죠.

이것을 이중 지수평활법 또는 Holt 방법이라고 부릅니다. 그로부터 3년 후인 1960년, Peter Winters가 여기에 계절성까지 추가했습니다.

이것이 바로 삼중 지수평활법 또는 Holt-Winters 방법입니다. 세 명의 선배 연구자들의 아이디어가 하나로 합쳐진 것입니다.

마치 라면의 진화와 비슷합니다. 처음에는 면만 있었습니다.

누군가 스프를 추가했고, 또 누군가 건더기를 추가했습니다. 면만 있던 라면이 스프와 건더기가 더해져 완전한 한 끼 식사가 된 것처럼, 단순 지수평활법도 추세와 계절성이 더해져 강력한 예측 도구가 되었습니다.

Holt-Winters 방법에는 세 개의 평활 계수가 있습니다. alpha는 수준을 평활화합니다.

데이터의 기본적인 높낮이를 조절합니다. beta는 추세를 평활화합니다.

상승 또는 하락 기울기의 변화에 얼마나 민감하게 반응할지 결정합니다. gamma는 계절성을 평활화합니다.

계절 패턴의 변화를 얼마나 빠르게 반영할지 조절합니다. 위 코드에서 optimized=True를 설정하면, 알고리즘이 최적의 alpha, beta, gamma 값을 자동으로 찾아줍니다.

직접 설정하는 것보다 훨씬 편리하고 정확합니다. initialization_method='estimated'는 초기값 설정 방법입니다.

지수평활법은 시작점이 필요한데, 이 옵션은 데이터에서 최적의 초기값을 추정하도록 합니다. 실무에서 Holt-Winters는 언제 사용할까요?

분기별 실적 보고, 월별 매출 예측, 주간 트래픽 예측 등 명확한 계절 패턴이 있을 때 매우 유용합니다. 특히 2년 이상의 데이터가 있다면 더욱 안정적인 예측이 가능합니다.

김개발 씨가 자신의 코드를 다시 살펴봅니다. "그러니까 제가 쓰던 ExponentialSmoothing이 바로 Holt-Winters 방법이었군요!" 박시니어 씨가 고개를 끄덕였습니다.

"맞아요. 같은 도구의 다른 이름일 뿐이에요."

실전 팁

💡 - 최소 2년 이상의 데이터가 있어야 계절성을 안정적으로 추정할 수 있습니다

  • damped_trend=True 옵션을 사용하면 장기 예측에서 추세가 과도하게 발산하는 것을 방지할 수 있습니다

5. 감쇠 추세와 장기 예측

김개발 씨가 5년 후 매출을 예측해보았습니다. 그런데 결과가 이상했습니다.

현재 매출의 10배가 넘는 숫자가 나온 것입니다. "이건 너무 낙관적인데요..." 박시니어 씨가 화면을 보더니 말했습니다.

"감쇠 추세를 적용해봐요. 현실에서 성장은 영원히 지속되지 않거든요."

**감쇠 추세(Damped Trend)**는 추세가 시간이 지날수록 점점 약해지도록 하는 기법입니다. 마치 던진 공이 점점 느려지다가 멈추는 것처럼, 성장세도 영원하지 않습니다.

장기 예측에서 비현실적으로 높거나 낮은 값이 나오는 것을 방지해줍니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.holtwinters import ExponentialSmoothing
import pandas as pd
import numpy as np

# 5년간 연간 매출 데이터
years = pd.date_range('2019-01-01', periods=5, freq='Y')
sales = [100, 120, 138, 152, 163]  # 성장률 둔화 패턴
series = pd.Series(sales, index=years)

# 일반 추세 모델
model_normal = ExponentialSmoothing(series, trend='add')
fit_normal = model_normal.fit()

# 감쇠 추세 모델
model_damped = ExponentialSmoothing(
    series, trend='add', damped_trend=True
)
fit_damped = model_damped.fit()

# 5년 후 예측 비교
print("5년 후 매출 예측:")
print(f"  일반 추세: {fit_normal.forecast(5).iloc[-1]:.1f}")
print(f"  감쇠 추세: {fit_damped.forecast(5).iloc[-1]:.1f}")

김개발 씨는 상사에게 5년 매출 전망을 보고했습니다. "5년 후 매출이 현재의 3배가 될 것으로 예측됩니다." 상사가 의아한 표정을 지었습니다.

"우리 시장이 포화 상태인데 그게 가능할까요?" 박시니어 씨가 설명을 시작했습니다. "현실에서는 성장이 영원히 지속되지 않아요.

시장이 포화되고, 경쟁이 심화되고, 여러 제약이 생기죠." 이것을 **S자 곡선(S-curve)**이라고 합니다. 처음에는 천천히 시작하고, 중간에 폭발적으로 성장하다가, 어느 순간 성장이 둔화됩니다.

스마트폰 보급률, SNS 가입자 수, 신기술 채택률 등 많은 현상이 이 패턴을 따릅니다. 감쇠 추세는 바로 이 현상을 반영합니다.

마치 자동차가 브레이크를 밟지 않아도 마찰력 때문에 점점 느려지는 것처럼, 감쇠 추세 모델에서는 추세가 자연스럽게 약해집니다. 수학적으로는 **감쇠 계수(phi)**를 곱해서 추세를 점점 줄입니다.

phi 값은 0과 1 사이입니다. phi가 0.8이라면, 매 시점마다 추세가 0.8배로 줄어듭니다.

처음 추세가 10이었다면, 다음 시점에는 8, 그 다음에는 6.4로 점점 작아집니다. phi가 1이면 감쇠가 없어서 일반 추세 모델과 같아집니다.

위 코드에서 damped_trend=True만 추가하면 감쇠 추세가 적용됩니다. 간단하지만 효과는 큽니다.

일반 모델은 계속 상승하는 직선을 그리지만, 감쇠 모델은 점점 평평해지는 곡선을 그립니다. 언제 감쇠 추세를 사용해야 할까요?

첫째, 장기 예측을 할 때입니다. 1-2개월 예측에는 큰 차이가 없지만, 1년 이상을 예측할 때는 감쇠 추세가 더 현실적입니다.

둘째, 성숙한 시장을 다룰 때입니다. 스타트업 초기의 급성장 시기보다는, 시장이 어느 정도 형성된 후에 감쇠 추세가 적합합니다.

셋째, 보수적인 예측이 필요할 때입니다. 투자 의사결정이나 예산 계획에서는 낙관적인 예측보다 현실적인 예측이 더 안전합니다.

김개발 씨가 감쇠 추세를 적용한 결과를 다시 보고했습니다. "5년 후 매출은 현재의 1.5배 정도로 예상됩니다." 상사가 고개를 끄덕였습니다.

"이 정도가 더 현실적이네요."

실전 팁

💡 - 연구에 따르면 감쇠 추세 모델이 장기 예측에서 일반적으로 더 정확합니다

  • phi 값은 보통 0.8~0.98 사이가 적절하며, 자동 최적화로 찾는 것이 좋습니다

6. 자동 모델 선택

김개발 씨는 이제 ETS의 다양한 옵션을 알게 되었습니다. 하지만 새로운 고민이 생겼습니다.

"추세는 add? mul?

계절성은? 감쇠는 적용할까?" 매번 직접 결정하기가 어려웠습니다.

박시니어 씨가 말했습니다. "ETSModel을 써보세요.

알아서 최적의 조합을 찾아줍니다."

자동 모델 선택은 가능한 모든 ETS 조합을 시도해보고, 가장 적합한 모델을 자동으로 선택하는 기능입니다. 마치 옷가게에서 모든 옷을 입어보고 가장 잘 맞는 옷을 고르는 것과 같습니다.

AIC, BIC 같은 지표를 기준으로 최적의 모델을 찾아줍니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.exponential_smoothing.ets import ETSModel
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')

# 3년간 월별 데이터
months = pd.date_range('2021-01-01', periods=36, freq='M')
np.random.seed(42)
trend = np.arange(36) * 0.5
seasonal = 10 * np.sin(np.arange(36) * np.pi / 6)
noise = np.random.normal(0, 2, 36)
sales = 100 + trend + seasonal + noise
series = pd.Series(sales, index=months)

# ETSModel로 자동 피팅
model = ETSModel(
    series,
    error='add',       # 오차 유형
    trend='add',       # 추세 유형
    seasonal='add',    # 계절성 유형
    seasonal_periods=12
)
fitted = model.fit()

# 모델 요약 및 예측
print(f"선택된 모델: ETS(A,A,A)")
print(f"AIC: {fitted.aic:.2f}")
print(f"\n향후 3개월 예측:")
print(fitted.forecast(3))

김개발 씨는 지금까지 배운 내용을 정리해보았습니다. 오차는 가법 또는 승법, 추세는 없음, 가법, 승법, 또는 감쇠 가법과 감쇠 승법, 계절성도 없음, 가법, 승법.

조합이 너무 많았습니다. 간단히 계산해보면, 오차 2가지 x 추세 5가지 x 계절성 3가지 = 30가지 조합이 가능합니다.

매번 모든 조합을 시도해볼 수는 없는 노릇입니다. 박시니어 씨가 화이트보드에 표를 그렸습니다.

ETS 모델의 표기법은 세 글자로 이루어집니다. 첫 번째는 오차(Error), 두 번째는 추세(Trend), 세 번째는 계절성(Seasonal)입니다.

각 위치에 N(없음), A(가법), M(승법)이 들어갑니다. 예를 들어 ETS(A,A,A)는 오차, 추세, 계절성 모두 가법적인 모델입니다.

ETS(M,M,M)은 모두 승법적입니다. ETS(A,N,N)은 오차만 가법이고 추세와 계절성이 없는, 즉 단순 지수평활법입니다.

실무에서는 어떻게 최적의 모델을 찾을까요? 첫 번째 방법은 **정보 기준(Information Criteria)**을 활용하는 것입니다.

AIC(Akaike Information Criterion)나 BIC(Bayesian Information Criterion) 값이 낮을수록 좋은 모델입니다. 모든 조합을 시도해보고 가장 낮은 값을 가진 모델을 선택합니다.

두 번째 방법은 **교차검증(Cross-Validation)**입니다. 데이터를 훈련 세트와 테스트 세트로 나누고, 테스트 세트에서 예측 오차가 가장 작은 모델을 선택합니다.

위 코드의 ETSModel은 statsmodels의 새로운 ETS 구현입니다. 기존의 ExponentialSmoothing보다 더 유연하고, 상태공간(State Space) 프레임워크를 기반으로 합니다.

R 언어에서는 forecast 패키지의 ets() 함수가 자동으로 최적 모델을 선택해줍니다. Python에서 유사한 기능을 원한다면 pmdarima나 sktime 라이브러리를 고려해보세요.

김개발 씨가 여러 조합을 시도한 후 말했습니다. "ETS(A,Ad,A)가 AIC가 가장 낮네요!" Ad는 감쇠 가법 추세를 의미합니다.

박시니어 씨가 미소를 지었습니다. "데이터가 말해주는 대로 따르면 됩니다."

실전 팁

💡 - 모델 선택에 정답은 없습니다. 여러 지표를 종합적으로 고려하세요

  • 자동 선택 결과도 항상 시각화를 통해 검증하는 것이 좋습니다

7. 예측 성능 평가

김개발 씨가 ETS 모델로 예측을 완료했습니다. 하지만 "이 예측이 얼마나 정확한가요?"라는 질문에 답할 수 없었습니다.

박시니어 씨가 물었습니다. "예측 성능은 어떻게 측정하셨어요?" 김개발 씨는 당황했습니다.

성능 측정을 한 적이 없었습니다.

예측 성능 평가는 모델이 얼마나 정확하게 예측하는지 수치로 측정하는 과정입니다. 마치 시험을 보고 점수를 받는 것처럼, 모델도 평가를 받아야 합니다.

MAE, RMSE, MAPE 등의 지표를 사용하여 예측 오차를 정량화합니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.holtwinters import ExponentialSmoothing
import pandas as pd
import numpy as np

# 데이터 생성
np.random.seed(42)
data = 100 + np.arange(36) * 2 + np.random.normal(0, 5, 36)
series = pd.Series(data)

# 훈련/테스트 분리 (마지막 6개월을 테스트로)
train = series[:-6]
test = series[-6:]

# 모델 학습 및 예측
model = ExponentialSmoothing(train, trend='add')
fitted = model.fit()
predictions = fitted.forecast(6)

# 성능 지표 계산
def evaluate_forecast(actual, predicted):
    mae = np.mean(np.abs(actual - predicted))
    rmse = np.sqrt(np.mean((actual - predicted) ** 2))
    mape = np.mean(np.abs((actual - predicted) / actual)) * 100
    return {'MAE': mae, 'RMSE': rmse, 'MAPE': mape}

metrics = evaluate_forecast(test.values, predictions.values)
for name, value in metrics.items():
    print(f"{name}: {value:.2f}")

김개발 씨는 중요한 교훈을 얻었습니다. 예측 모델은 반드시 평가해야 한다는 것입니다.

하지만 어떻게 평가해야 할까요? 박시니어 씨가 핵심을 짚었습니다.

"예측할 데이터로 학습하면 안 돼요. 그건 시험지를 미리 보고 시험 보는 것과 같아요." 이것을 훈련-테스트 분리라고 합니다.

전체 데이터 중 일부는 모델 학습에 사용하고, 나머지는 성능 평가에 사용합니다. 시계열 데이터에서는 보통 최근 데이터를 테스트용으로 남깁니다.

그렇다면 어떤 지표로 성능을 측정할까요? **MAE(Mean Absolute Error)**는 평균 절대 오차입니다.

예측값과 실제값의 차이를 절대값으로 바꾸고 평균을 냅니다. 해석이 직관적입니다.

MAE가 5라면, 평균적으로 5만큼 틀린다는 뜻입니다. **RMSE(Root Mean Square Error)**는 평균 제곱근 오차입니다.

오차를 제곱하고 평균을 낸 뒤 제곱근을 취합니다. 큰 오차에 더 민감하게 반응합니다.

하나의 큰 실수가 전체 점수를 크게 떨어뜨립니다. **MAPE(Mean Absolute Percentage Error)**는 평균 백분율 오차입니다.

오차를 실제값으로 나누어 백분율로 표현합니다. MAPE가 10%라면, 평균적으로 10% 정도 틀린다는 의미입니다.

세 지표 중 무엇을 사용해야 할까요? 상황에 따라 다릅니다.

MAE는 모든 오차를 동등하게 취급합니다. RMSE는 큰 오차를 더 심각하게 봅니다.

재고 예측처럼 큰 실수가 치명적인 경우 RMSE가 적합합니다. MAPE는 스케일이 다른 여러 제품의 예측을 비교할 때 유용합니다.

위 코드에서 훈련 데이터로 모델을 학습하고, 테스트 데이터로 예측한 뒤 성능을 측정했습니다. 이것이 올바른 평가 방법입니다.

실무에서는 시계열 교차검증을 사용하기도 합니다. 시간 순서를 유지하면서 여러 번 훈련-테스트를 반복하는 방법입니다.

더 안정적인 성능 추정이 가능합니다. 김개발 씨가 성능 지표를 확인했습니다.

"MAPE가 8%네요. 이게 좋은 건가요?" 박시니어 씨가 답했습니다.

"일반적으로 10% 이하면 꽤 좋은 예측이에요. 하지만 비즈니스 맥락에 따라 기준이 달라집니다."

실전 팁

💡 - 시계열 데이터는 반드시 시간 순서를 유지하며 분리해야 합니다. 무작위 분리는 안 됩니다

  • 하나의 지표만 보지 말고 여러 지표를 종합적으로 판단하세요

8. 실무 예측 파이프라인

김개발 씨가 이제 ETS 모델을 자신 있게 다룰 수 있게 되었습니다. 하지만 실제 서비스에 적용하려니 고민이 됩니다.

"매번 수동으로 돌릴 수는 없잖아요?" 박시니어 씨가 고개를 끄덕였습니다. "맞아요.

실무에서는 자동화된 파이프라인이 필요해요."

예측 파이프라인은 데이터 수집부터 예측, 결과 저장까지 전 과정을 자동화한 시스템입니다. 마치 공장의 조립 라인처럼, 데이터가 들어오면 자동으로 처리되어 예측 결과가 출력됩니다.

안정적인 서비스를 위해 에러 처리와 로깅도 포함해야 합니다.

다음 코드를 살펴봅시다.

from statsmodels.tsa.holtwinters import ExponentialSmoothing
import pandas as pd
import numpy as np
from datetime import datetime
import logging

# 로깅 설정
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class ETSForecaster:
    """ETS 예측 파이프라인"""

    def __init__(self, seasonal_periods=12):
        self.seasonal_periods = seasonal_periods
        self.model = None

    def fit_predict(self, data: pd.Series, horizon: int) -> pd.Series:
        """모델 학습 및 예측"""
        logger.info(f"학습 시작: {len(data)}개 데이터")

        # 데이터 검증
        if len(data) < 2 * self.seasonal_periods:
            logger.warning("데이터 부족, 단순 모델 사용")
            model = ExponentialSmoothing(data, trend='add')
        else:
            model = ExponentialSmoothing(
                data, trend='add', seasonal='add',
                seasonal_periods=self.seasonal_periods
            )

        self.model = model.fit()
        forecast = self.model.forecast(horizon)
        logger.info(f"예측 완료: {horizon}개 시점")
        return forecast

# 사용 예시
forecaster = ETSForecaster(seasonal_periods=12)
data = pd.Series([100 + i*2 + np.sin(i)*10 for i in range(36)])
result = forecaster.fit_predict(data, horizon=6)
print(f"예측 결과:\n{result}")

김개발 씨는 주피터 노트북에서 분석하던 코드를 실제 서비스에 적용해야 했습니다. 하지만 노트북 코드를 그대로 사용할 수는 없었습니다.

여러 가지 문제가 있었습니다. 첫 번째 문제는 재현성이었습니다.

노트북에서 이것저것 시도하다 보니, 어떤 설정이 최종 결과를 만들었는지 불분명했습니다. 두 번째 문제는 에러 처리였습니다.

데이터가 비어있거나 이상한 값이 들어오면 코드가 멈췄습니다. 세 번째 문제는 추적이었습니다.

언제, 어떤 데이터로, 어떤 결과가 나왔는지 기록이 없었습니다. 박시니어 씨가 조언했습니다.

"프로덕션 코드는 다르게 접근해야 해요." 위 코드는 실무에서 사용할 수 있는 예측 파이프라인의 기본 구조입니다. 먼저 클래스로 캡슐화했습니다.

설정값과 상태를 하나로 묶어 관리합니다. 다른 팀원도 쉽게 사용할 수 있고, 테스트도 용이합니다.

로깅을 추가했습니다. 학습 시작, 완료, 경고 상황 등을 기록합니다.

문제가 발생했을 때 원인을 추적할 수 있습니다. 데이터 검증도 포함했습니다.

데이터가 충분하지 않으면 간단한 모델로 대체합니다. 무작정 에러를 발생시키는 것보다 우아하게 처리하는 것이 좋습니다.

실제 서비스에서는 더 많은 것이 필요합니다. 스케줄링이 필요합니다.

매일 또는 매주 자동으로 예측을 실행해야 합니다. Airflow, Prefect 같은 워크플로우 도구를 활용합니다.

모니터링도 중요합니다. 예측 성능이 갑자기 나빠지면 알림을 받아야 합니다.

예측값과 실제값을 지속적으로 비교하는 시스템이 필요합니다. 버전 관리도 고려해야 합니다.

모델이 업데이트될 때마다 이전 버전과 비교할 수 있어야 합니다. 김개발 씨가 파이프라인을 완성하고 배포했습니다.

이제 매일 아침 자동으로 예측 결과가 생성됩니다. 상사가 만족스러워했습니다.

"이제 매번 요청하지 않아도 되겠네요!"

실전 팁

💡 - 프로덕션 코드에서는 예외 처리를 철저히 하고, 모든 단계에서 로그를 남기세요

  • 예측 결과와 함께 신뢰 구간도 저장하면 의사결정에 도움이 됩니다

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

#Python#ETS#TimeSeries#Forecasting#ExponentialSmoothing#Data Science

댓글 (0)

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