🤖

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

⚠️

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

이미지 로딩 중...

Prophet 하이퍼파라미터 튜닝 완벽 가이드 - 슬라이드 1/9
A

AI Generated

2025. 12. 3. · 12 Views

Prophet 하이퍼파라미터 튜닝 완벽 가이드

Facebook의 시계열 예측 라이브러리 Prophet의 하이퍼파라미터를 튜닝하는 방법을 초급자도 이해할 수 있도록 설명합니다. 실무에서 바로 활용할 수 있는 튜닝 기법과 최적화 전략을 다룹니다.


목차

  1. changepoint_prior_scale 이해하기
  2. seasonality_prior_scale 조절하기
  3. holidays_prior_scale 설정하기
  4. 교차 검증으로 최적 파라미터 찾기
  5. growth 파라미터로 성장 패턴 지정하기
  6. 맞춤형 계절성 추가하기
  7. 이상치와 결측치 처리하기
  8. 모델 성능 시각화와 진단

1. changepoint prior scale 이해하기

김개발 씨는 이커머스 회사에서 매출 예측 모델을 만들고 있었습니다. Prophet으로 첫 모델을 만들었는데, 예측 그래프가 너무 직선에 가까워서 실제 데이터의 급격한 변화를 따라가지 못했습니다.

"어떻게 하면 이 모델이 추세 변화를 더 잘 잡아낼 수 있을까요?"

changepoint_prior_scale은 Prophet 모델이 추세 변화에 얼마나 민감하게 반응할지 결정하는 핵심 파라미터입니다. 마치 자동차의 핸들 민감도와 같습니다.

값이 크면 작은 변화에도 빠르게 반응하고, 값이 작으면 큰 추세만 따라갑니다. 기본값은 0.05이며, 0.001에서 0.5 사이에서 조절합니다.

다음 코드를 살펴봅시다.

from prophet import Prophet
import pandas as pd

# 매출 데이터 로드
df = pd.read_csv('sales_data.csv')

# changepoint_prior_scale 튜닝
# 기본값 0.05보다 높이면 추세 변화에 더 민감해집니다
model = Prophet(
    changepoint_prior_scale=0.1,  # 유연성 증가
    n_changepoints=25  # 변화점 후보 개수
)

# 모델 학습 및 예측
model.fit(df)
future = model.make_future_dataframe(periods=30)
forecast = model.predict(future)

김개발 씨는 입사 6개월 차 데이터 분석가입니다. 오늘 팀장님께서 다음 분기 매출 예측 리포트를 요청하셨습니다.

김개발 씨는 Prophet을 사용해 모델을 만들었지만, 결과가 영 마음에 들지 않았습니다. 그래프를 보니 실제 매출 데이터는 블랙프라이데이나 연말 시즌에 급격히 치솟았다가 떨어지는 패턴을 보이는데, Prophet의 예측선은 너무 완만했습니다.

마치 산맥을 그려야 하는데 언덕만 그린 것 같았습니다. 옆자리 박시니어 씨가 화면을 슬쩍 보더니 말했습니다.

"changepoint_prior_scale 값을 조절해 봤어요?" 그렇다면 changepoint_prior_scale이란 정확히 무엇일까요? 쉽게 비유하자면, 이 파라미터는 마치 그림을 그리는 화가의 붓 굵기와 같습니다.

굵은 붓으로 그리면 대략적인 형태만 표현되고, 가는 붓으로 그리면 세밀한 디테일까지 표현할 수 있습니다. changepoint_prior_scale이 작으면 굵은 붓처럼 큰 추세만 잡고, 값이 크면 가는 붓처럼 작은 변화까지 포착합니다.

Prophet은 시계열 데이터에서 추세가 바뀌는 지점, 즉 **변화점(changepoint)**을 자동으로 찾아냅니다. 매출이 갑자기 증가하거나 감소하는 시점이 바로 변화점입니다.

changepoint_prior_scale은 이 변화점에서 얼마나 급격한 변화를 허용할지 결정합니다. 기본값인 0.05는 보수적인 설정입니다.

대부분의 경우 잘 작동하지만, 데이터에 급격한 변화가 많다면 모델이 이를 제대로 반영하지 못할 수 있습니다. 이럴 때 값을 0.1이나 0.2로 높이면 모델이 더 유연해집니다.

위 코드에서 changepoint_prior_scale을 0.1로 설정한 이유가 바로 이것입니다. 이커머스 데이터는 프로모션이나 시즌 이벤트로 인해 급격한 변화가 잦기 때문입니다.

