본문 바로가기
ML | DL | Big data/ML

Python Prophet - 자동차 판매량 시계열 데이터 예측하기(Time Series Forecasting)

by 썽하 2020. 8. 28.

이번 글에서는 시계열 예측을 위해 Facebook의 Prophet 라이브러리를 알아보자.

 

시계열 예측은 사용할 수 있는 방법들이 다양하고 각각의 방법마다 하이퍼 파라미터들이 매우 다양하기 때문에 어려울 수도 있다.

 

Prophet 라이브러리는 일변량 시계열 데이터셋(univariate time series datasets)을 예측하기 위해 설계된 오픈소스 라이브러리이다. 기본 적으로 추세나 계절적 구조를 가진 데이터에 대해 모델에 적합한 하이퍼 파라미터들을 자동으로 찾을 수 있도록 설계되었고 사용하기 쉽다.

 

이번 글에서는 다룰 내용은 다음과 같다.

  • Prophet의 전반적인 이해
  • Prophet 모델의 학습 방법, 입출력 형태
  • Prophet 모델을 평가하는 방법

이제 시작해보자.

 


Prophet Forecasting Libarary 란?

Prophet 혹은 Facebook Prophet은 페이스북이 개발한 일변량(하나의 변수) 시계열 예측을 위한 오픈소스 라이브러리이다. additive time series forecasting model을 참고해서 구현되었다. 그리고 경향성(Trends), 계절성(seasonality), 휴일(holidays)을 지원하는 모델이다.

 

Implements 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.

- Package Prophet(2020) 인용

 

이 라이브러리는 R과 Python을 지원한다. 나는 Python 인터페이스를 사용할 예정이다.

 

Prophet 설치하기

우선 prophet을 설치하기 전에 다음과 gcc, g++, python-devel 그리고 pystan을 설치해주자.

운영 체제 혹은 가상 환경에 따라 사전 필요조건이 다르니 여기를 참고하자

sudo yum install gcc
sudo yum install gcc64
sudo yum install gcc-c++
sudo yum install gcc64-c++
sudo yum install python36-devel #파이썬 버전에 맞게설치
pip install pystan

 

다음 Prophet을 설치해준다.

pip install fbprophet

정상적으로 설치되었다면 다음 python 스크립트로 버전을 확인해볼 수 있다.

 

# 버전 확인하기
import fbprophet
print(fbprophet.__version__)
>> 0.6

이 글을 따라 하는 사람이라면 0.6보다 크거나 같아야 하겠다.

 

간혹 아래와 같은 에러 메시지가 발생하기도 하는데 해당되는 라이브러리를 설치해주거나 업그레이드해주면 된다.

# Importing plotly failed. Interactive plots will not work.
pip install --upgrade plotly

 

자! 이제 설치가 완료되었다. 실습할 데이터를 불러와 데이터 분석부터 시작해보자.

 

자동차 판매량 데이터

내가 사용해볼 데이터는 자동차 판매량 데이터이다.

추세(trends)와 계절성(seasonality)을 모두 포함하는 일변량(univariate) 시계열 데이터이다. 총 108개월의 데이터가 있다.

 

다음 링크에서 데이터를 다운받을 수 있지만, 나는 예제에서 바로 다운로드 함으로 따로 다운로드할 필요는 없다.

월별 자동차 판매 데이터셋(csv)

 

데이터 읽어오기

우선 데이터셋을 읽어오고 형태를 살펴보자.

Prophet은 Pandas df 형식이 요구된다. 그렇게 읽어 오자.

pandas의 read_csv() 함수를 호출해서 URL에 직접 데이터를 로드한 다음 데이터 형태를 요약하고 몇 줄을 살펴보자.

import pandas as pd
path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/monthly-car-sales.csv'
df = pd.read_csv(path, header=0)
print(df.shape)
print(df.head())

다음과 같은 출력을 확인할 수 있다.

