Facebook Prophet으로 미래 지표 예측하기
안녕하세요. 저는 광고개발팀에서 백엔드 개발과 데이터 분석 업무를 맡은 정은석이라고 합니다.
우리는 하루에 몇 번 미래를 생각할까요? 당장 오늘 가기로 한 맛집에 줄이 길지 짧을지, 주말에 자전거를 타기로 했는데 비가 올지, 올해 크리스마스 거리에 눈이 소복이 쌓일지, 내년에 이사를 하고 싶은데 집값은 어떻게 변할지 등 여러 가지 사실이 궁금합니다.
회사 안에서도 비슷합니다. 다가올 이벤트의 수요를 알고 싶으며, 연말 시즌에는 내년 분기별 예상 매출을 계획해야 합니다. 또 다양한 부서에서 ‘린 분석’ 같은 책들에 나오는 수많은 지표가 궁금할 수도 있습니다. 물론 적절한 인프라가 없다면 데이터를 보관할 수도 없으며, 그에 따라 미래를 예측할 수도 없겠죠.
기존 예측 방식 개선하기
( Facebook Prophet 사용 자체가 궁금하신 분들은 바로 아래 ‘Prophet이란?’ 문단으로 이동하셔도 좋겠습니다.)
저희 부서도 연도마다 특정 지표를 예측할 필요가 있었습니다. 어떤 지표인지 직접 명시하긴 어려우므로, 이해하기 쉽도록 쇼핑몰의 매장별 매출이라고 가정해봅시다. 지금부터 데이터는 전부 다 예시라고 생각하시면 됩니다.
먼저 올해(2021년)의 쇼핑몰 매출 예상 지표는 어떻게 예측했는지 살펴보겠습니다.
2020년 이전의 쇼핑몰 매출 데이터와 고급 데이터 분석 도구를 활용, 매장마다 같은 방식으로 예측하였습니다.
그런데 사실 쇼핑몰 매출은 아래 그래프처럼 매장 종류에 따라서 양상이 조금 달랐습니다.
예를 들어 쇼핑몰의 내년 전체 매출을 올해의 1.2배로 예상했다고 가정해봅시다. 이때 각 쇼핑몰 개별 점포(옷 매장, 신발 매장, 가구 매장 등)의 매출도 전부 1.2배로 예측하는 것보단, 개별 점포에 상황에 맞게 각각 예측하는 게 더 정확할 수 있습니다. (물론 그만큼 시간과 비용이 많이 소요될 수도 있으니 세상에 정답은 없겠죠)
따라서 매장별로 매출을 각각 다르게 예측하고자 합니다. 옷 매장은 나름의 수요 곡선이 있고, 신발 매장은 역시 나름의 수요 곡선이 있겠죠. 자 그럼 이제 내년의 매장별 매출을 예측해볼까요? (두근두근)
문제 정의와 해결방법 정하기
입력 : 매장(Bn)별 과거 매출(A)
출력 : 매장(Bn)별 미래 매출(A)
이렇게 입력(input)과 출력(output)을 정의하였습니다. 매장별로 날짜마다 값 1개(매출)가 주어진 시계열 예측 문제를 풀면 되겠네요.
매장별 특성 Bn을 다시 분류하면 머신러닝이나 딥러닝을 사용한 예측에 활용할 수 있을 것으로 보입니다. 하지만 각 특성 Bn의 과거 매출 지표(A) 자체가 여러 가지 변수들을 반영하고 있을 것이기에, 우선 시계열 예측 관련 라이브러리를 바로 사용하기로 했습니다.
예를 들어 계절마다 매출이 크게 달라지는 매장들이 있다면 관련 변수를 만들어 분석에 참고할 수 있습니다. 하지만 예측에 사용되는 과거 데이터 자체가 실제로 계절에 따라 많이 변했다면, 자연스럽게 계절성이 고려됩니다. (아래에도 있지만 seasonality_prior_scale 변수로 더 조정할 수 있습니다)
이 글처럼 Python에는 다양한 시계열 예측 라이브러리가 있는데, Prophet을 선택하였습니다.
Prophet이란?
Facebook에서 만든 오픈소스 시계열 예측 라이브러리입니다.
Prophet is a procedure for forecasting time series data based on an additive model where non-linear trends are fit with yearly, weekly, and daily seasonality, plus holiday effects. It works best with time series that have strong seasonal effects and several seasons of historical data. Prophet is robust to missing data and shifts in the trend, and typically handles outliers well.
위 공식 소개처럼 주기성 및 휴일 변수를 고려한 예측에 적합하다는 평이 있고, 가이드가 비교적 자세했으며 파라미터 튜닝과 관련된 CV 기능까지 제공하고 있기에 잠정적으로 사용을 결정하였습니다.
사용과 관련해서는 Prophet Quick Start나 시계열 예측 패키지 Prophet 소개 글을 함께 보셔도 좋겠습니다. 이론적 배경과 관련해서는 논문을 참조하실 수 있습니다. 논문에서 소개되었듯이, 도메인 지식을 가진 실무자가 직관적으로 시계열 예측을 수행하기에 적합한 도구로 여겨집니다.
이제 예측해볼까요?
먼저 각 매장에 대해 다음을 알고 싶었습니다.
- 일반적인 매출 변화 추이
- 월별 / 주별 / 휴일별 매출 변화 추이
그리고 간단하게 확인할 수 있었습니다.
5줄로 만나는 미래
m = Prophet(yearly_seasonality = True)
m.add_country_holidays(country_name='KR')
m.fit(df)
future = m.make_future_dataframe(periods=412) #2022년 12월 31일까지 예측
forecast = m.predict(future)
참고로 df 변수에는 y(날짜)와 ds(예측 목표) 데이터가 있어야 합니다.
yearly_seasonality, weekly_seasonality, daily_seasonality 파라미터는 기본적으로 ‘auto’로 되어있습니다. 사용하지 않게 될 경우 warning에서 확인할 수 있으며, 이 경우 위처럼 다시 명시해서 사용할 수 있습니다. 아래 그래프를 보시면 weekly_seasonality는 자동으로 인식되었다는 것을 확인하실 수 있습니다.
결과를 확인해봅시다.
fig1 = m.plot(forecast)
fig2 = m.plot_components(forecast)
이렇게 값 예측뿐만 아니라, Trend 그래프를 보면 순수 매출 성장 추이를 알 수 있으며 holidays / weekly / yearly 그래프를 통해서 휴일별 / 주별 / 연도별 경향까지 파악할 수 있습니다.
각 매장의 특성에 맞는 판매 전략 등도 유추할 수 있습니다. 주말과 주중 중 언제 인기가 있는지, 여름과 겨울 중 언제가 성수기인지 확인할 수 있습니다.
Hyperparameter tuning을 통한 성능 최적화
어떻게 하면 조금 더 정확한 예측을 할 수 있을까요? 라이브러리를 살펴보면 Prophet 모델 설정 시 여러 가지 파라미터들이 특정 기본값으로 설정되어 있습니다. Prophet에서 아래 4가지 파라미터는 조정해봐도 좋을 것이라고 소개합니다.
seasonality_mode='additive',
seasonality_prior_scale=10.0,
holidays_prior_scale=10.0,
changepoint_prior_scale=0.05,
우선 성능(오차)을 어떤 지표(RMSE, MAE 등)로 정의할 것인지 생각한 후에 내장된 Cross Validation 기능(교차 검증)을 사용할 수 있습니다.
교차 검증 시 기본 내장 performance_metric 함수를 사용하면 여러 가지 오차 지표(MSE, RMSE, MAE, MAPE, MDAPE)와 예측 결과 내의 실제 값 Coverage 확인도 가능합니다.
다음의 교차 검증 예를 봅시다.
df_cv = cross_validation(m, initial=’730 days’, period=’90 days’, horizon = ‘180 days’)
전체 데이터가 7년이라고 하면 아래와 같이 예측하고 실제 데이터와 비교해서 검증합니다.
- 첫 2년 데이터 기준, 향후 180일 예측 후 실제와 비교
- 2년+90일 기준, 최근 2년 데이터로 향후 180일 예측 후 비교
- 2년 + 180일 기준, 최근 2년 데이터로 향후 180일 후 예측 후 비교
- (2년 + 90*n일 기준, 예측하는 범위가 7년을 초과하기 전까지 반복)
따라서 과거 데이터로 예측시 오차를 확인할 수 있습니다. 다양한 파라미터 조합을 후보로 두고 실험한다면, 그에 따라 오차가 제일 작은 파라미터를 찾을 수 있습니다.
더 자세히는 Prophet Diagnostics (Hyperparameter tuning) 페이지에서 참조하실 수 있습니다.
기존 방식과 성능 비교
그런데 정말 기존 방식보다 prophet이 더 좋은 방법일까요?
매장별 과거 매출 데이터로 2021년 매출 데이터를 예측해보고, 실제 2021년 매출 데이터와 비교해볼 수 있습니다.
매장별로 RMSE (편차 합의 제곱근으로, 큰 오류가 가중되는 경향이 있습니다.)가 얼마나 달라졌는지 확인했습니다. AS-IS가 현재 방식, TO-BE는 Prophet을 사용한 방식입니다.
특성별로 조금 편차가 있긴 하지만, 전반적으로 오차(RMSE)가 줄어들었다고 결론을 내릴 수 있었습니다. 기간별 방역 상황이 영향을 주었을 수도 있으므로, 2020년 이후 데이터를 활용한 예측 결과는 조금 더 주의 깊게 해석하거나 일부 보정할 필요가 있긴 합니다. Prophet에서 아웃라이어를 지정할 수도 있습니다
이렇게 Prophet을 사용하면 빠르고 직관적으로 시계열 예측을 수행할 수 있습니다. ‘일이 너무 빠르게 끝난 것 아니야?’라는 생각이 드신다면, 비즈니스 문제를 효율적으로 빠르게 푼다는 건 결국 좋은 일이라는 취지의 글도 함께 읽어보셔도 좋겠습니다.
(동시에 무슨 기술이든 잘 알고 써야 의미가 있듯이, Prophet으로 해당 비즈니스 문제를 i) 정확하게 ii) 효율적으로 iii) 빠르게 풀었는지 다시 한번 검토해볼 필요가 있습니다. )
마치며 - 미래 예측은 겸손하게
데이터로 말하는 것은, 어쩌면 무언가를 확신하는 말을 아끼게 되는 것인지도 모른다. [권정민, 주형(2021),『데이터 분석가의 숫자유감』(골든래빗), p329.]
기상청 예보가 틀린 걸 경험해보신 적이 있나요? 기상청 날씨 예측은 슈퍼컴퓨터로 진행하는데, 올해 도입한 장비는 무려 628억(!)이었다고 합니다. 628억짜리 슈퍼컴퓨터도 자주 틀리는 게 미래이기에, 미래를 예측하는 건 정말 쉽지 않겠죠.
특히 주식/부동산 가격과 같이 변수가 아주 많은 ‘가격'이라는 지표를 다룰 때는 더욱 신중해야 할 수 있습니다. 관련해서 미국 부동산 회사 Zillow와 Prophet과 관련한 글이 있는데, 함께 읽어보셔도 좋겠습니다.
저희도 Prophet으로 예측한 결과를 지속해서 살펴보고, 필요하면 보정하는 등 다소 보수적으로 접근하고 있습니다. 더 정확하고 좋은 방법이 있을지 계속 모색하고 있기도 합니다.
결국 100% 정확하게 미래를 예측할 수 없기에, 오히려 필요한 건 원칙과 다양한 가능성에 대한 준비가 아닐지 모르겠습니다. 예측을 아무리 잘해도 실패는 찾아올 수 있고, 예측을 못 해도 대응을 잘했을 경우 성공이 찾아올 수도 있으니까요. (라고 말하지만 사실 예측도 잘하면서 성공과 가까운 조직을 꿈꿉니다.)