하지만 주의할 점이 있습니다. 값을 너무 높이면 **과적합(overfitting)**이 발생할 수 있습니다.

모델이 노이즈까지 학습해버려서 미래 예측이 오히려 부정확해집니다. 마치 화가가 너무 세밀하게 그리다가 먼지 자국까지 그려버리는 것과 같습니다.

반대로 값을 너무 낮추면 **과소적합(underfitting)**이 됩니다. 중요한 추세 변화를 놓쳐서 예측이 현실과 동떨어지게 됩니다.

실무에서는 보통 0.001, 0.01, 0.1, 0.5 같은 값들을 시험해보며 최적값을 찾습니다. 교차 검증을 통해 어떤 값이 가장 좋은 예측 성능을 보이는지 확인하는 것이 좋습니다.

김개발 씨는 값을 0.1로 조절한 뒤 다시 그래프를 확인했습니다. 이제 예측선이 실제 데이터의 급격한 변화를 훨씬 잘 따라가고 있었습니다.

"오, 확실히 다르네요!"

실전 팁

💡 - 데이터에 급격한 변화가 많으면 0.1~0.3으로 높이고, 안정적인 데이터면 기본값 0.05를 유지하세요

  • 여러 값을 시험할 때는 cross_validation 함수로 성능을 비교하세요

2. seasonality prior scale 조절하기

매출 예측 모델을 개선한 김개발 씨에게 새로운 과제가 주어졌습니다. 이번에는 웹사이트 트래픽 예측입니다.

데이터를 보니 주말마다 트래픽이 급감하고, 월요일에 다시 치솟는 패턴이 뚜렷했습니다. "이 주간 패턴을 더 강하게 반영하려면 어떻게 해야 하지?"

seasonality_prior_scale은 계절성 효과의 강도를 조절하는 파라미터입니다. 마치 음악의 볼륨 조절기와 같습니다.

값이 크면 계절성 패턴이 더 뚜렷하게 반영되고, 값이 작으면 계절성이 완만해집니다. 기본값은 10이며, 데이터의 계절성 강도에 따라 조절합니다.

다음 코드를 살펴봅시다.

from prophet import Prophet

# 웹 트래픽 데이터
df = pd.read_csv('web_traffic.csv')

# seasonality_prior_scale 튜닝
model = Prophet(
    seasonality_prior_scale=15,  # 계절성 효과 강화
    yearly_seasonality=True,
    weekly_seasonality=True,
    daily_seasonality=False  # 일간 패턴은 비활성화
)

# 커스텀 계절성 추가 (월간 패턴)
model.add_seasonality(
    name='monthly',
    period=30.5,
    fourier_order=5
)

model.fit(df)

김개발 씨는 트래픽 데이터를 분석하면서 흥미로운 패턴을 발견했습니다. 평일에는 트래픽이 높고, 주말에는 뚝 떨어집니다.

또한 매월 월급날 즈음에 트래픽이 살짝 올라가는 경향도 있었습니다. Prophet은 이런 반복적인 패턴을 **계절성(seasonality)**이라고 부릅니다.

1년을 주기로 반복되는 연간 계절성, 1주를 주기로 반복되는 주간 계절성, 하루를 주기로 반복되는 일간 계절성이 있습니다. 하지만 기본 설정으로 모델을 돌려보니, 주말 트래픽 감소가 실제보다 약하게 표현되었습니다.

실제로는 50% 가까이 떨어지는데, 예측에서는 30% 정도만 반영된 것입니다. 박시니어 씨가 조언했습니다.

"seasonality_prior_scale 값을 높여보세요. 계절성 신호가 더 강하게 반영될 거예요." seasonality_prior_scale은 계절성 효과에 얼마나 큰 변동을 허용할지 결정합니다.

쉽게 말해, 이 값이 크면 Prophet이 "이 데이터에서 계절성 패턴이 정말 중요하구나"라고 판단하고 더 강하게 반영합니다. 기본값인 10은 대부분의 경우에 적절합니다.

하지만 데이터에서 계절성 패턴이 매우 뚜렷하다면 값을 높여야 합니다. 반대로 계절성이 약하거나 노이즈가 많다면 값을 낮춰서 과적합을 방지해야 합니다.

위 코드에서 주목할 부분이 하나 더 있습니다. add_seasonality 메서드로 커스텀 계절성을 추가한 것입니다.