(108, 2)
     Month  Sales
0  1960-01   6550
1  1960-02   8728
2  1960-03  12026
3  1960-04  14395
4  1960-05  14587

 

데이터 시각화하기

시계열 데이터는 우리가 시각화해보기 전까지는 큰 의미가 없다.

시계열을 그리고 그래프를 살펴보는 것은 실제로 추세, 계절 주기, 특이치(outlier) 등이 있는지 확인하는 데 도움이 된다. 개발자에게 데이터를 직관적으로 확인하는데 어떠한 영감을 준다.

 

그럼 다음을 입력해 그래프를 살펴보자.

 

from matplotlib import pyplot
df.plot()
pyplot.show()

결과는 다음과 같이 나온다.

월별 자동차 판매량 그래프

그래프를 확인하고 나면 월별 매출 추이와 계절별 매출 패턴에 대해 어느 정도 '감'이라는 게 생긴다.

 

Prophet으로 자동차 판매량 예측하기

이제 본격적으로 prophet은 어떻게 실행하는지 살펴보자.

 

Prophet 모델 학습 시기키

우선 학습을 하려면 모델을 생성하고 데이터를 전달한 뒤 fit() 함수를 호출하면 된다.

함수에 넣는 df의 첫 번째 컬럼명은 'ds', 두 번째 컬럼명은 'y' 이어야 한다. 

 

또한 첫 번째 컬럼인 'ds'의 데이터 타입을 date-time 형태로 변환해 주어야 한다.

다음과 같이 입력해보자.

 

# 컬럼명 변경
df.columns = ['ds', 'y']

# 데이터 타입 변경
df['ds']= pd.to_datetime(df['ds'])

# 모델 생성
from fbprophet import Prophet
model = Prophet()

# 모델 학습
model.fit(df)

별다른 에러가 없으면 잘 학습이 된 것이다. 단 5줄로

학습 예시

그럼 이제 미래를 예측해보자.

 

In-Sample Forecast

우선 미래나 과거를 예측하기 전에 우리가 학습으로 사용한 데이터부터 잘 예측이 되는지 확인해 볼 필요가 있다.

이를 In-Sample Forecast라고 하며, 이 결과를 검토함으로써 모델이 얼마나 좋은지 확인할 수 있다. 즉 train set을 얼마나 잘 학습했는가를 판단하는 것이다.

 

ds라는 칼럼명을 가진 데이터 프레임에 예측해볼 date-time 값을 넣어서 predict() 함수를 호출을 호출하면 된다.

나는 다음과 같이 샘플 데이터를 생성해 보았다.

 

# train set 마지막 1년 날짜 생성
last_1year = list()
for i in range(1, 13):
    last_1year.append(['1968-%02d' % i])
last_1year = pd.DataFrame(last_1year, columns = ['ds'])
last_1year['ds']= pd.to_datetime(last_1year['ds'])

그리고 곧바로 예측

# 에측
forecast = model.predict(last_1year)

예측 결과는 다음 칼럼을 가지고 있다.

forecast.columns

>>Index(['ds', 'trend', 'yhat_lower', 'yhat_upper', 'trend_lower', 'trend_upper',
       'additive_terms', 'additive_terms_lower', 'additive_terms_upper',
       'yearly', 'yearly_lower', 'yearly_upper', 'multiplicative_terms',
       'multiplicative_terms_lower', 'multiplicative_terms_upper', 'yhat'],
      dtype='object')

 

이 중에서 가장 눈여겨 볼만한 컬럼은 yhat, yhat_lower, yhat_upper이다. 예측값, 하한선, 상한선인데, 값을 살펴보자.

print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].head())

>>
          ds          yhat    yhat_lower    yhat_upper
0 1968-01-01  14372.957414  12813.604688  15946.867574
1 1968-02-01  14935.370169  13414.122243  16529.427559
2 1968-03-01  20885.171425  19473.558866  22566.078782
3 1968-04-01  22912.780725  21227.129873  24377.037726
4 1968-05-01  24211.263981  22735.553826  25723.955980

 

