์ค๋์ ์๊ณ์ด ์์ธก(Time-Series Prediction)์ ๋ค๋ฃจ๋ ์ฌ๋ฌ ๊ฐ์ง ํต๊ณ์ ๊ธฐ๋ฒ ์ค์ ๊ฐ์ฅ ๋๋ฆฌ ์๋ ค์ง ARIMA(Auto-regressive Integrated Moving Average)์ ๋ํด ์์๋ณด๊ณ ์ด๋ฅผ ํ ๋๋ก ํน์ ์ฃผ์ ์ข ๋ชฉ์ ๊ฐ๊ฒฉ์ ์์ธกํด ๋ณด๋ ์ค์ต์ ์งํํด๋ณด์.
- ์๊ณ์ด ๋ฐ์ดํฐ์ ํน์ฑ๊ณผ ์์ ์ (Stationary) ์๊ณ์ด์ ๊ฐ๋ ์ ์ดํดํ๋ค.
- ARIMA ๋ชจ๋ธ์ ๊ตฌ์ฑํ๋ AR, MA, Diffencing์ ๊ฐ๋ ์ ์ดํดํ๊ณ ๊ฐ๋จํ ์๊ณ์ด ๋ฐ์ดํฐ์ ์ ์ฉํด ๋ณธ๋ค.
- ์ค์ ์ฃผ์ ๋ฐ์ดํฐ์ ARIMA๋ฅผ ์ ์ฉํด์ ์์ธก ์ ํ๋๋ฅผ ํ์ธํด ๋ณธ๋ค.
- ์ง๊ธ๊น์ง์ ์ฃผ๊ฐ๋ณ๊ณก์ ์ ๋ฐํ์ผ๋ก ๋ค์ ์ฃผ๊ฐ๋ณ๋ ์์ธก
- ํน์ ์ง์ญ์ ๊ธฐํ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ๋ด์ผ์ ์จ๋๋ณํ ์์ธก
- ๊ณต์ฅ ์ผํฐ๋ฐ์ดํฐ ๋ณํ์ด๋ ฅ์ ํ ๋๋ก ์ด์ ๋ฐ์ ์์ธก
์ ์์์ ๊ณตํต์ ์ ์์ธก ๊ทผ๊ฑฐ๊ฐ ๋๋ ์๊ณ์ด(Time-Series) ๋ฐ์ดํฐ๊ฐ ์๋ค๋ ๊ฒ์ด๋ค. ์๊ณ์ด ๋ฐ์ดํฐ๋ ์๊ฐ ์์๋๋ก ๋ฐ์ํ ๋ฐ์ดํฐ์ ์์ด์ด๋ผ๋ ๋ป์ด๋ค.
์ผ์ ์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก ๋ฐ์ํ ๋ฐ์ดํฐ ๋ฟ๋ง ์๋๋ผ ๋งค์ผ์ ์ฃผ์ ๊ฑฐ๋ ๊ฐ๊ฒฉ์ ๋ ์ง-๊ฐ๊ฒฉ ํํ๋ก ๋ ์ง์์ผ๋ก ๋ชจ์๋ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด ์ด ๋ฐ์ดํฐ๋ ๋ง์ฐฌ๊ฐ์ง๋ก ํ๋ฅญํ ์๊ณ์ด ๋ฐ์ดํฐ๊ฐ ๋ ๊ฒ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ํน์ ์ฃผ์์ ๋งค์ผ ๊ฐ๊ฒฉ ๋ณ๋ ์๊ณ์ด ๋ฐ์ดํฐ๊ฐ ์๋ ์น ์์ฌ์๋ค๊ณ ํ ๋, ์ด ๋ฐ์ดํฐ๋ฅผ ํ ๋๋ก ๋ด์ผ์ ์ฃผ์ ๊ฐ๊ฒฉ์ด ์ผ๋ง๊ฐ ๋ ์ง, ์ค๋ฅผ์ง ๋ด๋ฆด์ง๋ฅผ ์์ธกํ ์ ์์๊น? ๊ฒฐ๋ก ์ ์ผ๋ก ๋งํ์๋ฉด ๋ฏธ๋ ์์ธก์ ๋ถ๊ฐ๋ฅํ ๊ฒ์ด๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๋ฏธ๋์ ๋ฐ์ดํฐ๋ฅผ ์์ธกํ๋ ค๊ณ ํ๋ค๋ฉด ๋ ๊ฐ์ง ์ ์ ๊ฐ ํ์ํ๋ค.
- ๊ณผ๊ฑฐ์ ๋ฐ์ดํฐ์ ์ผ์ ํ ํจํด์ด ๋ฐ๊ฒฌ๋๋ค
- ๊ณผ๊ฑฐ์ ํจํด์ ๋ฏธ๋์๋ ๋์ผํ๊ฒ ๋ฐ๋ณต๋ ๊ฒ์ด๋ค.
์ด ๋ ๊ฐ์ง ๋ฌธ์ฅ์ด ์๋ฏธํ๋ ๋ฐ๋ ์ฆ, ์์ ์ (Stationary)์ธ ๋ฐ์ดํฐ์ ๋ํด์๋ง ๋ฏธ๋ ์์ธก์ด ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ด๋ค. ์ฌ๊ธฐ์ ์์ ์ (Stationary)์ด๋ค๋ ๊ฒ์ ์๊ณ์ด ๋ฐ์ดํฐ์ ํต๊ณ์ ํ์ฑ์ด ๋ณํ์ง ์๋๋ค๋ ๋ป์ด๋ค.
-
์๊ฐ์ ์ถ์ด์ ๊ด๊ณ ์์ด ํ๊ท ์ด ๋ถ๋ณ
-
์๊ฐ์ ์ถ์ด์ ๊ด๊ณ ์์ด ๋ถ์ฐ์ด ๋ถ๋ณ
-
๋ ์์ ๊ฐ์ ๊ณต๋ถ์ฐ์ด ๊ธฐ์ค ์์ ๊ณผ ๋ฌด๊ด
๋ฐ์ดํฐ ์ค๋น
$ wget https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-min-temperatures.csv
$ wget https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv
์๊ณ์ด(Time Series) ์์ฑ
์ฒซ ๋ฒ์งธ๋ก ๋ค๋ฃจ์ด๋ณผ ๋ฐ์ดํฐ๋ Daily Minimum Temperatures in Melbourne์ด๋ค.
# ๋ชจ๋ import
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
# data load
dataset_filepath = os.getenv('HOME')+'/aiffel/stock_prediction/data/daily-min-temperatures.csv'
df = pd.read_csv(dataset_filepath)
print(type(df))
df.head()
# ์ด๋ฒ์๋ Date๋ฅผ index_col๋ก ์ง์
df = pd.read_csv(dataset_filepath, index_col='Date', parse_dates=True)
print(type(df))
df.head()
ts1 = df['Temp']
print(type(ts1))
ts1.head()
from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 13, 6
# ์๊ณ์ด(time series) ๋ฐ์ดํฐ๋ฅผ ์๊ฐํ. ํน๋ณํ ๋ ๊ฐ๊ณตํ์ง ์์๋ ์ ๊ทธ๋ ค์ง๋ค.
plt.plot(ts1)
# ์๊ณ์ด(Time Series)์์ ๊ฒฐ์ธก์น๊ฐ ์๋ ๋ถ๋ถ๋ง Series๋ก ์ถ๋ ฅ
ts1[ts1.isna()]
# ๊ฒฐ์ธก์น๊ฐ ์๋ค๋ฉด ์ด๋ฅผ ๋ณด๊ฐํฉ๋๋ค. ๋ณด๊ฐ ๊ธฐ์ค์ time์ ์ ํํฉ๋๋ค.
ts1=ts1.interpolate(method='time')
# ๋ณด๊ฐ ์ดํ ๊ฒฐ์ธก์น(NaN) ์ ๋ฌด๋ฅผ ๋ค์ ํ์ธํฉ๋๋ค.
print(ts1[ts1.isna()])
# ๋ค์ ๊ทธ๋ํ๋ฅผ ํ์ธํด๋ด
์๋ค!
plt.plot(ts1)
# ์ผ์ ๊ตฌ๊ฐ ๋ด ํต๊ณ์น(Rolling Statistics)๋ฅผ ์๊ฐํ
def plot_rolling_statistics(timeseries, window=12):
rolmean = timeseries.rolling(window=window).mean() # ์ด๋ํ๊ท ์๊ณ์ด
rolstd = timeseries.rolling(window=window).std() # ์ด๋ํ์คํธ์ฐจ ์๊ณ์ด
# ์๋ณธ์๊ณ์ด, ์ด๋ํ๊ท , ์ด๋ํ์คํธ์ฐจ๋ฅผ plot์ผ๋ก ์๊ฐํํด ๋ณธ๋ค.
orig = plt.plot(timeseries, color='blue',label='Original')
mean = plt.plot(rolmean, color='red', label='Rolling Mean')
std = plt.plot(rolstd, color='black', label = 'Rolling Std')
plt.legend(loc='best')
plt.title('Rolling Mean & Standard Deviation')
plt.show(block=False)
plot_rolling_statistics(ts1, window=12)
์๊ฐ์ ๋ฐ๋ผ ์ผ์ ํ ํ๊ท , ๋ถ์ฐ, ์๊ธฐ๊ณต๋ถ์ฐ์ ํจํด์ด ๋ํ๋๋ ๊ฒ ์ฒ๋ผ ๋ณด์ด๋ฏ๋ก ์์ ์ ์ธ ์๊ณ์ด ๋ฐ์ดํฐ๋ก ๋ณผ ์ ์์ ๊ฒ์ด๋ค. ์ข ๋ ๋ช ํํ๊ฒ ํ๋ ค๋ฉด ํต๊ณ์ ์ ๊ทผ์ด ํ์ํ๋ค.
# data load
dataset_filepath = os.getenv('HOME')+'/aiffel/stock_prediction/data/airline-passengers.csv'
df = pd.read_csv(dataset_filepath, index_col='Month', parse_dates=True).fillna(0)
print(type(df))
df.head()
ts2 = df['Passengers']
plt.plot(ts2)
plot_rolling_statistics(ts2, window=12)
์์ ์ฌ๋ก์๋ ๋ฌ๋ฆฌ ์๊ฐ์ ์ถ์ด์ ๋ฐ๋ผ ํ๊ท ๊ณผ ๋ถ์ฐ์ด ์ฆ๊ฐํ๋ ํจํด์ ๋ณด์ธ๋ค๋ฉด ์ด ์๊ณ์ด ๋ฐ์ดํฐ๋ ์ ์ด๋ ์์ ์ ์ด์ง ์๋ค๊ณ ์ ์ฑ์ ์ธ ๊ฒฐ๋ก ์ ๋ด๋ ค๋ณผ ์ ์์ ๊ฒ ๊ฐ๋ค. ์ด๋ฐ ๋ถ์์ ์ (Non-Stationary) ์๊ณ์ด ๋ฐ์ดํฐ์ ๋ํ ์๊ณ์ด ๋ถ์ ๊ธฐ๋ฒ๋ ์์๋ณด์.
Augmented Dickey-Fuller Test(ADF Test)๋ผ๋ ์๊ณ์ด ๋ฐ์ดํฐ์ ์์ ์ฑ์ ํ ์คํธํ๋ ํต๊ณ์ ๋ฐฉ๋ฒ์ ์๊ฐํ๋ค. ํ ์คํธ๋ ์ฃผ์ด์ง ์๊ณ์ด ๋ฐ์ดํฐ๊ฐ ์์ ์ ์ด์ง ์๋ค๋ผ๋ ๊ท๋ฌด๊ฐ์ค(Null Hypothesis)๋ฅผ ์ธ์ด ํ, ํต๊ณ์ ๊ฐ์ค ๊ฒ์ ๊ณผ์ ์ ํตํด ์ด ๊ท๋ฌด๊ฐ์ค์ด ๊ธฐ๊ฐ๋ ๊ฒฝ์ฐ์ ์ด ์๊ณ์ด ๋ฐ์ดํฐ๊ฐ ์์ ์ ์ด๋ค๋ผ๋ ๋๋ฆฝ๊ฐ์ค(Alternative Hypothesis)์ ์ฑํํ๋ค๋ ๋ด์ฉ์ด๋ค.
ํต๊ณ์ ๊ฐ์ค ๊ฒ์ ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ์ด๋ฃจ๋ p-value ๋ฑ์ ์ฉ์ด์ ๋ํด์๋ ํ ๋ฒ์ฏค ์ง๊ณ ๋์ด๊ฐ๋ ๊ฒ์ด ์ข์ ๊ฒ์ด๋ค.
statsmodels
ํจํค์ง๋ R์์ ์ ๊ณตํ๋ ํต๊ณ๊ฒ์ , ์๊ณ์ด๋ถ์ ๋ฑ์ ๊ธฐ๋ฅ์ ํ์ด์ฌ์์๋ ์ด์ฉํ ์ ์๋๋ก ํ๋ ๊ฐ๋ ฅํ ํต๊ณ ํจํค์ง์
๋๋ค. ์ด๋ฒ ๋
ธ๋์์๋ statsmodels
ํจํค์ง์ ๊ธฐ๋ฅ์ ์์ฃผ ํ์ฉํ๊ฒ ๋ ๊ฒ์
๋๋ค. ์๋๋ statsmodels
ํจํค์ง์์ ์ ๊ณตํ๋ adfuller
๋ฉ์๋๋ฅผ ์ด์ฉํด ์ฃผ์ด์ง timeseries์ ๋ํ Augmented Dickey-Fuller Test๋ฅผ ์ํํ๋ ์ฝ๋์ด๋ค.
from statsmodels.tsa.stattools import adfuller
def augmented_dickey_fuller_test(timeseries):
# statsmodels ํจํค์ง์์ ์ ๊ณตํ๋ adfuller ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
dftest = adfuller(timeseries, autolag='AIC')
# adfuller ๋ฉ์๋๊ฐ ๋ฆฌํดํ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ฆฌํ์ฌ ์ถ๋ ฅํฉ๋๋ค.
print('Results of Dickey-Fuller Test:')
dfoutput = pd.Series(dftest[0:4], index=['Test Statistic','p-value','#Lags Used','Number of Observations Used'])
for key,value in dftest[4].items():
dfoutput['Critical Value (%s)' % key] = value
print(dfoutput)
# Daily Minimum Temperatures in Melbourne
augmented_dickey_fuller_test(ts1)
"""
Results of Dickey-Fuller Test:
Test Statistic -4.444805
p-value 0.000247
#Lags Used 20.000000
Number of Observations Used 3629.000000
Critical Value (1%) -3.432153
Critical Value (5%) -2.862337
Critical Value (10%) -2.567194
dtype: float64
"""
Daily Minimum Temperatures in Melbourne
์๊ณ์ด์ด ์์ ์ ์ด์ง ์๋ค๋ ๊ท๋ฌด๊ฐ์ค์ p-value๊ฐ ๊ฑฐ์ 0์ ๊ฐ๊น๊ฒ ๋ํ๋ฌ๋ค. ๋ฐ๋ผ์ ์ด ๊ท๋ฌด๊ฐ์ค์ ๊ธฐ๊ฐ๋๊ณ , ์ด ์๊ณ์ด์ ์์ ์ ์๊ณ์ด์ด๋ผ๋ ๋๋ฆฝ๊ฐ์ค์ด ์ฑํ๋๋ค.
# International airline passengers
augmented_dickey_fuller_test(ts2)
"""
Results of Dickey-Fuller Test:
Test Statistic 0.815369
p-value 0.991880
#Lags Used 13.000000
Number of Observations Used 130.000000
Critical Value (1%) -3.481682
Critical Value (5%) -2.884042
Critical Value (10%) -2.578770
dtype: float64
"""
International airline passengers
์๊ณ์ด์ด ์์ ์ ์ด์ง ์๋ค๋ ๊ท๋ฌด๊ฐ์ค์ p-value๊ฐ ๊ฑฐ์ 1์ ๊ฐ๊น๊ฒ ๋ํ๋ฌ๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ์ด ๊ท๋ฌด๊ฐ์ค์ด ์ณ๋ค๋ ์ง์ ์ ์ธ ์ฆ๊ฑฐ๊ฐ ๋์ง๋ ์์ง๋ง, ์ ์ด๋ ์ด ๊ท๋ฌด๊ฐ์ค์ ๊ธฐ๊ฐํ ์๋ ์๊ฒ ๋์์ผ๋ฏ๋ก ์ด ์๊ณ์ด์ด ์์ ์ ์ธ ์๊ณ์ด์ด๋ผ๊ณ ๋งํ ์๋ ์๋ค.
์์ ์ ์ด์ง ์์ ์๊ณ์ด์ ์์ ์ ์ธ ์๊ณ์ด๋ก ๋ฐ๊พธ๊ธฐ ์ํด ํฌ๊ฒ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๊ฒ์ด๋ค. ํ๊ฐ์ง๋ ์ ์ฑ์ ์ธ ๋ถ์์ ํตํด ๋ณด๋ค ์์ ์ (starionary)์ธ ํน์ฑ์ ๊ฐ์ง๋๋ก ๊ธฐ์กด์ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณต/๋ณํํ๋ ์๋๋ค์ด๊ณ , ๋ค๋ฅธ ํ๋๋ ์๊ณ์ด ๋ถํด(Time series decomposition)๋ผ๋ ๊ธฐ๋ฒ์ ์ ์ฉํ๋ ๊ฒ์ด๋ค.
๋ก๊ทธํจ์ ๋ณํ
ts_log = np.log(ts2)
plt.plot(ts_log)
augmented_dickey_fuller_test(ts_log)
"""
Results of Dickey-Fuller Test:
Test Statistic -1.717017
p-value 0.422367
#Lags Used 13.000000
Number of Observations Used 130.000000
Critical Value (1%) -3.481682
Critical Value (5%) -2.884042
Critical Value (10%) -2.578770
dtype: float64
"""
p-value๊ฐ 0.42๋ก ๋ฌด๋ ค ์ ๋ฐ ์ด์ ์ค์ด๋ค์๋ค. ์ ์ฑ์ ์ผ๋ก๋ ์๊ฐ ์ถ์ด์ ๋ฐ๋ฅธ ๋ถ์ฐ์ด ์ผ์ ํด์ง ๊ฒ์ ํ์ธํ ์ ์๋ค. ์์ฃผ ํจ๊ณผ์ ์ธ ๋ณํ์ด์๋ ๊ฒ ๊ฐ์ด ๋ณด์ด๋, ๊ฐ์ฅ ๋๋๋ฌ์ง๋ ๋ฌธ์ ์ ์ ์๊ฐ ์ถ์ด์ ๋ฐ๋ผ ํ๊ท ์ด ๊ณ์ ์ฆ๊ฐํ๋ค๋ ์ ์ด๋ค.
Moving average ์ ๊ฑฐ - ์ถ์ธ(Trend) ์์ํ๊ธฐ
์๊ณ์ด ๋ถ์์์ ์์ ๊ฐ์ด ์๊ฐ ์ถ์ด์ ๋ฐ๋ผ ๋ํ๋๋ ํ๊ท ๊ฐ ๋ณํ๋ฅผ ์ถ์ธ(trend)๋ผ๊ณ ํ๋ค. ์ด ๋ณํ๋์ ์ ๊ฑฐํด ์ฃผ๋ ค๋ฉด ๊ฑฐ๊พธ๋ก Moving Average, ์ฆ rolling mean์ ๊ตฌํด์ ts_log
๋ฅผ ๋นผ์ฃผ๋ฉด ๋๋ค.
# moving average๊ตฌํ๊ธฐ
moving_avg = ts_log.rolling(window=12).mean()
plt.plot(ts_log)
plt.plot(moving_avg, color='red')
# ๋ณํ๋ ์ ๊ฑฐ
ts_log_moving_avg = ts_log - moving_avg
ts_log_moving_avg.head(15)
# ๊ฒฐ์ธก์น ์ ๊ฑฐ
ts_log_moving_avg.dropna(inplace=True)
ts_log_moving_avg.head(15)
plot_rolling_statistics(ts_log_moving_avg)
augmented_dickey_fuller_test(ts_log_moving_avg)
"""
Results of Dickey-Fuller Test:
Test Statistic -3.162908
p-value 0.022235
#Lags Used 13.000000
Number of Observations Used 119.000000
Critical Value (1%) -3.486535
Critical Value (5%) -2.886151
Critical Value (10%) -2.579896
dtype: float64
"""
p-value๊ฐ 0.02 ์์ค์ด ๋์์ผ๋ฏ๋ก, 95% ์ด์์ confidence๋ก ์ด time series๋ stationaryํ๋ค๊ณ ํ ์ ์์ ๊ฒ์ด๋ค. ๊ทธ๋ฌ๋ ์ง๊ธ๊น์ง์ ์ ๊ทผ์์ ํ๊ฐ์ง ์จ๊ฒจ์ง ๋ฌธ์ ์ ์ด ์๋ค. ๋ฐ๋ก Moving Average๋ฅผ ๊ณ์ฐํ๋ window=12๋ก ์ ํํ๊ฒ ์ง์ ํด ์ฃผ์ด์ผ ํ๋ค๋ ์ ์ด๋ค. ๋ง์ฝ ์ ์ฝ๋์์ window=6์ ์ ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
moving_avg_6 = ts_log.rolling(window=6).mean()
ts_log_moving_avg_6 = ts_log - moving_avg_6
ts_log_moving_avg_6.dropna(inplace=True)
plot_rolling_statistics(ts_log_moving_avg_6)
augmented_dickey_fuller_test(ts_log_moving_avg_6)
"""
Results of Dickey-Fuller Test:
Test Statistic -2.273822
p-value 0.180550
#Lags Used 14.000000
Number of Observations Used 124.000000
Critical Value (1%) -3.484220
Critical Value (5%) -2.885145
Critical Value (10%) -2.579359
dtype: float64
"""
๊ทธ๋ํ๋ฅผ ์ ์ฑ์ ์ผ๋ก ๋ถ์ํด์๋ window=12์ผ ๋์ ๋ณ ์ฐจ์ด๋ฅผ ๋๋์ ์์ง๋ง Augmented Dickey-Fuller Test์ ๊ฒฐ๊ณผ p-value๋ 0.18 ์์ค์ด์ด์ ์์ง๋ ์์ ์ ์๊ณ์ด์ด๋ผ๊ณ ๋งํ ์ ์๊ฒ ๋์๋ค.
์ด ๋ฐ์ดํฐ์ ์ ์ ๋จ์๋ก ๋ฐ์ํ๋ ์๊ณ์ด์ด๋ฏ๋ก 12๊ฐ์ ๋จ์๋ก ์ฃผ๊ธฐ์ฑ์ด ์๊ธฐ ๋๋ฌธ์ window=12๊ฐ ์ ๋นํ๋ค๋ ๊ฒ์ ์ถ์ธกํ ์๋ ์์ ๊ฒ ๊ฐ์ต๋๋ค๋ง, moving average๋ฅผ ๊ณ ๋ คํ ๋๋ rolling mean์ ๊ตฌํ๊ธฐ ์ํ window ํฌ๊ธฐ๋ฅผ ๊ฒฐ์ ํ๋ ๊ฒ์ด ๋งค์ฐ ์ค์ํ๋ค๋ ๊ฒ์ ๊ธฐ์ตํด๋์.
์ฐจ๋ถ(Differencing) - ๊ณ์ ์ฑ(Seasonality) ์์ํ๊ธฐ
Trend์๋ ์กํ์ง ์์ง๋ง ์๊ณ์ด ๋ฐ์ดํฐ ์์ ํฌํจ๋ ํจํด์ด ํ์ ๋์ง ์์ ์ฃผ๊ธฐ์ ๋ณํ๋ ์์ธก์ ๋ฐฉํด๊ฐ ๋๋ ๋ถ์์ ์ฑ ์์์ด๋ค. ์ด๊ฒ์ Moving Average ์ ๊ฑฐ๋ก๋ ์์๋์ง ์๋ ํจ๊ณผ๋ก, ์ด๋ฐ ๊ณ์ ์ , ์ฃผ๊ธฐ์ ํจํด์ ๊ณ์ ์ฑ(Seasonality)๋ผ๊ณ ํ๋ค.
์ด๋ฐ ํจํด์ ์์ํ๊ธฐ ์ํด ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์๋ ์ฐจ๋ถ(Differencing)์ด ์๋ค. ์๊ณ์ด์ ํ ์คํ ์์ผ๋ก ์ํํธํ ์๊ณ์ด์ ์๋ ์๊ณ์ด์ ๋นผ ์ฃผ๋ ๋ฐฉ๋ฒ์ด๋ค. ์ด๋ ๊ฒ ๋๋ฉด ๋จ์ ๊ฒ์ ํ์ฌ ์คํ ๊ฐ - ์ง์ ์คํ ๊ฐ์ด ๋์ด ์ ํํ ์ด๋ฒ ์คํ ์์ ๋ฐ์ํ ๋ณํ๋์ ์๋ฏธํ๊ฒ ๋๋ค.
ts_log_moving_avg_shift = ts_log_moving_avg.shift()
plt.plot(ts_log_moving_avg, color='blue')
plt.plot(ts_log_moving_avg_shift, color='green')
ts_log_moving_avg_diff = ts_log_moving_avg - ts_log_moving_avg_shift
ts_log_moving_avg_diff.dropna(inplace=True)
plt.plot(ts_log_moving_avg_diff)
plot_rolling_statistics(ts_log_moving_avg_diff)
augmented_dickey_fuller_test(ts_log_moving_avg_diff)
"""
Results of Dickey-Fuller Test:
Test Statistic -3.912981
p-value 0.001941
#Lags Used 13.000000
Number of Observations Used 118.000000
Critical Value (1%) -3.487022
Critical Value (5%) -2.886363
Critical Value (10%) -2.580009
dtype: float64
"""
Trend๋ฅผ ์ ๊ฑฐํ๊ณ ๋ ์๊ณ์ด์๋ค๊ฐ 1์ฐจ ์ฐจ๋ถ(1st order differencing)์ ์ ์ฉํ์ฌ Seasonality ํจ๊ณผ๋ฅผ ๋ค์ ์์ํ ๊ฒฐ๊ณผ, p-value๊ฐ ์ด์ ์ 10% ์ ๋๊น์ง๋ก ์ค์ด๋ค์์ต๋๋ค. ๋ฐ์ดํฐ์ ๋ฐ๋ผ์๋ 2์ฐจ ์ฐจ๋ถ(2nd order differencing, ์ฐจ๋ถ์ ์ฐจ๋ถ), 3์ฐจ ์ฐจ๋ถ(3rd order differencing, 2์ฐจ ์ฐจ๋ถ์ ์ฐจ๋ถ)์ ์ ์ฉํ๋ฉด ๋์ฑ p-value๋ฅผ ๋ฎ์ถ ์ ์์์ง๋ ๋ชจ๋ฅธ๋ค.
statsmodels
๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์๋ seasonal_decompose
๋ฉ์๋๋ฅผ ํตํด ์๊ณ์ด ์์ ์กด์ฌํ๋ trend, seasonality๋ฅผ ์ง์ ๋ถ๋ฆฌํด ๋ผ ์ ์๋ ๊ธฐ๋ฅ์ด ์๋ค. ์ด ๊ธฐ๋ฅ์ ํ์ฉํ๋ฉด ์ฐ๋ฆฌ๊ฐ ์์์ ์ง์ ์ํํ๋ moving average ์ ๊ฑฐ, differencing ๋ฑ์ ๊ฑฐ์น์ง ์๊ณ ๋ ํจ์ฌ ์์ ์ ์ธ ์๊ณ์ด์ ๋ถ๋ฆฌํด ๋ผ ์ ์๊ฒ ๋๋ค.
from statsmodels.tsa.seasonal import seasonal_decompose
decomposition = seasonal_decompose(ts_log)
trend = decomposition.trend
seasonal = decomposition.seasonal
residual = decomposition.resid
plt.rcParams["figure.figsize"] = (11,6)
plt.subplot(411)
plt.plot(ts_log, label='Original')
plt.legend(loc='best')
plt.subplot(412)
plt.plot(trend, label='Trend')
plt.legend(loc='best')
plt.subplot(413)
plt.plot(seasonal,label='Seasonality')
plt.legend(loc='best')
plt.subplot(414)
plt.plot(residual, label='Residuals')
plt.legend(loc='best')
plt.tight_layout()
Original
์๊ณ์ด์์ Trend
์ Seasonality
๋ฅผ ์ ๊ฑฐํ๊ณ ๋ ๋๋จธ์ง๋ฅผ Residual
์ด๋ผ๊ณ ํ๋ค. ๋ค์ง์ด์ ๋งํ๋ฉด Trend+Seasonality+Residual=Original
์ด ์ฑ๋ฆฝํ๋ค๋ ๋ป์ด๋ค. ์ด๋ฌํ Decomposing์ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ์ดํดํ๋ ์ค์ํ ๊ด์ ์ ์ ์ํด ์ค๋ค.
# Residual ์์ ์ฑ ์ฌ๋ถ ํ์ธ
plt.rcParams["figure.figsize"] = (13,6)
plot_rolling_statistics(residual)
residual.dropna(inplace=True)
augmented_dickey_fuller_test(residual)
"""
Results of Dickey-Fuller Test:
Test Statistic -6.332387e+00
p-value 2.885059e-08
#Lags Used 9.000000e+00
Number of Observations Used 1.220000e+02
Critical Value (1%) -3.485122e+00
Critical Value (5%) -2.885538e+00
Critical Value (10%) -2.579569e+00
dtype: float64
"""
Decomposing
์ ํตํด ์ป์ด์ง Residual
์ ์๋์ ์ผ๋ก ๋ฎ์ p-value๋ฅผ ๋ณด์ฌ ์ค๋ค. ์ด ์ ๋๋ฉด ํ์คํ ์์ธก ๊ฐ๋ฅํ ์์ค์ ์์ ์ ์ธ ์๊ณ์ด์ด ์ป์ด์ก๋ค๊ณ ๋ณผ ์ ์์ ๊ฒ์ด๋ค.
์ด์ ์คํ
์์ ์ฐ๋ฆฌ๋ ์๊ณ์ด ๋ฐ์ดํฐ๊ฐ Trend์ Seasonality์ Residual๋ก Decompose๋๋ฉฐ, Trend์ Seasonality๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๋ถ๋ฆฌํด ๋ธ ๊ฒฝ์ฐ ์์ฃผ ์์ธก๋ ฅ ์๋ ์์ ์ ์ธ ์๊ณ์ด ๋ฐ์ดํฐ๋ก ๋ณํ ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ ํ์ธํ์๋ค. ์ด๋ฐ ์๋ฆฌ๋ฅผ ์ด์ฉํ์ฌ ์๊ณ์ด ๋ฐ์ดํฐ ์์ธก๋ชจ๋ธ์ ์๋์ผ๋ก ๋ง๋ค์ด ์ฃผ๋ ๋ชจ๋ธ์ด ARIMA(Autoregressive Integrated Moving Average)
์ด๋ค.
ARIMA
๋ AR(Autoregressive)
+ I(Integrated)
+ MA(Moving Average)
๊ฐ ํฉ์ณ์ง ๋ชจ๋ธ์ด๋ค.
AR(์๊ธฐํ๊ท, Autoregressive)
- ์๊ธฐํ๊ท(AR)๋,
$Y_t$ ๊ฐ ์ด์ p๊ฐ์ ๋ฐ์ดํฐ$Y_{t-1},Y_{t-2}, ..., Y_{t-p}$ ์ ๊ฐ์คํฉ์ผ๋ก ์๋ ดํ๋ค๊ณ ๋ณด๋ ๋ชจ๋ธ์ด๋ค. - ๊ฐ์ค์น์ ํฌ๊ธฐ๊ฐ 1๋ณด๋ค ์์
$Y_{t-1},Y_{t-2}, ..., Y_{t-p}$ ์ ๊ฐ์คํฉ์ผ๋ก ์๋ ดํ๋ ์๊ธฐํ๊ท ๋ชจ๋ธ๊ณผ ์์ ์ ์๊ณ์ด์ ๋๊ณ์ ์ผ๋ก ๋์น์ด๋ค. - AR์ ์ผ๋ฐ์ ์ธ ์๊ณ์ด์์ Trend์ Seasonality๋ฅผ ์ ๊ฑฐํ Residual์ ํด๋นํ๋ ๋ถ๋ถ์ ๋ชจ๋ธ๋งํ๋ค๊ณ ๋ณผ ์ ์๋ค.
- ์ฃผ์๊ฐ์ด ํญ์ ์ผ์ ํ ๊ท ํ ์์ค์ ์ ์งํ ๊ฒ์ด๋ผ๊ณ ์์ธกํ๋ ๊ด์ ์ด ๋ฐ๋ก ์ฃผ์ ์๊ณ์ด์ AR๋ก ๋ชจ๋ธ๋งํ๋ ๊ด์ ์ด๋ผ๊ณ ๋ณผ ์ ์๋ค.
MA(์ด๋ํ๊ท , Moving Average)
- ์ด๋ํ๊ท (MV)์
$Y_t$ ๊ฐ ์ด์ q๊ฐ์ ์์ธก์ค์ฐจ๊ฐ$e_{t-1},e_{t-2}, ..., e_{t-q}$ ์ ๊ฐ์คํฉ์ผ๋ก ์๋ ดํ๋ค๊ณ ๋ณด๋ ๋ชจ๋ธ์ด๋ค. - MA๋ ์ผ๋ฐ์ ์ธ ์๊ณ์ด์์ Trend์ ํด๋นํ๋ ๋ถ๋ถ์ ๋ชจ๋ธ๋งํ๋ค๊ณ ๋ณผ ์ ์๋ค. ์์ธก์ค์ฐจ๊ฐ
$e_{t-1}$ ์ด +๋ผ๋ฉด ๋ชจ๋ธ ์์ธก๋ณด๋ค ๊ด์ธก๊ฐ์ด ๋ ๋์๋ค๋ ๋ป์ด๋ฏ๋ก, ๋ค์$Y_t$ ์์ธก ์์๋ ์์ธก์ง๋ฅผ ์ฌ๋ ค์ก๊ฒ ๋๋ค. - ์ฃผ์๊ฐ์ ํญ์ ์ต๊ทผ์ ์ฆ๊ฐ ํจํด์ด ์ง์๋ ๊ฒ์ด๋ผ๊ณ ์์ธกํ๋ ๊ด์ ์ด ๋ฐ๋ก ์ฃผ์ ์๊ณ์ด์ MA๋ก ๋ชจ๋ธ๋งํ๋ ๊ด์ ์ด๋ผ๊ณ ๋ณผ ์ ์๋ค.
I (์ฐจ๋ถ๋์ , Integration)
- ์ฐจ๋ถ๋์ ์
$Y_t$ ์ด ์ด์ ๋ฐ์ดํฐ์ d์ฐจ ์ฐจ๋ถ์ ๋์ (integration) ํฉ์ด๋ผ๊ณ ๋ณด๋ ๋ชจ๋ธ์ด๋ค. - ์๋ฅผ ๋ค์ด์ d=1์ด๋ผ๋ฉด,
$Y_t$ ๋$Y_{t-1}$ ๊ณผ$ฮY_{t-1}$ ์ ํฉ์ผ๋ก ๋ณด๋ ๊ฒ์ด๋ค. - I๋ ์ผ๋ฐ์ ์ธ ์๊ณ์ด์์ Seasonality์ ํด๋นํ๋ ๋ถ๋ถ์ ๋ชจ๋ธ๋งํ๋ค๊ณ ๋ณผ ์ ์๋ค.
ARIMA๋ ์ 3๊ฐ์ง ๋ชจ๋ธ์ ๋ชจ๋ ํ๊บผ๋ฒ์ ๊ณ ๋ คํ๋ ๋ชจ๋ธ์ด๋ค.
ARIMA๋ฅผ ํ์ฉํด์ ์๊ณ์ด ์์ธก ๋ชจ๋ธ์ ์ฑ๊ณต์ ์ผ๋ก ๋ง๋ค๊ธฐ ์ํด์๋ ARIMA์ ๋ชจ์(parameter)๋ฅผ ๋ฐ์ดํฐ์ ๋ง๊ฒ ์ค์ ํด์ผ ํ๋ค. ์ฝ๊ฒ ๋งํ์๋ฉด ๋ชจ๋ธ์ ์์ฃผ ํต์ฌ์ ์ธ ์ซ์๋ค์ ์ ์ค์ ํด์ผ ์ฌ๋ฐ๋ฅธ ์์ธก์์ ๊ตฌํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
ARIMA์ ๋ชจ์๋ 3๊ฐ์ง๊ฐ ์๋๋ฐ, ์๊ธฐํ๊ท ๋ชจํ(AR)์ ์์ฐจ๋ฅผ ์๋ฏธํ๋ p, ์ฐจ๋ถ(diffdrence) ํ์๋ฅผ ์๋ฏธํ๋ d, ์ด๋ํ๊ท ๋ชจํ(MA)์ ์์ฐจ๋ฅผ ์๋ฏธํ๋ q๊ฐ ์๋ค.
์ด๋ค ์ค p ์ q ์ ๋ํด์๋ ํต์์ ์ผ๋ก p + q < 2, p * q = 0 ์ธ ๊ฐ๋ค์ ์ฌ์ฉํ๋๋ฐ, ์ด๋ p ๋ q ์ค ํ๋์ ๊ฐ์ด 0์ด๋ผ๋ ๋ป์ด๋ค. ์ด๋ ๊ฒ ํ๋ ์ด์ ๋ ์ค์ ๋ก ๋๋ถ๋ถ์ ์๊ณ์ด ๋ฐ์ดํฐ๋ ์๊ธฐํ๊ท ๋ชจํ(AR)์ด๋ ์ด๋ํ๊ท ๋ชจํ(MA) ์ค ํ๋์ ๊ฒฝํฅ๋ง์ ๊ฐํ๊ฒ ๋ ๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋ฌ๋ฉด ARIMA(p,d,q) ๋ชจ๋ธ์ ๋ชจ์๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐฉ๋ฒ์ ์ด๋ป๊ฒ ๋ ๊น? ์๋ฅผ ๋ค์ด q๋ผ๋ฉด ์ด์ ์คํ ์์ Moving Average๋ฅผ ๊ตฌํ ๋์ window=12์ ํด๋นํ๋ ๊ฐ๊ณผ ๊ฐ์ ์ญํ ์ ํ๋ค๋ ๋๋์ด ๋ ๋ค. ์ด ๊ฐ์ ์ด๋ป๊ฒ ๊ฒฐ์ ํ๋๋๊ฐ ์๊ณ์ด ๋ฐ์ดํฐ์ ์์ ์ฑ ๋ฐ ์ดํ ์์ธก์ฑ๋ฅ์ ์ํฅ์ ํฌ๊ฒ ๋ฏธ์น ๊ฒ์ด๋ค.
ARIMA์ ์ ์ ํ ๋ชจ์ p,d,q๋ฅผ ์ ํํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์๋ ์์ฒญ๋ ํต๊ณํ์ ์ธ ๋ค์ํ ์๋๋ค์ด ์๋ค. ํต๊ณํ์ ์ธ ์ค๋ช
์ ์๋ตํ๊ณ ๊ฒฐ๋ก ๋ถํฐ ์ด์ผ๊ธฐํ์๋ฉด, ๋ชจ์ p,d,q๋ ACF(Autocorrelation Function)
์ PACF(Partial Autocorrelation Function)
์ ํตํด ๊ฒฐ์ ํ ์ ์๋ค. ์ด AutoCorrelation์ ์ฐ๋ฆฌ๊ฐ ๋งจ ์ฒซ ์คํ
์์ ๋ง๋ฌ๋ ๋ฐ๋ก ๊ฐ๋
์ค ํ๋์ธ ์๊ธฐ์๊ด๊ณ์์ ๊ฐ์ ๊ฒ์ด๋ค.
ACF ๋ ์์ฐจ(lag)์ ๋ฐ๋ฅธ ๊ด์ธก์น๋ค ์ฌ์ด์ ๊ด๋ จ์ฑ์ ์ธก์ ํ๋ ํจ์์ด๋ฉฐ, PACF ๋ ๋ค๋ฅธ ๊ด์ธก์น์ ์ํฅ๋ ฅ์ ๋ฐฐ์ ํ๊ณ ๋ ์์ฐจ์ ๊ด์ธก์น ๊ฐ ๊ด๋ จ์ฑ์ ์ธก์ ํ๋ ํจ์์ด๋ค.
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
plot_acf(ts_log) # ACF : Autocorrelation ๊ทธ๋ํ ๊ทธ๋ฆฌ๊ธฐ
plot_pacf(ts_log) # PACF : Partial Autocorrelation ๊ทธ๋ํ ๊ทธ๋ฆฌ๊ธฐ
plt.show()
์๋ ๊ทธ๋ฆผ์ ACF
๋ฅผ ํตํด MA ๋ชจ๋ธ์ ์์ฐจ q๋ฅผ ๊ฒฐ์ ํ๊ณ , PACF
๋ฅผ ํตํด AR ๋ชจ๋ธ์ ์์ฐจ p๋ฅผ ๊ฒฐ์ ํ ์ ์์์ ํต๊ณํ์ ์ผ๋ก ์ค๋ช
ํ๋ ์ํฐํด์์ ์์ฝ๊ฒฐ๋ก ๋ถ๋ถ๋ง ๊ฐ์ ธ์จ ๊ฒ์ด๋ค.
์ด ๊ฒฐ๋ก ์ ๋ฐ๋ผ ๋ณด์๋ฉด PACF ๊ทธ๋ํ๋ฅผ ๋ณผ ๋ p=1์ด ๋งค์ฐ ์ ํฉํ ๊ฒ ๊ฐ๋ค. p๊ฐ 2 ์ด์์ธ ๊ตฌ๊ฐ์์ PACF๋ ๊ฑฐ์ 0์ ๊ฐ๊น์์ง๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค. PACF๊ฐ 0์ด๋ผ๋ ์๋ฏธ๋ ํ์ฌ ๋ฐ์ดํฐ์ p ์์ ๋จ์ด์ง ์ด์ ์ ๋ฐ์ดํฐ๋ ์๊ด๋๊ฐ 0, ์ฆ ์๋ฌด ์๊ด ์๋ ๋ฐ์ดํฐ์ด๊ธฐ ๋๋ฌธ์ ๊ณ ๋ คํ ํ์๊ฐ ์๋ค๋ ๋ป์ด๋ค.
๋ฐ๋ฉด ACF๋ ์ ์ฐจ์ ์ผ๋ก ๊ฐ์ํ๊ณ ์์ด์ AR(1) ๋ชจ๋ธ์ ์ ์ฌํ ํํ๋ฅผ ๋ณด์ด๊ณ ์๋ค.
q์ ๋ํด์๋ ์ ํฉํ ๊ฐ์ด ์์ด ๋ณด์ธ๋ค. MA๋ฅผ ๊ณ ๋ คํ ํ์๊ฐ ์๋ค๋ฉด q=0์ผ๋ก ๋ ์ ์์ผ๋, q๋ฅผ ๋ฐ๊ฟ ๊ฐ๋ฉด์ ํ์ธํด ๋ณด๋ ๊ฒ๋ ์ข์ ๊ฒ ๊ฐ๋ค.
d๋ฅผ ๊ตฌํ๊ธฐ ์ํด์๋ ์ข ๋ค๋ฅธ ์ ๊ทผ์ด ํ์ํ๋ค. d์ฐจ ์ฐจ๋ถ์ ๊ตฌํด ๋ณด๊ณ ์ด๋ ์๊ณ์ด์ด ์์ ๋ ์ํ์ธ์ง๋ฅผ ํ์ธํด ๋ณด์์ผ ํ๋ค.
# 1์ฐจ ์ฐจ๋ถ ๊ตฌํ๊ธฐ
diff_1 = ts_log.diff(periods=1).iloc[1:]
diff_1.plot(title='Difference 1st')
augmented_dickey_fuller_test(diff_1)
"""
Results of Dickey-Fuller Test:
Test Statistic -2.717131
p-value 0.071121
#Lags Used 14.000000
Number of Observations Used 128.000000
Critical Value (1%) -3.482501
Critical Value (5%) -2.884398
Critical Value (10%) -2.578960
dtype: float64
"""
# 2์ฐจ ์ฐจ๋ถ ๊ตฌํ๊ธฐ
diff_2 = diff_1.diff(periods=1).iloc[1:]
diff_2.plot(title='Difference 2nd')
augmented_dickey_fuller_test(diff_2)
"""
Results of Dickey-Fuller Test:
Test Statistic -8.196629e+00
p-value 7.419305e-13
#Lags Used 1.300000e+01
Number of Observations Used 1.280000e+02
Critical Value (1%) -3.482501e+00
Critical Value (5%) -2.884398e+00
Critical Value (10%) -2.578960e+00
dtype: float64
"""
์ด๋ฒ ๊ฒฝ์ฐ์๋ 1์ฐจ ์ฐจ๋ถ์ ๊ตฌํ์ ๋ ์ฝ๊ฐ ์ ๋งคํ ์์ค์ ์์ ํ ์ํ๋ฅผ ๋ณด์๊ณ , 2์ฐจ ์ฐจ๋ถ์ ๊ตฌํ์ ๋๋ ํ์คํ ์์ ํ ์ํ์์ง๋ง ์ด๋ฒ ๊ฒฝ์ฐ์๋ d=1๋ก ๋จผ์ ์๋ํด๋ณด์.
# train, test ๋ฐ์ดํฐ ๋ถ๋ฆฌ
train_data, test_data = ts_log[:int(len(ts_log)*0.9)], ts_log[int(len(ts_log)*0.9):]
plt.figure(figsize=(10,6))
plt.grid(True)
plt.plot(ts_log, c='r', label='training dataset') # train_data๋ฅผ ์ ์ฉํ๋ฉด ๊ทธ๋ํ๊ฐ ๋์ด์ ธ ๋ณด์ด๋ฏ๋ก ์์ฐ์ค๋ฌ์ด ์ฐ์ถ์ ์ํด ts_log๋ฅผ ์ ํ
plt.plot(test_data, c='b', label='test dataset')
plt.legend()
# ๋ฐ์ดํฐ์
ํํ ํ์ธ
print(ts_log[:2])
print(train_data.shape)
print(test_data.shape)
์์์ ์ฐ๋ฆฌ๋ ์ผ๋จ p=1, d=1, q=0์ ๋ชจ์๋ก ๊ฐ์ง๋ ARIMA ๋ชจ๋ธ์ ์ฐ์ ์ ์ผ๋ก ๊ณ ๋ คํ๊ฒ ๋์๋ค. ARIMA ๋ชจ๋ธ์ ํ๋ จํ๋ ๊ฒ์ ์๋์ ๊ฐ์ด ๊ฐ๋จํ๋ค.
from statsmodels.tsa.arima_model import ARIMA
# Build Model
model = ARIMA(train_data, order=(1, 1, 0))
fitted_m = model.fit(disp=-1)
print(fitted_m.summary())
# ๋ชจ๋ธ ์์ธก ํ์ธ
fitted_m.plot_predict()
# Forecast : ๊ฒฐ๊ณผ๊ฐ fc์ ๋ด๊น๋๋ค.
fc, se, conf = fitted_m.forecast(len(test_data), alpha=0.05) # 95% conf
# Make as pandas series
fc_series = pd.Series(fc, index=test_data.index) # ์์ธก๊ฒฐ๊ณผ
lower_series = pd.Series(conf[:, 0], index=test_data.index) # ์์ธก๊ฒฐ๊ณผ์ ํํ ๋ฐ์ด๋
upper_series = pd.Series(conf[:, 1], index=test_data.index) # ์์ธก๊ฒฐ๊ณผ์ ์ํ ๋ฐ์ด๋
# Plot
plt.figure(figsize=(9,5), dpi=100)
plt.plot(train_data, label='training')
plt.plot(test_data, c='b', label='actual price')
plt.plot(fc_series, c='r',label='predicted price')
plt.fill_between(lower_series.index, lower_series, upper_series, color='k', alpha=.10)
plt.legend()
plt.show()
์ต์ข ์ ์ธ ๋ชจ๋ธ์ ์ค์ฐจ์จ์ ๊ณ์ฐํ๋ ค๋ฉด, ๊ทธ๋์ ๋ก๊ทธ ๋ณํ๋ ์๊ณ์ด์ ์ฌ์ฉํด ์๋ ๊ฒ์ ๋ชจ๋ ์ง์ ๋ณํํ์ฌ ์๋ณธ์ ์ค์ผ์ผ๋ก ๊ณ์ฐํด์ผ ํ๋นํ๋ค. np.exp()๋ฅผ ํตํด ์ ๋ถ ์๋ณธ ์ค์ผ์ผ๋ก ๋๋ฆฐ ํ MSE, MAE, RMSE, MAPE๋ฅผ ๊ณ์ฐํ๋ค.
from sklearn.metrics import mean_squared_error, mean_absolute_error
import math
mse = mean_squared_error(np.exp(test_data), np.exp(fc))
print('MSE: ', mse)
mae = mean_absolute_error(np.exp(test_data), np.exp(fc))
print('MAE: ', mae)
rmse = math.sqrt(mean_squared_error(np.exp(test_data), np.exp(fc)))
print('RMSE: ', rmse)
mape = np.mean(np.abs(np.exp(fc) - np.exp(test_data))/np.abs(np.exp(test_data)))
print('MAPE: {:.2f}%'.format(mape*100))
"""
MSE: 5409.550103512347
MAE: 63.136923863759435
RMSE: 73.54964380275644
MAPE: 14.08%
"""
์ต์ข ์ ์ผ๋ก ์์ธก ๋ชจ๋ธ์ ๋ฉํธ๋ฆญ์ผ๋ก ํ์ฉํ๊ธฐ์ ์ ๋นํ MAPE ๊ธฐ์ค์ผ๋ก 14% ์ ๋์ ์ค์ฐจ์จ์ ๋ณด์๋ค. ๋ง์กฑ์ค๋ฝ์ง ๋ชปํ ๊ฒฐ๊ณผ์ธ ๊ฒ ๊ฐ์์ ๋ ์ ๋นํ ๋ชจ์๋ฅผ ์ฐพ์ ๊ฐ์ ํ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค. q=8 ์ ์ค ๊ฒฝ์ฐ MAPE๊ฐ 10% ์ ๋๋ก ๋ด๋ ค๊ฐ๋ค. q=12๋ฅผ ์ธ ์ ์์ผ๋ฉด ๋์ฑ ์ข์ ๊ฒ ๊ฐ์ง๋ง ์ด๋ฒ ๊ฒฝ์ฐ์๋ ๋ฐ์ดํฐ์ ์ด ๋๋ฌด ์์ ์ธ ์ ์๋ค.
์ผํ ํ์ด๋ธ์ค์์ ์ข ๋ชฉ์ ๊ฒ์ํ ํ, "Historical Data" ํญ์์ "Time Period"๋ฅผ "Max"๋ก ์ ํ, "Apply" ๋ฒํผ์ ๋๋ฌ ๊ณผ๊ฑฐ ์์ฅํ ์์ ๋ถํฐ ๊ฐ์ฅ ์ต๊ทผ๊น์ง์ ์๋ฃ๋ฅผ ์กฐํํ ๋ค์ "Download"๋ฅผ ํด๋ฆญํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ๋ค์ด๋ก๋๋ฅผ ํ ์ ์๋ค.
- ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ์ฒ์ ์ ํ์ ๋ ๋ค๋ฃจ๊ธฐ ์ด๋ ค์ด ๋ฐ์ดํฐ๋ผ๊ณ ์๊ฐํ๋๋ฐ ๋ ธ๋๋ฅผ ์งํํ๋ฉด์ ๊ณ์ ๋ค๋ฃจ๋ค๋ณด๋ ์กฐ๊ธ์ ์ต์ํด์ง ๊ฒ ๊ฐ๋ค.
- ์์ ๋ถํฐ ์ฃผ๊ฐ๋ฅผ ์์ธกํ๋ ๊ฒ์ ํ๋ฒ ํด๋ณด๊ณ ์ถ์๋๋ฐ ์๊ฐ๋ณด๋ค ์ด๋ ค์ด ๊ฒ ๊ฐ๋ค. ํ๊ธด ์ฌ์ฐ๋ฉด ๋๊ตฌ๋ ๋ถ์๊ฐ ๋๊ฒ ์ง...
- ์ฒ์์ผ๋ก raw data๋ฅผ ์ฒ๋ฆฌํ๋ ๊ณผ์ ์์ ์ด์์น๋ฅผ ๋ฐ๊ฒฌํ์ฌ ๊ทธ๋์ ํ์ตํ ๋ฐฉ๋ฒ์ ๋์ํ์ฌ ์ ์์ ์ผ๋ก ์์ ํ์๋ค! ์ง์ ํด๋ณด๊ณ ๋๋ ์กฐ๊ธ์ ์ฑ์ฅํ๋ค๊ณ ๋๊ผ๋ค.
- ์ด์ ์ ํด์ปคํค์ ์งํํ์ ๋๋ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ๊ฐ๊ฒฉ์ ์์ธกํ๋ ๋ฌธ์ ์์ ARIMA ๋ชจ๋ธ์ ์ฑ๋ฅ์ด ๋ณ๋ก์ฌ์ XGBoost์ LightGBM์ ์ด์ฉํ๋ ๊ธฐ์ต์ด ๋๋ค. ์ด ๋ชจ๋ธ๋ ์ถํ ์์๋ธ ๋ชจ๋ธ์ ์ด์ฉํด์ ํ๋ฒ ์์ธก์ ์๋ํด๋ด์ผ๊ฒ ๋ค.
http://www.dodomira.com/2016/04/21/arima_in_r/ ARIMA ๋ชจํ
https://destrudo.tistory.com/15 ๊ณต๋ถ์ฐ๊ณผ ์๊ด๊ณ์
https://rfriend.tistory.com/264 ๊ฒฐ์ธก์น ๋ณด๊ฐ