Prophet은 기본적으로 연간, 주간, 일간 계절성만 제공하지만, 월간 패턴처럼 다른 주기의 패턴도 직접 추가할 수 있습니다. fourier_order 파라미터는 계절성 패턴의 복잡도를 결정합니다.

값이 클수록 더 복잡한 패턴을 표현할 수 있지만, 과적합 위험도 높아집니다. 보통 연간 계절성은 10, 주간 계절성은 3 정도를 사용합니다.

김개발 씨는 seasonality_prior_scale을 15로 높이고 월간 계절성도 추가했습니다. 결과를 확인하니 주말 트래픽 감소와 월급날 상승 패턴이 잘 반영되어 있었습니다.

다만 한 가지 주의할 점이 있습니다. 계절성을 너무 강하게 설정하면 실제로는 우연의 일치인 패턴까지 학습할 수 있습니다.

예를 들어 데이터가 1년치밖에 없는데 연간 계절성을 강하게 설정하면, 그 해에만 있었던 특이한 현상을 매년 반복되는 패턴으로 착각할 수 있습니다.

실전 팁

💡 - 계절성 패턴이 뚜렷한 데이터는 1520으로 높이고, 노이즈가 많은 데이터는 58로 낮추세요

  • 최소 2개 주기 이상의 데이터가 있을 때 해당 계절성을 활성화하세요 (주간 계절성이면 2주 이상)

3. holidays prior scale 설정하기

추석 연휴가 끝난 후 김개발 씨는 예측 모델의 오차를 분석하고 있었습니다. 유독 명절 기간에 예측이 크게 빗나갔습니다.

"명절이나 공휴일의 영향을 모델에 반영할 수 있는 방법이 있을까요?"

holidays_prior_scale은 공휴일이나 특별 이벤트의 영향력을 조절하는 파라미터입니다. 마치 특정 날짜에 스포트라이트를 비추는 것과 같습니다.

값이 크면 공휴일의 영향이 강하게 반영되고, 값이 작으면 완만하게 반영됩니다. 기본값은 10입니다.

다음 코드를 살펴봅시다.

from prophet import Prophet
import pandas as pd

# 한국 공휴일 정의
holidays = pd.DataFrame({
    'holiday': 'korean_holidays',
    'ds': pd.to_datetime([
        '2024-01-01', '2024-02-09', '2024-02-10', '2024-02-11',
        '2024-03-01', '2024-05-05', '2024-06-06', '2024-08-15',
        '2024-09-16', '2024-09-17', '2024-09-18', '2024-10-03',
        '2024-10-09', '2024-12-25'
    ]),
    'lower_window': -1,  # 공휴일 1일 전부터
    'upper_window': 1    # 공휴일 1일 후까지 영향
})

model = Prophet(
    holidays=holidays,
    holidays_prior_scale=15  # 공휴일 효과 강화
)
model.fit(df)

김개발 씨가 분석한 예측 오차 리포트에서 흥미로운 패턴이 보였습니다. 평소에는 오차율이 5% 내외인데, 추석이나 설날 연휴에는 오차율이 20%까지 치솟았습니다.

명절에는 사람들의 행동 패턴이 완전히 달라지기 때문입니다. Prophet에서는 이런 특별한 날을 holidays로 정의하여 모델에 반영할 수 있습니다.

단순히 공휴일뿐만 아니라 블랙프라이데이, 광군제, 회사 창립기념일 등 어떤 이벤트든 추가할 수 있습니다. holidays 데이터프레임을 만들 때 중요한 점은 lower_windowupper_window 설정입니다.

추석 당일뿐만 아니라 연휴 전날부터 쇼핑이 증가하고, 연휴 다음 날도 여파가 남을 수 있습니다. lower_window를 -1로 설정하면 공휴일 하루 전부터, upper_window를 1로 설정하면 공휴일 하루 후까지 영향을 받는다고 모델에 알려주는 것입니다.

holidays_prior_scale은 이 공휴일 효과를 얼마나 강하게 반영할지 결정합니다. 쇼핑몰처럼 공휴일에 매출이 급변하는 비즈니스는 값을 높게 설정해야 합니다.

반면 B2B 서비스처럼 공휴일 영향이 크지 않은 비즈니스는 기본값이나 더 낮은 값을 사용합니다. 실무에서 자주 하는 실수 중 하나는 공휴일 목록을 불완전하게 만드는 것입니다.