숫자로만 보면 해석하기 가 어렵다. 여기에서 Prophet의 장점 하나가 빛을 발한다. 이런저런 데이터 후처리 필요 없이 내장 함수 plot()을 사용해서 그래프를 그려볼 수 있다. 단순히 예측값을 파라미터에 전달해주면 된다.

다음과 같이 입력하자.

model.plot(forecast)
pyplot.show()

결과는 다음과 같다.

 

검은색 점들이 학습으로 사용된 데이터이고 파란 색선이 예측한 값이다. 하늘색 범위는 상한선과 하한선을 나타낸다.

실제 데이터와 큰 차이가 없는 걸 보니 잘 학습된 것을 알 수 있다.

 

Out-Of-Sample Forecast

이제 미래를 예측해보자. 우리는 학습 데이터 내부에 있었던 기간 외에 미래를 예측할 것이다.

이를 Out-Of-Sample Forecast라고 한다.

학습 데이터 직후 12개월의 데이터를 다음과 같이 만들자. 1969년 1월부터 12월까지이다.

# train set 이후 1년 날짜 생성
last_1year = list()
for i in range(1, 13):
    last_1year.append(['1969-%02d' % i])
last_1year = pd.DataFrame(last_1year, columns = ['ds'])
last_1year['ds']= pd.to_datetime(last_1year['ds'])

 

그리고 예측하고 그래프까지 그려보자.

다음과 같이 입력하면 된다.

forecast = model.predict(last_1year)
model.plot(forecast)
pyplot.show()

결과는 다음과 같다.

눈으로 얼핏 보기에는 적당한 예측값이 나온 것 같다.

 

모델 평가하기

그래프 확인과 같이 눈으로만 모델을 평가해서는 안된다. 모델의 퍼포먼스는 객관적인 값으로 평가를 해야 한다.

데이터셋의 마지막 12개월을 테스트 셋으로 빼서 학습시킨 뒤 예측이 잘되는지 살펴보자. 즉, 이미 알고 있는 데이터를 Out-Of-Sample Forecast 하는 것이다.

 

데이터셋에서 마지막 12개월을 제외한 데이터를 train 데이터로, 그리고 마지막 12개월을 테스트 데이터로 사용하자.

모델과 데이터마다 다르겠지만 여기에서는 모델 평가를 절대 오차 평균(MAE)으로 한다.

 

# 마지막 12개월 제외시키기
train = df.drop(df.index[-12:])
y_true = df['y'][-12:].values

# 모델 생성 후 학습
model = Prophet()
model.fit(train)

# train set 마지막 1년 날짜 생성
last_1year = list()
for i in range(1, 13):
    last_1year.append(['1968-%02d' % i])
last_1year = pd.DataFrame(last_1year, columns = ['ds'])
last_1year['ds']= pd.to_datetime(last_1year['ds'])

# 예측하고 비교하기
# 여기에서는 MAE를 살펴본다.
forecast = model.predict(last_1year)
y_pred = forecast['yhat'].values
from sklearn.metrics import mean_absolute_error
mae = mean_absolute_error(y_true, y_pred)
print('MAE: %.3f' % mae)

>> 1336.814

mae가 작을수록 좋은 모델이다.

 

실제 데이터와 예측 데이터를 그래프를 통해 살펴보자.

pyplot.plot(y_true, label='Actual')
pyplot.plot(y_pred, label='Predicted')
pyplot.legend()
pyplot.show()

완벽하진 않지만 이 정도면 추세를 잘 따라서 예측한 듯하다.

 

Reference

cran.r-project.org/web/packages/prophet/prophet.pdf

https://research.fb.com/blog/2017/02/prophet-forecasting-at-scale/ 

 


끝.

댓글