시계열분석 Prophet 예측모델에 대하여(3)
전편에서 수행한 ARIMA의 성능이 생각보다 더 안좋았기에 비교적 최근에 나온 모델인 meta의 prophet을 이용해 보기로 했다. (arima는 1900년대 중반에 나왔다고 함..)
1. Prophet 모델은 무엇인가?
ARIMA는 자기회귀 AR모델과 이동평균 MA 모델의 결합(Integrated)이었다.
통계적으로 정상성을 띄게 만들고 원점으로 돌아오려는 특징을 이용한 예측이 주가 되었다.
그렇다면 Prophet은 뭘까? 어떤 것을 근거로 주된 예측을 수행하게 될까?
fb의 깃허브 페이지를 가보자. 코딩 잘하게 생긴 청년의 얼굴과 함께 설명 영상이 있다.
Prophet 공홈 설명
Prophet은 연간, 주간, 일간 계절성 그리고 주말/공휴일 효과와 같은 비선형 트렌드에 기반한 추가적인 모델을 활용한 시계열 데이터 예측 시스템이다.
강한 계절성을 가졌고 과거 여러번 계절이 반복됐을 때 가장 잘 작동한다. Prophet은 결측 데이터나 트렌드 이동 현상에도 강경하며 특히 outlier들을 잘 다룬다.
특징
- 신속/정확
- 완전한 자동화: 지저분한 데이터에도 합리적인 예측을 하니 수작업이 필요없다. outlier와 결측값에 강경하니까~
- 여러곳에 끼워넣을 수 있는 예측: 이식성이 좋아 어디든 끼워맞추기 좋다. 더의 도메인 지식을 더해 사람만 해석할 수 있는 파라미터를 만들어 예측 성능을 향상시킬 수도 있다.
- R & Python에서 사용가능
그래서 원리가 무엇인가?
공홈에 read the paper[https://peerj.com/preprints/3190/]를 누르면 나오는 abstract를 살펴보자 (2017년 논문)
예보는 조직이 용량을 계획하거나 목표 설정, 이상 탐지하는데 사용하는 일반적인 데이터 과학 과제다. 근데 그렇게 중요함에도 믿을만한 고품질의 예보를 만드는건 어렵다. 특히 시계열이 종류가 다양한데다 전문 지식을 가진 분석가가 드물다. 이러한 문제를 다루기 위해 실용적으로 접근한 예보 모델을 가져왔다. 시계열 도메인 지식이 있는 분석가들이 직관적으로 조정할 수 있는 해석 가능한 파라미터들을 가진 모듈식 회귀 모델을 제안한다. -> 번역하면 별 내용은 없다. 잘 모르겠다.
2. 시계열 데이터 예측
데이터 가져오기
저번처럼 ms 주식 데이터를 가져오자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.arima.model import ARIMA
from datetime import datetime
# 주식 데이터를 불러올 종목과 기간을 설정합니다.
# stock_symbol = '453810.KS' # 삼성 nifty50
stock_symbol = 'MSFT' # Microsoft
start_date = '2021-01-01'
end_date = datetime.today().strftime('%Y-%m-%d')
# 주식 데이터를 불러옵니다.
stock_data = yf.download(stock_symbol, start=start_date, end=end_date)
stock_data = stock_data.asfreq('B')
# prophet은 목표값 y와 날짜 ds 컬럼이 꼭 필요하다.
stock_data["y"] = stock_data["Close"]
stock_data["ds"] = stock_data.index
Open | High | Low | Close | Adj Close | Volume | y | ds | |
---|---|---|---|---|---|---|---|---|
Date | ||||||||
2024-02-29 | 408.640015 | 414.200012 | 405.920013 | 413.640015 | 413.640015 | 31947300.0 | 413.640015 | 2024-02-29 |
2024-03-01 | 411.269989 | 415.869995 | 410.880005 | 415.500000 | 415.500000 | 17800300.0 | 415.500000 | 2024-03-01 |
2024-03-04 | 413.440002 | 417.350006 | 412.320007 | 414.920013 | 414.920013 | 17596000.0 | 414.920013 | 2024-03-04 |
2024-03-05 | 413.959991 | 414.250000 | 400.640015 | 402.649994 | 402.649994 | 26919200.0 | 402.649994 | 2024-03-05 |
2024-03-06 | 402.970001 | 405.160004 | 398.390015 | 402.089996 | 402.089996 | 22315200.0 | 402.089996 | 2024-03-06 |
(데이터는 now를 기준으로 한다.)
원하는 만큼 예측하기
범위 (start_date - now) 인 시계열 데이터를 넣고 future 객체의 period로 30일을 넣으면 지금으로부터 한 달 뒤를 예측해준다. ARIMA와 달리 train/test로 데이터를 나누는 번거로움이 없음.
1
2
3
4
5
6
from prophet import Prophet
m = Prophet()
m.fit(stock_data)
future = m.make_future_dataframe(periods=30)
future
ds | |
---|---|
0 | 2021-01-04 |
1 | 2021-01-05 |
2 | 2021-01-06 |
3 | 2021-01-07 |
4 | 2021-01-08 |
… | … |
823 | 2024-04-01 |
824 | 2024-04-02 |
825 | 2024-04-03 |
826 | 2024-04-04 |
827 | 2024-04-05 |
기존 stock_data에 예측할 한달치 날짜를 붙여준다. 4월이 생겼다. (작성일 기준 현재 3월임)
예측
1
2
forecast = m.predict(future)
forecast.tail()
ds | trend | yhat_lower | yhat_upper | … | yhat | |
---|---|---|---|---|---|---|
823 | 2024-04-01 | 418.560595 | 422.138829 | 445.435841 | 434.043367 | |
824 | 2024-04-02 | 418.933966 | 422.045629 | 445.075031 | 434.124133 | |
825 | 2024-04-03 | 419.307338 | 422.652142 | 447.306651 | 435.106716 | |
826 | 2024-04-04 | 419.680709 | 424.560026 | 446.641825 | 435.885870 | |
827 | 2024-04-05 | 420.054081 | 425.604725 | 447.810933 | 436.663380 |
… 은 여러 column들을 포함하고 있다. 여러가지 lower와 upper가 있는데 보기 불편해 제외했다.
우리에게 중요한건 예측값인 yhat이다. 4월의 예측값이 나왔다.
흐름 확인
meta의 prophet은 microsoft의 주가가 3월은 우습고 4월에는 더오를것이라고 한다. 무려 10%나 오른다는건데… 참고만 하자
prediction 시점에서 자기 스탠스를 고수하던 ARIMA에 비하면 meta의 prophet은 꽤나 과감한 예측을 하는 것을 알 수 있다. 사용자의 돈을 크게 날려먹거나(?) 크게 벌어다 줄 수 있지 않을까 싶다.
물론 prophet의 예측 또한 정상성을 담고있다. Uncertainty interval는 upper와 lower로 이루어져 실제 데이터 포인트를 감싸고있는데 임계치에 근처할수록 정상성을 갖고 다시 반대쪽으로 끌려올 것이라는 가정을 하고 예측한다.
그래서 위의 그래프에서 검은 점들이 바깥으로 튀어나갈수록 uncertainty interval은 그 반대 추세를 향한다.
그렇긴 해도 이는 실제 데이터를 예측한 것이 아니므로 불안함을 감출 수 없다. 1월말부터 3월 지금까지의 데이터 30개를 감추고 예측하게 한 뒤 실제 데이터와 비교해보자
prophet은 급등하는 1월말의 실제 데이터가 예측 범위(Uncertainty interval)을 벗어나고 있으므로 정상성을 얻기 위해 급락하는 그래프를 예측했다.
실제 test 데이터는 어떨까?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from copy import deepcopy
train_data = stock_data.iloc[:-30]["Close"]
test_data = stock_data.iloc[-30:]["Close"]
result = deepcopy(forecast.iloc[-30:])
fc = tuple(result['yhat'].values) # 예측값
lower_coef = tuple(result['yhat_lower'].values) # 신뢰구간 최소
upper_coef = tuple(result['yhat_upper'].values) # 신뢰구간 최대
# 예측값 인덱스 넣기
fc_data = pd.Series(fc, index = test_data.index)
# 신뢰구간 인덱스 넣기
lower_data = pd.Series(lower_coef, index = test_data.index)
upper_data = pd.Series(upper_coef, index = test_data.index)
#시각화
plt.figure(figsize =(15, 6))
plt.plot(train_data, label = 'training')
plt.plot(test_data, label = 'actual')
plt.plot(fc_data, label = 'forecast')
plt.fill_between(test_data.index, lower_data, upper_data, color = 'black', alpha = 0.1)
plt.legend(loc = 'upper left')
plt.show()
실제 데이터도 급등이 멈추긴 했지만 급락의 폭의 차이가 조금 났다. scale이 조금 다르긴 하지만 그래도 추세는 얼추 맞춘 듯 하다. (scale이 안맞아 코드가 잘못된줄 알았다 ;;)
이정도 유연하게 움직이는 예측이라면 무언가 해볼 수 있을 듯 하다.
3. 결론
ARIMA보다 훨씬 가치가 있어보이는 prophet을 사용해 주식 자동매매를 쓰면 될 것 같다.
시계열 분석 대표주자 rnn계열인 lstm을 사용해도 되겠지만 해당 자원은 aws의 gpu 인프라에 사
용해야하고 혹은 내 맥북을 통해 수동으로 mps 사용해서 추론해야한다. 목표는 자동화에 초점이 있으므로 prophet으로 결정한다. ram 제한이 있는지 모르겠다.
ml모델을 이용해서 우선적으로 해보고 DL NN 모델을 이용해서도 해볼 생각이다.
이후 둘을 앙상블하는 것까지..
참고
https://www.youtube.com/watch?v=Sm-YBPUe3qU
+
뭔가… 어설프면서 얼추 맞추는 느낌이 있다.