한국에서 서비스한다면 한국 공휴일만 넣으면 되지만, 글로벌 서비스라면 각 국가의 공휴일을 모두 고려해야 합니다. 다행히 holidays 라이브러리를 사용하면 각국의 공휴일을 쉽게 가져올 수 있습니다.

또 하나 주의할 점은 공휴일 효과의 방향입니다. 어떤 비즈니스는 공휴일에 매출이 증가하고, 어떤 비즈니스는 감소합니다.

Prophet은 데이터에서 이 방향을 자동으로 학습하므로, 충분한 학습 데이터가 있다면 걱정하지 않아도 됩니다. 김개발 씨는 한국 공휴일 목록을 만들고 holidays_prior_scale을 15로 설정했습니다.

다시 예측을 돌려보니 명절 기간의 오차율이 10% 이하로 크게 개선되었습니다.

실전 팁

💡 - 공휴일별로 영향력이 다르다면 별도의 holiday 이름을 지정하여 구분하세요

  • lower_window와 upper_window는 비즈니스 특성에 맞게 설정하세요 (여행업은 공휴일 1주 전부터 영향)

4. 교차 검증으로 최적 파라미터 찾기

김개발 씨는 여러 파라미터를 조절해가며 모델을 개선했습니다. 하지만 문득 의문이 들었습니다.

"내가 설정한 이 값들이 정말 최적인 걸까? 객관적으로 비교할 방법이 있을까요?"

Prophet의 cross_validation 함수를 사용하면 시계열 데이터에 맞는 교차 검증을 수행할 수 있습니다. 마치 시험을 여러 번 봐서 실력을 정확히 측정하는 것과 같습니다.

과거 데이터로 학습하고 미래 데이터로 검증하는 과정을 여러 번 반복하여 모델의 진짜 성능을 평가합니다.

다음 코드를 살펴봅시다.

from prophet import Prophet
from prophet.diagnostics import cross_validation, performance_metrics
import itertools

# 튜닝할 파라미터 조합 정의
param_grid = {
    'changepoint_prior_scale': [0.01, 0.1, 0.5],
    'seasonality_prior_scale': [1, 10, 15],
}

# 모든 조합 생성
all_params = [dict(zip(param_grid.keys(), v))
              for v in itertools.product(*param_grid.values())]

results = []
for params in all_params:
    model = Prophet(**params)
    model.fit(df)

    # 교차 검증 수행
    df_cv = cross_validation(
        model, initial='365 days',
        period='30 days', horizon='90 days'
    )
    df_p = performance_metrics(df_cv)
    results.append({'params': params, 'mape': df_p['mape'].mean()})

# 최적 파라미터 찾기
best = min(results, key=lambda x: x['mape'])
print(f"Best params: {best['params']}, MAPE: {best['mape']:.4f}")

머신러닝에서 가장 흔한 실수 중 하나는 학습 데이터에서만 성능이 좋은 모델을 만드는 것입니다. 이런 모델은 새로운 데이터에서 형편없는 성능을 보입니다.

이것이 바로 과적합입니다. 시계열 데이터에서는 이 문제가 더 까다롭습니다.

일반적인 교차 검증처럼 데이터를 무작위로 나누면 안 됩니다. 왜냐하면 시계열에서는 시간 순서가 중요하기 때문입니다.

미래 데이터로 학습하고 과거를 예측하는 것은 현실에서 불가능합니다. Prophet의 cross_validation 함수는 이 문제를 해결합니다.

시간 순서를 유지하면서 여러 번의 검증을 수행합니다. 함수의 파라미터를 살펴보겠습니다.

initial은 첫 학습에 사용할 데이터 기간입니다. 위 코드에서 365일로 설정했으므로, 처음 1년치 데이터로 학습합니다.

horizon은 예측할 기간입니다. 90일로 설정했으므로, 학습 후 90일을 예측합니다.

period는 다음 검증까지의 간격입니다. 30일로 설정했으므로, 30일씩 이동하며 검증을 반복합니다.

결과적으로 1년 학습, 90일 예측, 30일 이동을 반복하면서 여러 시점에서 모델 성능을 측정합니다. 이렇게 하면 특정 시점에서만 우연히 좋은 성능을 보이는 것이 아니라, 전반적으로 안정적인 성능을 보이는 파라미터를 찾을 수 있습니다.

performance_metrics 함수는 교차 검증 결과를 분석하여 다양한 성능 지표를 계산합니다. MAPE(Mean Absolute Percentage Error)는 평균 절대 백분율 오차로, 예측이 실제 값에서 평균적으로 몇 퍼센트 벗어나는지를 보여줍니다.

