057 Prophet 기초
키워드: Prophet, Facebook, 시계열 예측
개요
Prophet은 Facebook(Meta)에서 개발한 시계열 예측 라이브러리입니다. 비즈니스 시계열에 특화되어 있으며, 트렌드, 계절성, 휴일 효과를 자동으로 처리합니다.
실습 환경
- Python 버전: 3.11 권장
- 필요 패키지:
prophet, pandas, numpy
pip install prophet pandas numpy matplotlib
Prophet 소개
Prophet의 특징
import pandas as pd
import numpy as np
from prophet import Prophet
import matplotlib.pyplot as plt
# 057 Prophet 특징
features = {
'특징': ['트렌드 모델링', '계절성 자동 탐지', '휴일 효과', '이상치 처리', '결측치 처리'],
'설명': [
'선형/로지스틱 성장 트렌드',
'연간, 주간, 일간 계절성',
'휴일/이벤트 효과 모델링',
'이상치에 강건함',
'결측치 자동 처리'
],
'장점': [
'유연한 트렌드 변화점 감지',
'파라미터 튜닝 최소화',
'도메인 지식 반영 가능',
'불완전한 데이터에도 동작',
'별도 전처리 불필요'
]
}
print("Prophet 특징:")
print(pd.DataFrame(features).to_string(index=False))
데이터 형식
# 057 Prophet은 특정 컬럼명 필요: ds (datetime), y (target)
np.random.seed(42)
dates = pd.date_range('2020-01-01', periods=730, freq='D')
# 057 트렌드 + 주간 + 연간 계절성 + 노이즈
trend = np.linspace(100, 200, 730)
weekly = 20 * np.sin(np.arange(730) * 2 * np.pi / 7)
yearly = 40 * np.sin(np.arange(730) * 2 * np.pi / 365)
noise = np.random.randn(730) * 15
values = trend + weekly + yearly + noise
# 057 Prophet 형식
df = pd.DataFrame({
'ds': dates, # 필수: datetime 컬럼
'y': values # 필수: target 컬럼
})
print("Prophet 데이터 형식:")
print(df.head())
print(f"\n데이터 기간: {df['ds'].min()} ~ {df['ds'].max()}")
기본 사용법
모델 학습
# 057 학습/테스트 분할
train = df[df['ds'] < '2021-07-01']
test = df[df['ds'] >= '2021-07-01']
print(f"학습: {len(train)}일, 테스트: {len(test)}일")
# 057 Prophet 모델 생성 및 학습
model = Prophet(
yearly_seasonality=True,
weekly_seasonality=True,
daily_seasonality=False
)
model.fit(train)
print("\n모델 학습 완료!")
예측
# 057 미래 데이터프레임 생성
future = model.make_future_dataframe(periods=len(test))
print(f"예측 기간: {future['ds'].min()} ~ {future['ds'].max()}")
# 057 예측
forecast = model.predict(future)
print("\n예측 결과 컬럼:")
print(forecast.columns.tolist()[:10])
print("\n주요 예측 결과:")
print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
시각화
# 057 Prophet 내장 시각화
fig1 = model.plot(forecast)
plt.title('Prophet Forecast')
plt.show()
# 057 구성요소 시각화
fig2 = model.plot_components(forecast)
plt.show()
예측 성능 평가
from sklearn.metrics import mean_absolute_error, mean_squared_error
# 057 테스트 기간만 추출
forecast_test = forecast[forecast['ds'] >= '2021-07-01']
y_true = test['y'].values
y_pred = forecast_test['yhat'].values
# 057 평가
mae = mean_absolute_error(y_true, y_pred)
rmse = np.sqrt(mean_squared_error(y_true, y_pred))
mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
print("예측 성능:")
print(f" MAE: {mae:.2f}")
print(f" RMSE: {rmse:.2f}")
print(f" MAPE: {mape:.2f}%")
# 057 시각화
plt.figure(figsize=(14, 6))
plt.plot(test['ds'], y_true, label='Actual', linewidth=2)
plt.plot(forecast_test['ds'], y_pred, label='Predicted', linewidth=2)
plt.fill_between(
forecast_test['ds'],
forecast_test['yhat_lower'],
forecast_test['yhat_upper'],
alpha=0.2, label='Confidence Interval'
)
plt.title(f'Prophet Prediction (MAE: {mae:.2f})')
plt.legend()
plt.show()
파라미터 조정
트렌드 조정
# 057 트렌드 변화점 조정
model_trend = Prophet(
changepoint_prior_scale=0.5, # 트렌드 유연성 (기본: 0.05)
changepoint_range=0.9, # 변화점 탐지 범위 (기본: 0.8)
n_changepoints=30 # 변화점 후보 수 (기본: 25)
)
model_trend.fit(train)
forecast_trend = model_trend.predict(future)
# 057 변화점 시각화
from prophet.plot import add_changepoints_to_plot
fig = model_trend.plot(forecast_trend)
add_changepoints_to_plot(fig.gca(), model_trend, forecast_trend)
plt.title('Trend with Changepoints')
plt.show()
계절성 조정
# 057 계절성 강도 조정
model_seasonal = Prophet(
seasonality_prior_scale=10.0, # 계절성 유연성 (기본: 10)
seasonality_mode='multiplicative' # 'additive' or 'multiplicative'
)
# 057 커스텀 계절성 추가
model_seasonal.add_seasonality(
name='monthly',
period=30.5,
fourier_order=5
)
model_seasonal.fit(train)
forecast_seasonal = model_seasonal.predict(future)
fig = model_seasonal.plot_components(forecast_seasonal)
plt.show()
휴일 효과
휴일 추가
# 057 한국 휴일 (간단 버전)
holidays = pd.DataFrame({
'holiday': 'korean_holiday',
'ds': pd.to_datetime([
'2020-01-01', '2020-01-24', '2020-01-25', '2020-01-26', # 설날
'2020-05-05', '2020-09-30', '2020-10-01', '2020-10-02', # 추석
'2021-01-01', '2021-02-11', '2021-02-12', '2021-02-13',
'2021-05-05', '2021-09-20', '2021-09-21', '2021-09-22',
]),
'lower_window': 0,
'upper_window': 1,
})
# 057 휴일 포함 모델
model_holiday = Prophet(holidays=holidays)
model_holiday.fit(train)
forecast_holiday = model_holiday.predict(future)
# 057 휴일 효과 확인
print("휴일 효과:")
holiday_effect = forecast_holiday[['ds', 'korean_holiday']].dropna()
print(holiday_effect[holiday_effect['korean_holiday'] != 0].head(10))
이벤트 효과
# 057 프로모션 등 이벤트
promotions = pd.DataFrame({
'holiday': 'promotion',
'ds': pd.to_datetime([
'2020-11-11', # 싱글데이
'2020-11-27', # 블랙프라이데이
'2021-11-11',
'2021-11-26',
]),
'lower_window': -1, # 이벤트 전날부터
'upper_window': 3, # 이벤트 후 3일까지
})
all_events = pd.concat([holidays, promotions])
model_events = Prophet(holidays=all_events)
model_events.fit(train)
외생 변수 (Regressors)
# 057 외생 변수가 있는 데이터
df_with_regressor = df.copy()
df_with_regressor['temperature'] = 20 + 10 * np.sin(np.arange(730) * 2 * np.pi / 365) + np.random.randn(730) * 3
# 057 학습 데이터
train_reg = df_with_regressor[df_with_regressor['ds'] < '2021-07-01']
test_reg = df_with_regressor[df_with_regressor['ds'] >= '2021-07-01']
# 057 외생 변수 추가
model_reg = Prophet()
model_reg.add_regressor('temperature')
model_reg.fit(train_reg)
# 057 예측 (미래의 외생 변수 필요)
future_reg = model_reg.make_future_dataframe(periods=len(test_reg))
future_reg['temperature'] = df_with_regressor['temperature'].values
forecast_reg = model_reg.predict(future_reg)
print("외생 변수 효과:")
print(forecast_reg[['ds', 'temperature', 'extra_regressors_additive']].tail())
Prophet vs FLAML
# 057 비교를 위한 FLAML 예측
from flaml import AutoML
# 057 FLAML용 특성 생성
def create_features_for_flaml(df):
df = df.copy()
df['dayofweek'] = df['ds'].dt.dayofweek
df['month'] = df['ds'].dt.month
df['dayofyear'] = df['ds'].dt.dayofyear
for lag in [1, 7, 14, 30]:
df[f'lag_{lag}'] = df['y'].shift(lag)
for window in [7, 14]:
df[f'rolling_mean_{window}'] = df['y'].shift(1).rolling(window).mean()
return df.dropna()
df_flaml = create_features_for_flaml(df)
train_flaml = df_flaml[df_flaml['ds'] < '2021-07-01']
test_flaml = df_flaml[df_flaml['ds'] >= '2021-07-01']
feature_cols = [col for col in train_flaml.columns if col not in ['ds', 'y']]
automl = AutoML()
automl.fit(
train_flaml[feature_cols], train_flaml['y'],
task="regression",
time_budget=60,
verbose=0
)
y_pred_flaml = automl.predict(test_flaml[feature_cols])
mae_flaml = mean_absolute_error(test_flaml['y'], y_pred_flaml)
# 057 비교
print("\nProphet vs FLAML:")
print(f" Prophet MAE: {mae:.2f}")
print(f" FLAML MAE: {mae_flaml:.2f}")
comparison = {
'항목': ['MAE', '설정 용이성', '해석 가능성', '외생 변수'],
'Prophet': [f'{mae:.2f}', '매우 쉬움', '구성요소 분해', '지원'],
'FLAML': [f'{mae_flaml:.2f}', '특성 엔지니어링 필요', '특성 중요도', '자연스러운 통합']
}
print(pd.DataFrame(comparison).to_string(index=False))
정리
- Prophet: 비즈니스 시계열에 특화된 예측 라이브러리
- 데이터 형식:
ds(날짜),y(타겟) - 자동 처리: 트렌드, 계절성, 휴일 효과
- 파라미터: changepoint_prior_scale, seasonality_prior_scale
- 외생 변수:
add_regressor()로 추가 - 결측치와 이상치에 강건함
다음 글 예고
다음 글에서는 시계열 특성 엔지니어링에 대해 알아보겠습니다. 시계열 예측 성능을 높이는 다양한 특성 생성 기법을 다룹니다.
FLAML AutoML 마스터 시리즈 #057