Prophet์ ํ์ฉํ ์๊ณ์ด ์์ธก๐ญ
์๋ณธ ๊ฒ์๊ธ: https://velog.io/@euisuk-chung/Prophet์-ํ์ฉํ-์๊ณ์ด-์์ธก
Prophet ์๊ฐ
Facebook Prophet์ ์๊ณ์ด ๋ฐ์ดํฐ์ ์์ธก์ ์ํด Facebook์์ ๊ฐ๋ฐํ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. Prophet์ ์๋ํ๋ ์ด์ ํ์ง ๋ฐ ๊ณ์ ์ฑ ๋ถ์์ ์ง์ํ๋ฉฐ, ํนํ ๋น์ฆ๋์ค ์์ธก(์: ๋งค์ถ, ์ฌ์ฉ์ ์, ์น ํธ๋ํฝ ๋ฑ)์ ์ ์ฉํฉ๋๋ค.
Prophet์ ์ฅ์
Meta(Facebook)์์๋ Prophet์ ์ฅ์ ์ ๋ค์๊ณผ ๊ฐ์ด ์๊ฐํฉ๋๋ค:
1. ์ ํํ๊ณ ๋น ๋ฅด๋ค (Accurate and Fast)
- ์ ํ์ฑ: Prophet์ Facebook ๋ด๋ถ์ ๋ค์ํ ์์ฉ ํ๋ก๊ทธ๋จ์์ ์ ๋ขฐํ ์ ์๋ ์์ธก์ ์ ๊ณตํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ณํ ์๋ฆฝ ๋ฐ ๋ชฉํ ์ค์ ์ ํฐ ๋์์ ์ค๋๋ค.
- ์๋: ๋๋ถ๋ถ์ ๊ฒฝ์ฐ, ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์๋ณด๋ค ๋ ๋์ ์ฑ๋ฅ์ ๋ณด์ฌ์ค๋๋ค. Stan์ ์ฌ์ฉํ์ฌ ๋ชจ๋ธ์ ํผํ ํ๋ฏ๋ก, ๋ช ์ด ๋ง์ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
2. ์์ ์๋ํ (Fully Automatic)
- ์๋ ์์ธก: ๋ฐ์ดํฐ๊ฐ ์ด์ง๋ฝ๊ณ ๋ณต์กํด๋ ๋ณ๋ค๋ฅธ ์์์ ์์ด ํฉ๋ฆฌ์ ์ธ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
- ๊ฐ๊ฑด์ฑ: ์ด์์น, ๊ฒฐ์ธก์น, ์๊ฐ ์๊ณ์ด์ ๊ทน์ ์ธ ๋ณํ์ ๋ํด ๊ฐ๊ฑดํ ์ฑ๋ฅ์ ๋ณด์ ๋๋ค.
3. ์กฐ์ ๊ฐ๋ฅํ ์์ธก (Tunable Forecasts)
- ์ฌ์ฉ์ ์กฐ์ ๊ฐ๋ฅ์ฑ: ์ฌ์ฉ์๊ฐ ์์ธก์ ๋ฏธ์ธ ์กฐ์ ํ๊ณ ์กฐ์ ํ ์ ์๋ ๋ค์ํ ๊ฐ๋ฅ์ฑ์ ์ ๊ณตํฉ๋๋ค.
- ํด์ ๊ฐ๋ฅํ ๋งค๊ฐ๋ณ์: ์ธ๊ฐ์ด ํด์ ๊ฐ๋ฅํ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ฉ์ธ ์ง์์ ์ถ๊ฐํจ์ผ๋ก์จ ์์ธก์ ๊ฐ์ ํ ์ ์์ต๋๋ค.
4. R ๋๋ Python์์ ์ฌ์ฉ ๊ฐ๋ฅ (Available in R or Python)
- ์ธ์ด ์ง์: Prophet์ R๊ณผ Python์์ ๋ชจ๋ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๋์ผํ Stan ์ฝ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋์ํฉ๋๋ค.
- ์ ์ฐ์ฑ: ์ฌ์ฉ์๊ฐ ํธ์ํ๊ฒ ์ฌ์ฉํ ์ ์๋ ์ธ์ด๋ฅผ ์ ํํ์ฌ ์์ธก์ ์ํํ ์ ์์ต๋๋ค.
์ฃผ์ ๊ธฐ๋ฅ
-
์ถ์ธ ๋ณ๋: ์ ํ ๋ฐ ๋น์ ํ ์ถ์ธ ๋ชจ๋ธ๋ง ์ง์.
Prophet์ ๋ฐ์ดํฐ์
์ฅ๊ธฐ์ ์ธ ์ถ์ธ๋ฅผ ๋ชจ๋ธ๋ง
ํ ์ ์์ต๋๋ค.Prophet
์ ์๋์ผ๋ก ์ต์ ์ ์ถ์ธ ๋ชจ๋ธ์ ์ ํํ๊ฑฐ๋, ์ฌ์ฉ์๊ฐ ์๋์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค. Prophet์์๋ ๋ ๊ฐ์ง ์ฃผ์ ์ถ์ธ ๋ชจ๋ธ์ ์ง์ํฉ๋๋ค:- ์ ํ ์ถ์ธ (Linear Trend): ๋ฐ์ดํฐ๊ฐ ์ผ์ ํ ์๋๋ก ์ฆ๊ฐํ๊ฑฐ๋ ๊ฐ์ํ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
-
๋น์ ํ ์ถ์ธ (Non-linear Trend): ๋ฐ์ดํฐ์ ๋ณํ ์๋๊ฐ ์๊ฐ์ ๋ฐ๋ผ ๋ณํ ๋ ์ฌ์ฉ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ก๊ทธ ๋ณํ ์ถ์ธ ๋ฑ์ด ์์ต๋๋ค.
1 2 3 4 5 6
# ๊ธฐ๋ณธ ์ค์ ์์๋ ์ ํ ์ถ์ธ ๋ชจ๋ธ์ ์ฌ์ฉ model = Prophet() # ์ด๋ model = Prophet(growth='linear')์ ๋์ผ # ์ ํํด์ ์ฌ์ฉ๊ฐ๋ฅ model = Prophet(growth='linear') # ์ ํ ์ถ์ธ ๋ชจ๋ธ model = Prophet(growth='logistic') # ๋น์ ํ ์ถ์ธ ๋ชจ๋ธ
-
๊ณ์ ์ฑ: ์ฃผ๊ธฐ์ ๋ณ๋(์ผ, ์ฃผ, ๋ ๋จ์)์ ๋ชจ๋ธ๋ง.
Prophet์
๋ฐ์ดํฐ์ ์ฃผ๊ธฐ์ ์ธ ๋ณ๋
์ ๋ชจ๋ธ๋งํ ์ ์์ต๋๋ค. ์ด๋ ์ฃผ๊ฐ, ์๊ฐ, ์ฐ๊ฐ ๋ฑ์ ์ฃผ๊ธฐ๋ก ๋ฐ์ํ๋ ๋ณ๋์ ์๋ฏธํฉ๋๋ค. Prophet์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฐ๊ฐ ๊ณ์ ์ฑ(yearly_seasonality)๊ณผ ์ฃผ๊ฐ ๊ณ์ ์ฑ(weekly_seasonality)์ ํฌํจํ๋ฉฐ, ์ด๋ ํ์์ ๋ฐ๋ผ ์ผ๊ณ ๋ ์ ์์ต๋๋ค. ์ถ๊ฐ๋ก, ์ฌ์ฉ์ ์ ์ ๊ณ์ ์ฑ์ ๋๋ฉ์ธ ์ง์์ ๊ธฐ๋ฐ์ผ๋ก ์ถ๊ฐํ ์ ์์ต๋๋ค.๊ธฐ๋ณธ ๊ณ์ ์ฑ
- ์ฐ๊ฐ ๊ณ์ ์ฑ (yearly_seasonality): ๋ฐ์ดํฐ์ ์ฐ๊ฐ ์ฃผ๊ธฐ๋ฅผ ๋ฐ์ํฉ๋๋ค.
-
์ฃผ๊ฐ ๊ณ์ ์ฑ (weekly_seasonality): ๋ฐ์ดํฐ์ ์ฃผ๊ฐ ์ฃผ๊ธฐ๋ฅผ ๋ฐ์ํฉ๋๋ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# ๊ธฐ๋ณธ ์ฐ๊ฐ ๊ณ์ ์ฑ์ ํ์ฑํ model = Prophet(yearly_seasonality=True) # ๊ธฐ๋ณธ ์ฃผ๊ฐ ๊ณ์ ์ฑ์ ํ์ฑํ model = Prophet(weekly_seasonality=True) # ์ฐ๊ฐ ๊ณ์ ์ฑ์ ๋นํ์ฑํ model = Prophet(yearly_seasonality=False) # ์ฃผ๊ฐ ๊ณ์ ์ฑ์ ๋นํ์ฑํ model = Prophet(weekly_seasonality=False) # ์ฌ์ฉ์ ์ ์ ๊ณ์ ์ฑ ์ถ๊ฐ model.add_seasonality(name='monthly', period=30.5, fourier_order=5)
-
ํด์ผ ํจ๊ณผ: ๊ณตํด์ผ ๋ฐ ํน๋ณ ์ด๋ฒคํธ์ ๋ํ ํจ๊ณผ๋ฅผ ๋ฐ์.
Prophet์
๊ณตํด์ผ ๋ฐ ํน๋ณ ์ด๋ฒคํธ๊ฐ ์๊ณ์ด ๋ฐ์ดํฐ์ ๋ฏธ์น๋ ์ํฅ
์ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด๋ฅผ ์ํด ๊ณตํด์ผ ๋ฆฌ์คํธ๋ฅผ ์ ๊ณตํ์ฌ ๋ชจ๋ธ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.1 2 3 4 5 6 7
from prophet.make_holidays import make_holidays_df # ๊ณตํด์ผ ๋ฆฌ์คํธ ์์ฑ holidays = make_holidays_df(year_list=[2015, 2016, 2017, 2018, 2019], country='US') # ๋ชจ๋ธ ์ด๊ธฐํ ์ ๊ณตํด์ผ ์ถ๊ฐ model = Prophet(holidays=holidays)
-
๊ฒฐ์ธก์น ์ฒ๋ฆฌ: ์๋์ผ๋ก ๊ฒฐ์ธก์น๋ฅผ ์ฒ๋ฆฌํ๊ณ ๋ถ๊ท์นํ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ์ ์์.
Prophet์
๊ฒฐ์ธก์น๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌ
ํ ์ ์์ผ๋ฉฐ, ๋ถ๊ท์นํ ์๊ณ์ด ๋ฐ์ดํฐ์์๋ ์ ์๋ํฉ๋๋ค. ๊ฒฐ์ธก์น๋ฅผ ๋ณ๋๋ก ์ฒ๋ฆฌํ ํ์ ์์ด Prophet ๋ชจ๋ธ์ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋๋ก ์ ๋ ฅํ๋ฉด ๋ฉ๋๋ค. -
์ด์์น ์ฒ๋ฆฌ: ์ด์์น์ ๊ฐ๊ฑดํ ๋ชจ๋ธ๋ง.
Prophet์
์ด์์น์ ๊ฐ๊ฑดํ ๋ชจ๋ธ๋ง์ ์ ๊ณต
ํฉ๋๋ค. ์ด์์น๊ฐ ์๋ ๋ฐ์ดํฐ์์๋ ๋ชจ๋ธ์ ๊ฐ๊ฑดํ๊ฒ ์๋ํฉ๋๋ค. ์ถ๊ฐ์ ์ผ๋ก ์ ๊ฑฐ๊ฐ ํ์ํ๋ฉด, ์ฌ์ฉ์๋ ์ด์์น๋ฅผ ์๋์ผ๋ก ์ ๊ฑฐํ ์ ์์ต๋๋ค.1 2
# ์ด์์น๊ฐ ํฌํจ๋ ๋ฐ์ดํฐ train_data.loc[train_data['ds'] == '2017-07-01', 'y'] = None # ํน์ ๋ ์ง์ ์ด์์น๋ฅผ ๊ฒฐ์ธก์น๋ก ์ค์
์ฝ๋ ์ค์ต
์ค์ต ๋ฐ์ดํฐ
Kaggle: Panama Electricity Load Forecasting
ํด๋น ๋ฐ์ดํฐ์
์ ํ๋๋ง์ ์ ๋ ฅ ๋ถํ(MW)๋ฅผ ์์ธก
ํ๊ธฐ ์ํ ์๊ณ์ด ๋ฐ์ดํฐ
์
๋๋ค. ๋ ์จ ๋ณ์์ ํน๋ณํ ๋ (๊ณตํด์ผ, ํ๊ต ํด์ผ ๋ฑ)์ ์ฐธ์กฐํ์ฌ ์์ธกํ๋ ๊ฒ์ด ๋ชฉ์ ์
๋๋ค. Kaggle์์ ์ ๊ณต๋๊ณ ์์ผ๋ฉฐ, ์ด๋ฒ ํฌ์คํ
์์๋ ์ด๋ฅผ ํ์ฉํ ์๊ณ์ด ์์ธก์ ์ํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ฐ์ดํฐ์ ๊ฐ์
- ๋ชฉ์ : ํ๋๋ง์ ์ ๋ ฅ ๋ถํ(MW)๋ฅผ ์์ธก
- ์ฐธ์กฐ ๋ณ์: ๋ ์จ ๋ณ์ ๋ฐ ํน๋ณํ ๋
- ํน์ง: ์ด 15๊ฐ์ ํน์ง(features)์ ํฌํจ
๋ฐ์ดํฐ์ ๊ตฌ์ฑ
- ํน์ง(features):
-
์ด 15๊ฐ์ ํน์ง์ ํฌํจ
-
12๊ฐ์ ์ฐ์์ ์ธ ์์นํ ๋ณ์: ๋ ์จ ๋ณ์
-
3๊ฐ์ ํน๋ณํ ๋ ๊ด๋ จ ๋ณ์: ๊ณตํด์ผ, ๊ณตํด์ผ ID, ํ๊ต ํด์ผ
- ๊ฒฐ์ธก์น ์์: ๋ฐ์ดํฐ์ ์ ๊ฒฐ์ธก์น๊ฐ ์์
- ์์ธก ๋์: โnat_demandโ ์ด์ ์๋ ํ๋๋ง์ ์ ๋ ฅ ๋ถํ
Column ์ค๋ช
- ds: ๋ ์ง ๋ฐ ์๊ฐ (datetime)
- T2M_toc, QV2M_toc, TQL_toc, W2M_toc: ํน์ ์ง์ญ(toc)์ ๋ ์จ ๋ณ์ (์จ๋, ์ต๋, ๊ฐ์๋, ํ์ ๋ฑ)
- T2M_san, QV2M_san, TQL_san, W2M_san: ๋ค๋ฅธ ์ง์ญ(san)์ ๋ ์จ ๋ณ์
- T2M_dav, QV2M_dav, TQL_dav, W2M_dav: ๋ ๋ค๋ฅธ ์ง์ญ(dav)์ ๋ ์จ ๋ณ์
- Holiday_ID: ๊ณตํด์ผ ID
- holiday: ๊ณตํด์ผ ์ฌ๋ถ (True/False)
- school: ํ๊ต ํด์ผ ์ฌ๋ถ (True/False)
nat_demand
: ํ๋๋ง์ ์ ๋ ฅ ๋ถํ (MW)
์ด ๋ฐ์ดํฐ์
์ ๋๋จธ์ง ๋ณ์๋ค์ ํ์ฉํ์ฌ ํ๋๋ง์ ์ ๋ ฅ ๋ถํ(net_demand)
๋ฅผ ์์ธกํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ๋ค์ํ ๋ ์จ ๋ณ์์ ํน๋ณํ ๋ ์ ๊ณ ๋ คํ์ฌ ์ ๋ ฅ ๋ถํ๋ฅผ ์์ธกํจ์ผ๋ก์จ, ์ ๋ ฅ ํ์ฌ๋ ํจ์จ์ ์ผ๋ก ์ ๋ ฅ ๊ณต๊ธ์ ๊ด๋ฆฌํ๊ณ ์ต์ ํํ ์ ์์ต๋๋ค. ๊ฐ๊ฐ train๊ณผ test y ๋ฐ์ดํฐ์ ์์์ ์ดํด๋ณด์์ฃ .
Train y
Test y
๋ฐ์ดํฐ ์ค๋น
Prophet์์ ์๊ตฌํ๋ ๋ฐ์ดํฐ ํ์์ ds
(datetime)์ y
(value) ์ปฌ๋ผ์ ํฌํจํด์ผ ํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
# ๋ฐ์ดํฐ ๋ก๋
train_data = pd.read_csv('./data/panama/train.csv')
test_data = pd.read_csv('./data/panama/test.csv')
# ์ปฌ๋ผ ์ด๋ฆ ๋ณ๊ฒฝ
train_data.rename(columns={'datetime': 'ds', 'nat_demand': 'y'}, inplace=True)
test_data.rename(columns={'datetime': 'ds', 'nat_demand': 'y'}, inplace=True)
# ๋ ์ง ํ์ ๋ณํ
train_data['ds'] = pd.to_datetime(train_data['ds'], format='%d-%m-%Y %H:%M')
test_data['ds'] = pd.to_datetime(test_data['ds'], format='%d-%m-%Y %H:%M')
์ค๋ช :
pd.read_csv
: CSV ํ์ผ์ DataFrame์ผ๋ก ๋ก๋ํ๋ ํจ์์ ๋๋ค.rename(columns=...)
: ์ปฌ๋ผ ์ด๋ฆ์ ๋ณ๊ฒฝํ์ฌ Prophet์ด ์๊ตฌํ๋ ํ์์ ๋ง์ถฅ๋๋ค.pd.to_datetime
: ๋ฌธ์์ด์ datetime ๊ฐ์ฒด๋ก ๋ณํํฉ๋๋ค.
๋ชจ๋ธ ํ์ต ๋ฐ ์์ธก
๋ชจ๋ธ ์ด๊ธฐํ ๋ฐ ํ์ต
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from prophet import Prophet
# ๋ชจ๋ธ ์ด๊ธฐํ
model = Prophet()
# ์ถ๊ฐ ๋ณ์ (exogenous variables) ๋ฑ๋ก
regressors = ['T2M_toc', 'QV2M_toc', 'TQL_toc', 'W2M_toc',
'T2M_san', 'QV2M_san', 'TQL_san', 'W2M_san',
'T2M_dav', 'QV2M_dav', 'TQL_dav', 'W2M_dav',
'Holiday_ID', 'holiday', 'school']
for regressor in regressors:
model.add_regressor(regressor)
# ๋ชจ๋ธ ํ์ต
model.fit(train_data)
์ค๋ช :
Prophet()
: Prophet ๋ชจ๋ธ์ ์ด๊ธฐํํฉ๋๋ค.add_regressor
: ๋ชจ๋ธ์ ์ธ๋ถ ๋ณ์๋ฅผ ์ถ๊ฐํฉ๋๋ค.fit
: ์ฃผ์ด์ง ๋ฐ์ดํฐ๋ก ๋ชจ๋ธ์ ํ์ต์ํต๋๋ค.
์ฃผ์ ์ฌํญ:
- ์ธ๋ถ ๋ณ์๋ฅผ ์ถ๊ฐํ ๋, ํ๋ จ ๋ฐ์ดํฐ์ ์์ธก ๋ฐ์ดํฐ์ ๋์ผํ ๋ณ์๊ฐ ์์ด์ผ ํฉ๋๋ค.
- ์ธ๋ถ ๋ณ์๋ ์์นํ ๋ณ์์ฌ์ผ ํฉ๋๋ค. ๋ฒ์ฃผํ ๋ณ์์ผ ๊ฒฝ์ฐ, one-hot-encoding๊ณผ ๊ฐ์ด ์์นํ์ผ๋ก ๋ณํ์ ์ํํด์ฃผ์ด์ผ ํฉ๋๋ค.
- ๋ฐ์ดํฐ์ ์๊ฐ ํ์๊ณผ ๊ฐ๊ฒฉ์ ํ์ธํ์ฌ ์ผ๊ด๋๊ฒ ์ ์งํด์ผ ํฉ๋๋ค.
์์ธก ์ํ
1
2
3
4
5
6
7
8
# ์์ธก์ ์ํ ๋ฏธ๋ ๋ฐ์ดํฐํ๋ ์ ์์ฑ (ํ
์คํธ ๋ฐ์ดํฐ์ ๋์ผํ ๊ธฐ๊ฐ)
future = test_data[['ds'] + regressors]
# ์์ธก ์ํ
forecast = model.predict(future)
# ์์ธก ๊ฒฐ๊ณผ ํ์ธ
print(len(forecast), len(test_data)) # 744 744
์ค๋ช :
make_future_dataframe
: ์์ธก์ ์ํ ๋ฏธ๋ ๋ฐ์ดํฐํ๋ ์์ ์์ฑํฉ๋๋ค.predict
: ์์ธก์ ์ํํฉ๋๋ค.print
: ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
์๊ฐํ
Prophet์ Plotly ๊ธฐ๋ฐ ์๊ฐํ ํจ์
์ Matplotlib ๊ธฐ๋ฐ ์๊ฐํ ํจ์
๋ฅผ ์ ๊ณตํฉ๋๋ค.
1. ์์ธก ๊ฒฐ๊ณผ ์๊ฐํ (Plotly ์ฌ์ฉ)
1
2
3
4
5
6
7
8
9
from prophet.plot import plot_plotly, plot_components_plotly
# ์์ธก ๊ฒฐ๊ณผ ์๊ฐํ (Plotly)
fig_forecast = plot_plotly(model, forecast)
fig_forecast.show()
# ์ปดํฌ๋ํธ ์๊ฐํ (Plotly)
fig_components = plot_components_plotly(model, forecast)
fig_components.show()
์ค๋ช :
plot_plotly
: Plotly๋ฅผ ์ฌ์ฉํ์ฌ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์๊ฐํํฉ๋๋ค. ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์ธํฐ๋ํฐ๋ธํ๊ฒ ํ์ธํ ์ ์์ผ๋ฉฐ, ๋ง์ฐ์ค๋ก ๊ทธ๋ํ๋ฅผ ํ๋ํ๊ฑฐ๋ ํน์ ๊ตฌ๊ฐ์ ์์ธํ ๋ณผ ์ ์์ต๋๋ค.plot_components_plotly
: Plotly๋ฅผ ์ฌ์ฉํ์ฌ ์์ธก ๊ฒฐ๊ณผ์ ์ปดํฌ๋ํธ(์ถ์ธ, ๊ณ์ ์ฑ, ํด์ผ ํจ๊ณผ ๋ฑ)๋ฅผ ์๊ฐํํฉ๋๋ค. ๊ฐ ์ปดํฌ๋ํธ๊ฐ ์๊ณ์ด ๋ฐ์ดํฐ์ ์ด๋ค ์ํฅ์ ๋ฏธ์น๋์ง ์ฝ๊ฒ ํ์ ํ ์ ์์ต๋๋ค.
2. ์์ธก ๊ฒฐ๊ณผ ์๊ฐํ (Matplotlib ์ฌ์ฉ)
1
2
3
4
5
6
7
8
9
from prophet.plot import plot_forecast_component, add_changepoints_to_plot
# ์์ธก ๊ฒฐ๊ณผ ์๊ฐํ (Matplotlib)
fig1 = model.plot(forecast)
plt.show()
# ์ปดํฌ๋ํธ ์๊ฐํ (Matplotlib)
fig2 = model.plot_components(forecast)
plt.show()
์ค๋ช :
plot
: Matplotlib์ ์ฌ์ฉํ์ฌ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์๊ฐํํฉ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก Prophet์ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์๊ฐํํ๋ฉฐ, ์ค์ ๋ฐ์ดํฐ์ ์์ธก๋ ๋ฐ์ดํฐ, ์์ธก ๊ตฌ๊ฐ ๋ฑ์ ํฌํจํฉ๋๋ค.plot_components
: Matplotlib์ ์ฌ์ฉํ์ฌ ์์ธก ๊ฒฐ๊ณผ์ ์ปดํฌ๋ํธ๋ฅผ ์๊ฐํํฉ๋๋ค. ์ถ์ธ, ์ฃผ๊ธฐ์ฑ(๊ณ์ ์ฑ), ํด์ผ ํจ๊ณผ ๋ฑ์ ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ฅผ ์๊ฐํํ์ฌ ๋ฐ์ดํฐ์ ๋ณ๋ ์์ธ์ ์๊ฐ์ ์ผ๋ก ๋ถ์ํ ์ ์์ต๋๋ค.
๊ฐ๋ฅ ์ด์
โ ๏ธ ํ์ง๋ง! ์ฌ๊ธฐ์
2๊ฐ์ง ๋ฌธ์ ์
์ ๋ง์ฃผํ์ค ์ ์์ต๋๋ค!!
(1) ์ฒซ๋ฒ์งธ๋ JupyterLab์ ์ฌ์ฉํ๋ ๋ถ๋ค์ ๊ฒฝ์ฐ ๋ณ๋๋ก Plotly๋ฅผ ์คํํ์ค ๊ฒฝ์ฐ, ์๊ฐํ ์ฝ๋๋ ์คํ์ ๋์ง๋ง ๊ฒฐ๊ณผ๊ฐ ๋ณด์ด์ง ์๋ ๋ฌธ์
๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ ์ํด ๋๋ฆฌ๊ฒ ์ต๋๋ค:
-
์ฃผํผํฐ๋ฉ ํ์ฅ ํ๋ก๊ทธ๋จ ์ค์น:
JupyterLab์์ Plotly๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ถ๊ฐ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ํ์ํ ์ ์์ต๋๋ค. ๋ค์ ๋ช ๋ น์ด๋ก ์ค์นํด๋ณด์ธ์:
1
jupyter labextension install jupyterlab-plotly
-
๋ ๋๋ฌ ์ค์ :
๋ ธํธ๋ถ ์์ ๋ถ๋ถ์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ฌ ๋ ๋๋ฌ๋ฅผ ๋ช ์์ ์ผ๋ก ์ค์ ํด๋ณด์ธ์:
1 2
import plotly.io as pio pio.renderers.default = "jupyterlab"
-
์ธ๋ผ์ธ ๋ชจ๋ ์ฌ์ฉ:
plotly.offline.init_notebook_mode()
๋ฅผ ์ฌ์ฉํ์ฌ ์ธ๋ผ์ธ ๋ชจ๋๋ฅผ ํ์ฑํํด๋ณด์ธ์:1 2
import plotly.offline as pyo pyo.init_notebook_mode(connected=True)
-
๋ช ์์ ์ผ๋ก ๊ทธ๋ํ ํ์:
fig.show()
๋์display(fig)
๋ฅผ ์ฌ์ฉํด๋ณด์ธ์:1 2
from IPython.display import display display(fig)
-
์ฃผํผํฐ๋ฉ ์ฌ์์:
๋ณ๊ฒฝ์ฌํญ์ด ์ ์ฉ๋์ง ์์ ๊ฒฝ์ฐ ์ฃผํผํฐ๋ฉ์ ์์ ํ ์ข ๋ฃํ๊ณ ๋ค์ ์์ํด๋ณด์ธ์.
(2) ๋๋ฒ์งธ๋ Prophet์ plot ํจ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์ฒด ์์ธก ๊ธฐ๊ฐ์ ์๊ฐํ
ํ๋ฏ๋ก, ํ๋ จ ๋ฐ์ดํฐ์ ์์ธก ๊ธฐ๊ฐ์ด ๋ชจ๋ ํฌํจ๋ฉ๋๋ค. ๋ฐ๋ผ์, ๊ฒฐ๊ณผ๋ก ๋์จ ๊ทธ๋ํ์ ๋ชจ์์ด ์ด์์ง ์์ ํ๋ฅ ์ด ๋งค์ฐ๋งค์ฐ ๋์ต๋๋ค.
ํ ์คํธ ๊ธฐ๊ฐ๋ง ์๊ฐํํ๊ณ ์ถ๋ค๋ฉด, ์๋์ ๊ฐ์ด ์์ธก ๊ฒฐ๊ณผ๋ฅผ ํํฐ๋งํ์ฌ ์ํ๋ ๊ธฐ๊ฐ๋ง ์๊ฐํํ ์ ์์ต๋๋ค.
- ์๊ฐํ ํ๊ธฐ ๊ตฌ์ญ์
xlim
์ ํตํด ์กฐ์ ํ์ฌ ์ค์ ํด์ฃผ๋ฉด test ๊ฒฐ๊ณผ๋ง ๋ณผ ์ ์์ต๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
# ํ
์คํธ ๊ธฐ๊ฐ๋ง ํํฐ๋ง
forecast_test_period = forecast[forecast['ds'].isin(test_data['ds'])]
# ์ ์ฒด ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์๊ฐํ
fig = model.plot(forecast)
# x์ถ์ ๋ฒ์๋ฅผ ํ
์คํธ ๊ธฐ๊ฐ์ผ๋ก ์ ํ
plt.xlim([test_data['ds'].min(), test_data['ds'].max()])
# ํ
์คํธ ๋ฐ์ดํฐ ์ค์ ๊ฐ ์ถ๊ฐ
plt.plot(test_data['ds'], test_data['y'], 'r.', label='Actual')
# ๊ทธ๋ํ ํ์
plt.show()
# Plotly๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ ์๊ฐํ
fig_components = model.plot_components(forecast_test_period)
fig_components.show()
์ค๋ช :
warnings.filterwarnings('ignore')
: ๊ฒฝ๊ณ ๋ฉ์์ง๋ฅผ ๋ฌด์ํ๋๋ก ์ค์ ํฉ๋๋ค.forecast[forecast['ds'].isin(test_data['ds'])]
: ํ ์คํธ ๋ฐ์ดํฐ์ ๊ธฐ๊ฐ์ ํด๋นํ๋ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ํํฐ๋งํฉ๋๋ค.model.plot(forecast)
: Prophet ๋ชจ๋ธ์ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์๊ฐํํฉ๋๋ค. ์ ์ฒด ์์ธก ๊ฒฐ๊ณผ๊ฐ ํ์๋ฉ๋๋ค.plt.xlim([test_data['ds'].min(), test_data['ds'].max()])
: x์ถ์ ๋ฒ์๋ฅผ ํ ์คํธ ๊ธฐ๊ฐ์ผ๋ก ์ ํํฉ๋๋ค.plt.plot(test_data['ds'], test_data['y'], 'r.', label='Actual')
: ํ ์คํธ ๋ฐ์ดํฐ์ ์ค์ ๊ฐ์ ๊ทธ๋ํ์ ์ถ๊ฐํฉ๋๋ค.plt.show()
: ๊ทธ๋ํ๋ฅผ ํ๋ฉด์ ํ์ํฉ๋๋ค.model.plot_components(forecast_test_period)
: Prophet ๋ชจ๋ธ์ ์ปดํฌ๋ํธ๋ฅผ ์๊ฐํํฉ๋๋ค. Plotly๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ปดํฌ๋ํธ(์ถ์ธ, ๊ณ์ ์ฑ, ํด์ผ ํจ๊ณผ ๋ฑ)๋ฅผ ์๊ฐํํฉ๋๋ค.- ์๋๋ฉด ๊ทธ๋ฅ ๋ง์ ํธํ๊ฒ ์ง์ ์๊ฐํ ๊ฒฐ๊ณผ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ๋ ์์ต๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error
# ์ค์ ๊ฐ๊ณผ ์์ธก๊ฐ ๋ณํฉ
result = test_data.copy()
result['yhat'] = forecast.set_index('ds').loc[test_data['ds']]['yhat'].values
# ์์ธก ๊ฒฐ๊ณผ ์๊ฐํ
plt.figure(figsize=(20, 4))
plt.plot(result['ds'], result['y'], label='Actual')
plt.plot(result['ds'], result['yhat'], label='Predicted', linestyle='dashed')
plt.fill_between(forecast['ds'], forecast['yhat_lower'], forecast['yhat_upper'], color='gray', alpha=0.2)
plt.legend()
plt.show()
์ค๋ช :
test_data.copy()
: ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํ์ฌresult
๋ฐ์ดํฐํ๋ ์์ ์์ฑํฉ๋๋ค.forecast.set_index('ds').loc[test_data['ds']]['yhat'].values
: ์์ธก ๊ฒฐ๊ณผ์์ ํ ์คํธ ๊ธฐ๊ฐ์ ํด๋นํ๋ ์์ธก ๊ฐ์ ์ถ์ถํฉ๋๋ค.result['yhat'] = ...
: ์ถ์ถํ ์์ธก ๊ฐ์result
๋ฐ์ดํฐํ๋ ์์ ์ถ๊ฐํฉ๋๋ค.plt.figure(figsize=(20, 4))
: ๊ทธ๋ํ์ ํฌ๊ธฐ๋ฅผ ์ค์ ํฉ๋๋ค.plt.plot(result['ds'], result['y'], label='Actual')
: ํ ์คํธ ๋ฐ์ดํฐ์ ์ค์ ๊ฐ์ ๊ทธ๋ํ์ ์ถ๊ฐํฉ๋๋ค.plt.plot(result['ds'], result['yhat'], label='Predicted', linestyle='dashed')
: ์์ธก ๊ฐ์ ๊ทธ๋ํ์ ์ถ๊ฐํฉ๋๋ค.plt.fill_between(forecast['ds'], forecast['yhat_lower'], forecast['yhat_upper'], color='gray', alpha=0.2)
: ์์ธก ๊ฐ์ ๋ถํ์ค์ฑ ๊ตฌ๊ฐ์ ํ์ ์์์ผ๋ก ํ์ํฉ๋๋ค.plt.legend()
: ๋ฒ๋ก๋ฅผ ์ถ๊ฐํฉ๋๋ค.plt.show()
: ๊ทธ๋ํ๋ฅผ ํ๋ฉด์ ํ์ํฉ๋๋ค.
์ฑ๋ฅ ํ๊ฐ
์์ธก ๊ฒฐ๊ณผ๋ฅผ ์ค์ ํ ์คํธ ๋ฐ์ดํฐ์ ๋น๊ตํ์ฌ ์ฑ๋ฅ์ ๊ฒ์ฆํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
from sklearn.metrics import mean_squared_error
# ์ค์ ๊ฐ๊ณผ ์์ธก๊ฐ ๋ณํฉ
result = test_data.copy()
result['yhat'] = forecast.set_index('ds').loc[test_data['ds']]['yhat'].values
# ์ฑ๋ฅ ํ๊ฐ (MSE)
mse = mean_squared_error(result['y'], result['yhat'])
print(f'Mean Squared Error: {mse}')
์ค๋ช :
mean_squared_error
: ์ค์ ๊ฐ๊ณผ ์์ธก๊ฐ์ ํ๊ท ์ ๊ณฑ ์ค์ฐจ๋ฅผ ๊ณ์ฐํฉ๋๋ค.copy
: ๋ฐ์ดํฐํ๋ ์์ ๋ณต์ฌํฉ๋๋ค.set_index
: ๋ฐ์ดํฐํ๋ ์์ ์ธ๋ฑ์ค๋ฅผ ์ค์ ํฉ๋๋ค.loc
: ํน์ ํ์ ์ ํํฉ๋๋ค.
์์ฝ
์ด๋ฒ ํฌ์คํธ์์๋ Prophet์ ๋ํ ์๊ฐ์ ์ด๋ฅผ ํ์ฉํ ์๊ณ์ด ์์ธก์ ์ํํด๋ณด์์ต๋๋ค.
- ๋ฐ์ดํฐ ์ค๋น: Prophet์์ ์๊ตฌํ๋ ํ์์ ๋ง์ถฐ ๋ฐ์ดํฐ๋ฅผ ์ค๋นํฉ๋๋ค.
- ๋ชจ๋ธ ์ด๊ธฐํ ๋ฐ ํ์ต: Prophet ๋ชจ๋ธ์ ์ด๊ธฐํํ๊ณ ํ์ต ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ธ์ ํ์ต์ํต๋๋ค.
- ์์ธก ์ํ: ๋ฏธ๋ ๋ฐ์ดํฐํ๋ ์์ ์์ฑํ๊ณ ์์ธก์ ์ํํฉ๋๋ค.
- ์๊ฐํ: Prophet์ ๋ด์ฅ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์์ธก ๊ฒฐ๊ณผ์ ์ปดํฌ๋ํธ๋ฅผ ์๊ฐํํฉ๋๋ค.
- ์ฑ๋ฅ ํ๊ฐ: ์์ธก ๊ฒฐ๊ณผ๋ฅผ ์ค์ ๋ฐ์ดํฐ์ ๋น๊ตํ์ฌ ์ฑ๋ฅ์ ํ๊ฐํฉ๋๋ค.
๊ธด ๊ธ ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค โญ