비즈니스 담당자에게 설명하기 쉬운 지표입니다. 위 코드에서는 그리드 서치를 사용하여 모든 파라미터 조합을 시험합니다.

3x3 = 9개의 조합을 모두 검증하고, 가장 낮은 MAPE를 보이는 조합을 선택합니다. 다만 파라미터 조합이 많아지면 시간이 오래 걸립니다.

실무에서는 먼저 넓은 범위에서 대략적인 최적값을 찾고, 그 주변에서 더 세밀하게 탐색하는 방법을 사용합니다.

실전 팁

💡 - initial은 최소 horizon의 3배 이상으로 설정하세요

  • 데이터가 충분하다면 period를 짧게 하여 더 많은 검증 포인트를 확보하세요
  • MAPE 외에도 MAE, RMSE 등 여러 지표를 함께 확인하세요

5. growth 파라미터로 성장 패턴 지정하기

스타트업에서 일하는 박시니어 씨가 고민에 빠졌습니다. 서비스 론칭 후 사용자가 빠르게 증가하고 있지만, 시장 규모를 고려하면 무한정 성장할 수는 없습니다.

"성장에 한계가 있는 상황을 모델에 어떻게 반영할 수 있을까요?"

Prophet의 growth 파라미터는 데이터의 성장 패턴을 지정합니다. 기본값인 linear는 무한히 선형 성장하는 패턴이고, logistic은 상한선이 있는 S자형 성장 패턴입니다.

마치 나무가 자라는 것처럼, 초반에는 빠르게 성장하다가 어느 수준에서 성장이 멈추는 패턴을 표현할 수 있습니다.

다음 코드를 살펴봅시다.

from prophet import Prophet
import pandas as pd

# 사용자 수 데이터
df = pd.read_csv('user_growth.csv')

# 로지스틱 성장 모델 (상한선 있음)
# cap: 최대 도달 가능한 값 (시장 규모)
# floor: 최소값 (보통 0)
df['cap'] = 1000000  # 최대 100만 사용자
df['floor'] = 0

model = Prophet(
    growth='logistic',
    changepoint_prior_scale=0.05
)

model.fit(df)

# 미래 예측 시에도 cap과 floor 설정 필요
future = model.make_future_dataframe(periods=365)
future['cap'] = 1000000
future['floor'] = 0
forecast = model.predict(future)

세상의 많은 것들은 무한히 성장하지 않습니다. 스타트업의 사용자 수는 전체 인구를 넘을 수 없고, 특정 제품의 판매량은 시장 규모를 넘을 수 없습니다.

이런 현실을 모델에 반영하지 않으면 예측이 비현실적으로 치솟을 수 있습니다. Prophet의 기본 성장 모델은 linear, 즉 선형 성장입니다.

현재 추세가 그대로 계속된다고 가정합니다. 매년 10만 명씩 사용자가 증가했다면, 앞으로도 계속 10만 명씩 증가할 것이라고 예측합니다.

하지만 logistic 성장 모델은 다릅니다. 처음에는 빠르게 성장하다가 상한선에 가까워질수록 성장 속도가 느려지는 S자형 곡선을 그립니다.

생태학에서 개체 수 증가를 설명할 때 사용하는 로지스틱 함수와 같은 원리입니다. 로지스틱 성장을 사용하려면 cap(상한선)과 floor(하한선)를 지정해야 합니다.

cap은 도달 가능한 최대값입니다. 위 예시에서는 시장 규모를 분석하여 최대 100만 사용자까지 가능하다고 판단했습니다.

floor는 보통 0으로 설정합니다. 여기서 중요한 점은 cap과 floor가 데이터프레임의 열로 추가되어야 한다는 것입니다.

각 시점마다 다른 상한선을 설정할 수도 있습니다. 예를 들어 새로운 국가에 서비스를 론칭하면 시장 규모가 확대되므로, 그 시점 이후로는 cap을 높일 수 있습니다.

미래 예측 데이터프레임을 만들 때도 cap과 floor를 설정해야 합니다. 이 부분을 빠뜨리면 에러가 발생합니다.

로지스틱 성장 모델을 언제 사용해야 할까요? 일반적으로 시장 규모가 명확하거나, 자원의 한계가 있거나, 포화 상태에 도달할 수 있는 지표를 예측할 때 적합합니다.

반면 매출처럼 이론적으로 상한이 없는 지표는 선형 모델이 더 적합할 수 있습니다. 박시니어 씨는 시장 조사 자료를 바탕으로 cap을 설정하고 로지스틱 모델을 적용했습니다.

이제 예측 그래프가 현실적인 상한선 내에서 완만하게 수렴하는 모습을 보였습니다.

실전 팁

💡 - cap 값은 비즈니스 지식을 바탕으로 현실적으로 설정하세요

  • cap이 불확실하면 여러 시나리오(낙관적, 중립적, 비관적)로 예측해 보세요

6. 맞춤형 계절성 추가하기

김개발 씨의 회사는 월급날인 매월 25일에 매출이 급증하는 패턴이 있었습니다. 하지만 Prophet의 기본 계절성으로는 이런 특수한 패턴을 잡아내기 어려웠습니다.

"특정 날짜에 반복되는 패턴을 직접 정의할 수 있을까요?"

Prophet의 add_seasonality 메서드를 사용하면 기본 제공되지 않는 맞춤형 계절성을 추가할 수 있습니다. 월급날 효과, 분기말 효과 등 비즈니스 특성에 맞는 주기적 패턴을 직접 정의합니다.

fourier_order로 패턴의 복잡도를, prior_scale로 영향력을 조절합니다.

다음 코드를 살펴봅시다.

from prophet import Prophet
import numpy as np

def is_payday(ds):
    """매월 25일 여부를 반환하는 함수"""
    date = pd.to_datetime(ds)
    return (date.day >= 23) & (date.day <= 27)

df = pd.read_csv('sales_data.csv')

# 월급날 효과를 위한 조건 함수
df['is_payday'] = df['ds'].apply(lambda x: is_payday(x))

model = Prophet(weekly_seasonality=True)

# 월간 계절성 추가
model.add_seasonality(
    name='monthly',
    period=30.5,
    fourier_order=5,
    prior_scale=10
)

# 분기 계절성 추가
model.add_seasonality(
    name='quarterly',
    period=91.25,
    fourier_order=8,
    prior_scale=5
)

model.fit(df)

모든 비즈니스는 고유한 리듬이 있습니다. 어떤 회사는 월말에 바쁘고, 어떤 회사는 분기말에 실적 압박을 받습니다.

Prophet의 기본 계절성(연간, 주간, 일간)만으로는 이런 다양한 패턴을 모두 담아내기 어렵습니다. add_seasonality 메서드는 이 문제를 해결합니다.

원하는 주기의 계절성을 직접 정의할 수 있습니다. 핵심 파라미터를 살펴보겠습니다.

period는 패턴이 반복되는 주기를 일(day) 단위로 지정합니다. 월간 패턴이면 30.5일, 분기 패턴이면 91.25일입니다.

fourier_order는 조금 어려운 개념입니다. 쉽게 설명하면, 패턴의 복잡도를 결정합니다.

값이 1이면 단순한 사인 곡선, 값이 클수록 더 복잡한 파형을 표현할 수 있습니다. 마치 그림을 그릴 때 사용하는 색연필 개수와 같습니다.

색연필이 많으면 더 세밀하게 표현할 수 있지만, 너무 많으면 오히려 지저분해질 수 있습니다. 일반적으로 연간 계절성은 10, 주간 계절성은 3, 월간 계절성은 5 정도가 적당합니다.

데이터의 패턴이 복잡하면 높이고, 단순하면 낮춥니다. prior_scale은 앞서 배운 seasonality_prior_scale과 같은 역할을 합니다.

이 특정 계절성의 영향력을 조절합니다. 실무에서 자주 사용되는 맞춤형 계절성을 몇 가지 소개합니다.

월급날 효과는 매월 25일 전후로 소비가 증가하는 패턴입니다. 분기말 효과는 3, 6, 9, 12월 말에 매출이나 계약이 집중되는 B2B 비즈니스에서 흔합니다.

학기 계절성은 교육 관련 비즈니스에서 3월, 9월에 수요가 급증하는 패턴입니다. 계절성을 추가할 때 주의할 점이 있습니다.

해당 주기의 패턴이 최소 2번 이상 반복된 데이터가 있어야 합니다. 1년치 데이터로 2년 주기의 계절성을 학습하는 것은 불가능합니다.

또한 너무 많은 계절성을 추가하면 모델이 복잡해지고 과적합 위험이 높아집니다. 비즈니스적으로 의미 있는 패턴만 선별적으로 추가하세요.

실전 팁

💡 - 새로운 계절성을 추가하기 전에 데이터를 시각화하여 실제로 해당 패턴이 있는지 확인하세요

  • mode 파라미터로 additive(덧셈) 또는 multiplicative(곱셈) 효과를 선택할 수 있습니다

7. 이상치와 결측치 처리하기

코로나19 팬데믹 기간의 매출 데이터를 분석하던 김개발 씨는 곤란에 빠졌습니다. 2020년 데이터가 너무 비정상적이어서 모델이 이상하게 학습되었습니다.

"이런 예외적인 기간의 데이터는 어떻게 처리해야 할까요?"

시계열 데이터에서 **이상치(outlier)**는 모델 학습에 큰 영향을 미칩니다. Prophet에서는 이상치를 처리하는 몇 가지 방법이 있습니다.

해당 기간을 NaN으로 처리하여 학습에서 제외하거나, 별도의 이벤트로 정의하여 효과를 분리할 수 있습니다.

다음 코드를 살펴봅시다.

from prophet import Prophet
import pandas as pd
import numpy as np

df = pd.read_csv('sales_data.csv')
df['ds'] = pd.to_datetime(df['ds'])

# 방법 1: 이상치 기간을 NaN으로 처리 (학습에서 제외)
# 코로나 기간의 데이터를 제외
covid_period = (df['ds'] >= '2020-03-01') & (df['ds'] <= '2020-12-31')
df.loc[covid_period, 'y'] = np.nan

# Prophet은 NaN을 자동으로 무시하고 학습합니다
model = Prophet()
model.fit(df)

# 방법 2: 특별 기간을 이벤트로 처리
covid_event = pd.DataFrame({
    'holiday': 'covid_lockdown',
    'ds': pd.date_range('2020-03-01', '2020-12-31'),
    'lower_window': 0,
    'upper_window': 0
})

model_with_event = Prophet(holidays=covid_event)
model_with_event.fit(df_original)  # 원본 데이터 사용

모든 데이터가 깨끗하면 좋겠지만, 현실은 그렇지 않습니다. 시스템 장애로 데이터가 누락되거나, 코로나19 같은 예외적 상황으로 패턴이 완전히 뒤바뀌기도 합니다.

이런 이상치를 그냥 두면 모델이 잘못된 패턴을 학습합니다. Prophet에서 이상치를 처리하는 가장 간단한 방법은 해당 값을 **NaN(Not a Number)**으로 바꾸는 것입니다.

Prophet은 NaN 값이 있는 행을 자동으로 무시하고 학습합니다. 마치 해당 기간의 데이터가 처음부터 없었던 것처럼 취급합니다.

위 코드에서 2020년 3월부터 12월까지의 데이터를 NaN으로 처리했습니다. 이 기간은 코로나19로 인해 매출 패턴이 완전히 달랐기 때문입니다.

모델은 이 기간을 제외한 나머지 데이터에서 정상적인 패턴을 학습합니다. 하지만 이 방법에는 단점이 있습니다.

해당 기간의 정보를 완전히 버리는 것이기 때문입니다. 만약 2020년에만 있었던 중요한 패턴이 있다면 그것까지 놓치게 됩니다.

두 번째 방법은 이상 기간을 특별 이벤트로 처리하는 것입니다. 코로나 기간을 하나의 holiday로 정의하면, Prophet은 이 기간의 특수한 효과를 별도로 학습합니다.

정상적인 계절성과 추세는 유지하면서, 코로나 효과만 따로 분리하는 것입니다. 어떤 방법을 선택해야 할까요?

이상치가 일시적이고 다시 발생하지 않을 것 같으면 NaN 처리가 좋습니다. 하지만 비슷한 상황이 다시 발생할 수 있다면(예: 감염병 재유행), 이벤트로 처리하여 효과를 학습해 두는 것이 유용합니다.

**결측치(missing value)**도 비슷하게 처리합니다. Prophet은 불규칙한 시간 간격의 데이터도 처리할 수 있습니다.

매일 데이터가 없어도 괜찮습니다. 있는 데이터만으로 학습하고, 없는 날짜도 예측해 줍니다.

다만 결측치가 너무 많으면 모델 성능이 떨어집니다. 전체 데이터의 20% 이상이 결측치라면, 데이터 수집 방법을 개선하거나 보간(interpolation) 기법을 먼저 적용하는 것이 좋습니다.

실전 팁

💡 - 이상치를 제거하기 전에 왜 이상치가 발생했는지 원인을 파악하세요

  • 결측치가 랜덤하게 발생한 것인지, 특정 패턴이 있는지 확인하세요 (주말에만 결측이면 그것도 정보입니다)

8. 모델 성능 시각화와 진단

김개발 씨는 여러 파라미터를 튜닝하며 모델을 개선했습니다. 하지만 숫자로만 성능을 보니 직관적으로 와닿지 않았습니다.

"모델이 데이터를 얼마나 잘 학습했는지 눈으로 확인할 방법이 없을까요?"

Prophet은 강력한 시각화 기능을 제공합니다. plot 메서드로 예측 결과를, plot_components로 추세와 계절성을 분해하여 볼 수 있습니다.

또한 plot_cross_validation_metric으로 교차 검증 결과를 시각화하여 모델의 신뢰성을 확인할 수 있습니다.

다음 코드를 살펴봅시다.

from prophet import Prophet
from prophet.diagnostics import cross_validation, performance_metrics
from prophet.plot import plot_cross_validation_metric
import matplotlib.pyplot as plt

model = Prophet()
model.fit(df)
forecast = model.predict(future)

# 예측 결과 시각화
fig1 = model.plot(forecast)
plt.title('Sales Forecast')
plt.savefig('forecast.png')

# 컴포넌트 분해 시각화
fig2 = model.plot_components(forecast)
plt.savefig('components.png')

# 교차 검증 성능 시각화
df_cv = cross_validation(model, initial='365 days',
                         period='30 days', horizon='90 days')
fig3 = plot_cross_validation_metric(df_cv, metric='mape')
plt.savefig('cv_metrics.png')

데이터 과학에서 시각화는 매우 중요합니다. 아무리 정교한 모델이라도 결과를 눈으로 확인하지 않으면 문제를 발견하기 어렵습니다.

Prophet은 이를 위한 편리한 시각화 도구를 제공합니다. **model.plot(forecast)**는 가장 기본적인 시각화입니다.

검은 점은 실제 데이터, 파란 선은 예측값, 하늘색 영역은 불확실성 구간을 나타냅니다. 이 그래프를 보면 모델이 실제 데이터의 패턴을 얼마나 잘 따라가는지 한눈에 알 수 있습니다.

예측선이 실제 데이터를 잘 통과하고 있나요? 불확실성 구간 안에 대부분의 데이터가 들어가나요?

특정 구간에서 예측이 크게 빗나가지는 않나요? 이런 질문에 대한 답을 시각적으로 얻을 수 있습니다.

**model.plot_components(forecast)**는 더 깊은 인사이트를 제공합니다. Prophet이 학습한 추세, 연간 계절성, 주간 계절성 등을 개별 그래프로 보여줍니다.

추세 그래프에서는 시간에 따른 전반적인 성장이나 감소를 볼 수 있습니다. 변화점이 어디에서 발생했는지도 확인할 수 있습니다.

연간 계절성 그래프에서는 어느 달에 높고 어느 달에 낮은지 패턴을 볼 수 있습니다. 주간 계절성 그래프에서는 요일별 패턴을 확인합니다.

이 컴포넌트 분석은 비즈니스 인사이트를 얻는 데도 유용합니다. "우리 매출은 화요일에 가장 높고 일요일에 가장 낮구나", "매년 11월에 피크를 찍는구나" 같은 발견을 할 수 있습니다.

plot_cross_validation_metric은 교차 검증 결과를 시각화합니다. x축은 예측 기간(horizon), y축은 성능 지표입니다.

이 그래프를 보면 예측이 멀어질수록 오차가 얼마나 증가하는지 알 수 있습니다. 일반적으로 가까운 미래는 정확하게 예측하고, 먼 미래는 오차가 커집니다.

하지만 그 증가 속도가 중요합니다. 완만하게 증가하면 모델이 안정적인 것이고, 급격히 증가하면 먼 미래 예측에 주의가 필요합니다.

시각화 결과를 보고 파라미터를 조절하는 것이 효과적입니다. 추세가 너무 직선이면 changepoint_prior_scale을 높이고, 계절성이 과하게 보이면 seasonality_prior_scale을 낮추는 식입니다.

실전 팁

💡 - 시각화 결과를 팀원이나 이해관계자와 공유할 때는 그래프에 제목과 설명을 추가하세요

  • plot_components에서 이상한 패턴이 보이면 해당 계절성의 파라미터를 재검토하세요

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

#Python#Prophet#TimeSeries#Hyperparameter#Forecasting#Data Science

댓글 (0)

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