ARIMA๋ฅผ ๋ค๋ฃฌ ์ ํ๋ธ ๊ฐ์์ ๋ค์ํ ๊ธฐ์ ๋ธ๋ก๊ทธ๋ค์ ์ฐธ๊ณ ํ์ฌ
ARIMA ๋ชจ๋ธ์ ๋ํด ๊ฐ๋จํ ์ ๋ฆฌํด๋ณด์๊ณ
๊ฐ๋จํ ํ์ด์ฌ ์์ ๋ก ์ฝ๋๋ ๋ค๋ค๋ณด๋ ค ํ๋ค.
ARIMA ๋ชจ๋ธ์
Autoregressive Integrated Moving Average ๋ผ๋ ๋ป์ผ๋ก,
AR(Autoregression) ๋ชจํ๊ณผ MA(Moving Average) ๋ชจํ์ ํฉ์น ๋ชจํ์ด๋ค.
๋ ๋ฆฝ๋ณ์๊ณผ ์ข ์๋ณ์๋ฅผ ํ์ฉํ๋ ๋ค๋ฅธ ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ๊ณผ๋ ๋ฌ๋ฆฌ ์๊ฐ์ ๋ ๋ฆฝ๋ณ์๋ก ์ข ์๋ณ์๋ฅผ ์์ธกํ๋ค.
๋ํ, ์ ํต์ ์ธ ํต๊ณ ๊ธฐ๋ฒ์ ํ์ฉํ ๋ชจ๋ธ์ด๊ธฐ ๋๋ฌธ์ ํต๊ณ์ ์ธ ์ดํด๊ฐ ์ด๋์ ๋ ํ์ํ๋ค.
0. ์ ์์ฑ
์๊ณ์ด ๋ถ์์ ๋ฐ์ดํฐ๊ฐ ์ ์์ฑ์ ๋ ์ด์ผ ํ๋ค
์๊ฐ์ ๊ด๊ณ์์ด ํ๊ท ๊ณผ ๋ถ์ฐ์ด ์ผ์ ํ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ์ ์์ ์ด๋ผ๊ณ ํ๋ค.
์๊ฐ์ ํ๋ฆ์ ๋ฐ์ดํฐ๊ฐ ์ํฅ์ ๋ฐ๋๋ค๋ฉด, ์๋ก ์ถ์ธ๋ ๊ณ์ ์ฑ์ด ์๋ค๋ฉด ๊ทธ๊ฒ์ ์ ์ ์๊ณ์ด์ด ์๋๋ค.

๋น์ ์์ ์ธ ๋ฐ์ดํฐ๋ ์์ธก์ด ์ ๋๋ก ๋์ง ์๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ๋ณํ์์ผ์ผ ํ๋ค.
- ๋ก๊ทธ
(b) ๊ทธ๋ํ๋ (a) ๊ทธ๋ํ๋ฅผ ๋ก๊ทธ ๋ณํํ ๊ฒ์ด๋ค.
๋ก๊ทธ ๋ณํ์ ์ข ๋ ๋จ์ํ๋ ์ผ์ ํ ๋ถ์ฐ์ ๊ฐ๊ฒ ํด์ค๋ค
- ์ฐจ๋ถ
ํ์ฌ ์ํ์์ ์ด์ ์ํ๋ฅผ ๋นผ์ฃผ๋ ๊ฒ์ ์๋ฏธํ๋ค. (Yt - Yt-1)
(c) ๊ทธ๋ํ๋ (a) ๊ทธ๋ํ๋ฅผ ์ฐจ๋ถํ ๊ฒ์ด๋ค.
์ฐจ๋ถ์ 0์ ์ค์ฌ์ผ๋ก ํ๊ท ์ด ์ผ์ ํ๊ฒ ์ ์ง๋๋ ํจํด์ผ๋ก ๋ณํ์์ผ์ค๋ค.
1. AR ๋ชจ๋ธ
ํน์ ๋ณ์์ ๊ณผ๊ฑฐ ๊ด์ธก๊ฐ์ ์ ํ๊ฒฐํฉ์ผ๋ก ํด๋น ๋ณ์์ ๋ฏธ๋๊ฐ์ ์์ธกํ๋ ๋ชจํ์ด๋ค.
๊ณผ๊ฑฐ p๊ฐ์ ๊ด์ธก๊ฐ์ ์ ํ๊ฒฐํฉ์ผ๋ก ์์ธกํ๋ ๋ชจ๋ธ์ p์ฐจ MA๋ชจ๋ธ (AR(p))๋ผ๊ณ ํํํ๋ค.

2. MA ๋ชจ๋ธ
์์ธก์ค์ฐจ๋ฅผ ์ด์ฉํ์ฌ ๋ฏธ๋์ ๊ฐ์ ์์ธกํ๋ ๋ชจํ์ด๋ค.
๊ณผ๊ฑฐ q๊ฐ ์์ธก์ค์ฐจ์ ์ ํ๊ฒฐํฉ์ผ๋ก ์์ธกํ๋ ๋ชจ๋ธ์ q์ฐจ MA๋ชจ๋ธ (MA(q))๋ผ๊ณ ํํํ๋ค.

3. ARMA ๋ชจ๋ธ
ARMA๋ชจ๋ธ์ AR๋ชจ๋ธ๊ณผ MA๋ชจ๋ธ์ ๊ฒฐํฉํ ๋ชจ๋ธ๋ก ARMA(p,q)๋ก ํํํ๋ค.

4. ARIMA ๋ชจ๋ธ
ARIMA(p,d,q) ๋ชจ๋ธ์ ARMA๋ชจ๋ธ์ ์ฐจ๋ถ ๊ณผ์ ์ ์ถ๊ฐํ ๊ฒ์ด๋ค.
์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ dํ ์ฐจ๋ถํ๊ณ ๊ณผ๊ฑฐ p๊ฐ์ ๊ด์ธก๊ฐ๊ณผ q๊ฐ ์ค์ฐจ์ ์ํด ์์ธก๋๋ ๋ชจ๋ธ์ด๋ค.
์ต์ ์ p์ q๋ ACF์ PACF ๊ทธ๋ํ๋ฅผ ํตํด ํ์ธํ ์ ์๋ค.
1. ACF(์๊ธฐ์๊ดํจ์, AutoCorrelation Function)
์๊ธฐ์๊ด์ ๋ค๋ฅธ ์์ ์ ๊ด์ธก๊ฐ ๊ฐ ์ํธ์ฐ๊ด์ฑ์ ๋ํ๋ธ๋ค.
์์ฐจ๋ฅผ ์ ์ฉํ ์๊ณ์ด ๋ฐ์ดํฐ ๊ฐ์ ์๊ด๊ด๊ณ๋ฅผ ์๋ฏธํ๋ค.


2. PACF(ํธ์๊ธฐ์๊ดํจ์, Partial AutoCorrelation Function)
ํธ์๊ธฐ์๊ด์ ์์ฐจ๊ฐ ๋ค๋ฅธ ๋ ์๊ณ์ด ๋ฐ์ดํฐ ๊ฐ์ ์์ํ ์ํธ ์ฐ๊ด์ฑ์ ๋ํ๋ธ๋ค.
PACk๋ ์๋์ ์๊ณ์ด ๋ฐ์ดํฐ(Yt)์ ์์ฐจ k ์๊ณ์ด ๋ฐ์ดํฐ(Yt-k)๊ฐ์ ์์ํ ์๊ด๊ด๊ณ๋ก์ ๋ ์์ ์ฌ์ด์ ํฌํจ๋ ์๊ณ์ด ๋ฐ์ดํฐ(Yt-1, Yt-2, ... , Yt-k+1)์ ์ํฅ์ ์ ๊ฑฐ๋๋ค.



ACF ๋ํ์์ ํ๋์ ์์ ์์ ๋ค์ด์ค๋ ์์ฐจ(์ ๋จ์ ) - 1์ q๋ก ์ค์ ํ๋ค.
PACF ๋ํ์์ ํ๋์ ์์ ์์ ๋ค์ด์ค๋ ์์ฐจ(์ ๋จ์ ) - 1์ p๋ก ์ค์ ํ๋ค.
ํ์ด์ฌ ์์
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ์ ธ์ค๊ธฐ
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller # ADF ๊ฒ์
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf # ACF, PACF ๊ทธ๋ํ
from statsmodels.tsa.arima.model import ARIMA # ARIMA ๋ชจ๋ธ
from sklearn.metrics import mean_absolute_error, mean_squared_error
import math
import itertools
import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv("Aquifer_Petrignano.csv")
df.Depth_to_Groundwater = df.Depth_to_Groundwater.interpolate()
df.Depth_to_Groundwater.plot()

์์ธกํ๊ณ ์ ํ๋ Depth_to_Groundwater ๋ณ์ ์๊ฐํํ์ฌ ๋ฐ์ดํฐ ๋ถํฌ ํ์ธ
# Date๋ฅผ 7์ผ ๊ฐ๊ฒฉ์ผ๋ก ์ฌ์กฐ์
df_downsampled = df[['Date', 'Depth_to_Groundwater']].resample('7D', on = 'Date').mean()
df = df_downsampled.reset_index()
plt.figure(figsize = (15,8))
# 1๋
= 52์ฃผ
rolling_window = 52
sns.lineplot(x = df.Date, y = df.Depth_to_Groundwater, color = 'indianred')
sns.lineplot(x = df.Date, y = df.Depth_to_Groundwater.rolling(rolling_window).mean(), color = 'black', label = 'rolling mean')
sns.lineplot(x = df.Date, y = df.Depth_to_Groundwater.rolling(rolling_window).std(), color = 'blue', label = 'rolling std')
plt.xlim([date(2009,1,1), date(2020,6,30)])
plt.title('Feature : Depth_to_Groundwater', fontsize = 14)
plt.ylabel(ylabel = 'Depth_to_Groundwater', fontsize = 14)
plt.show()

์ฃผ ๋จ์์ ๋ฐ์ดํฐ๋ก 1๋ ์ ๋ํ ์ด๋ํ๊ท ๊ณผ ํ์คํธ์ฐจ๋ฅผ ์๊ฐํํ์๋ค.
plt.figure(figsize = (15,7))
sns.distplot(df.Depth_to_Groundwater, color = 'indianred')
plt.title('Histogram : Depth_to_Groundwater', fontsize = 14)
plt.ylabel(ylabel = 'Depth_to_Groundwater', fontsize = 14);

์ ์์ฑ ์๊ณ์ด ๋ฐ์ดํฐ๋ ํ๊ท , ๋ถ์ฐ์ด ๊ฐ์ฐ์์ ๋ถํฌ๋ฅผ ๋ฐ๋ฅธ๋ค.
๊ทธ๋ํ๋ฅผ ๋ณด๋ฉด ํ๊ท ๊ณผ ๋ถ์ฐ์ด ์ด๋์ ๋ ์ข ๋ชจ์์ ๊ทธ๋ฆฌ๋ ๊ฒ ๊ฐ๋ค.
๋ฐ์ดํฐ๊ฐ ์ ์์์ ๋ฐ๋ฅด๋์ง ๊ฒ์ฆํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ด ์๋๋ฐ ์ด๋ฅผ ADF ๊ฒ์ ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
๊ฐ๋จํ๊ฒ ADF ๊ฒ์ ๊ฒฐ๊ณผ์ p-value ๊ฐ 0.05 ์ดํ์ด๋ฉด, ๋จ์๊ทผ์ด ์๋ค๋ ๊ท๋ฌด๊ฐ์ค์ ๊ธฐ๊ฐํ๋ฏ๋ก ์๊ณ์ด ๋ฐ์ดํฐ๊ฐ ์ ์์ ์ด์ง ์๋ค๊ณ ์ถ๋ก ํ ์ ์๋ค.
result = adfuller(df.Depth_to_Groundwater.values)
print(f'adf_stat : {result[0] : 0.3f}')
print(f'p_val : {result[1] : 0.3f}')
print(f'crit_val_1 : %0.3f' % result[4]['1%'])
print(f'crit_val_1 : %0.3f' % result[4]['5%'])
print(f'crit_val_1 : %0.3f' % result[4]['10%'])

ADF ๊ฒ์ ๊ฒฐ๊ณผ p value๊ฐ 0.05๋ณด๋ค ๋ฎ์ง๋ง ์๊ฐํ ๊ทธ๋ํ๋ฅผ ๋ณด๋ฉด ๋ฐ์ดํฐ๊ฐ ์ ์์ ์ด์ง ์์ ๋ชจ์ต์ ๋ณด์ด๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ ๋ณํ์ ๊ฑฐ์ณ์ค๋ค.
# ๋ก๊ทธ ๋ณํ
df['Depth_to_Groundwater_log'] = np.log(abs(df.Depth_to_Groundwater)) #์์๋ฅผ ๋ก๊ทธ ๋ณํ ์ NaN ๋ฐํ
f, ax = plt.subplots(nrows = 2, ncols = 2, figsize= (15,6))
visualize_adfuller_results(abs(df.Depth_to_Groundwater),
'Depth_to_Groundwater \n Absolute', ax[0,0])
sns.distplot(df.Depth_to_Groundwater, ax = ax[0,1])
visualize_adfuller_results(df.Depth_to_Groundwater_log,
'Depth_to_Groundwater_log', ax = ax[1,0])
sns.distplot(df.Depth_to_Groundwater_log, ax = ax[1,1])
plt.tight_layout()
plt.show()

ํ๊ท ๊ณผ ๋ถ์ฐ์ด ์ข ๋ ๋์นญ์ ์ด๋ฃจ๋ฉฐ ์ข ๋ชจ์๊ณผ ๊ฐ๊น์์ง ๊ฒ์ ํ์ธํ ์ ์๋ค.
# 1์ฐจ ์ฐจ๋ถ
ts_diff = np.diff(df.Depth_to_Groundwater)
df['Depth_to_Groundwater_df_1']= np.append([0], ts_diff) #์ฐจ๋ถ์ผ๋ก ์ญ์ ๋ ์ฒซ ํ ๋ถ์ฌ์ฃผ๊ธฐ
# 2์ฐจ ์ฐจ๋ถ
ts_diff = np.diff(df.Depth_to_Groundwater_df_1)
df['Depth_to_Groundwater_df_2'] = np.append([0], ts_diff)
# ์ฐจ๋ถํ ๋ฐ์ดํฐ ์๊ฐํ
f, ax = plt.subplots(nrows = 2, ncols = 1, figsize = (15,6))
visualize_adfuller_results(df.Depth_to_Groundwater_df_1,
'Depth_to_Groundwater_df_1', ax[0])
visualize_adfuller_results(df.Depth_to_Groundwater_df_2,
'Depth_to_Groundwater_df_2', ax[1])
plt.tight_layout()
plt.show()

2์ฐจ ์ฐจ๋ถํ ๋ฐ์ดํฐ์ ๋ถํฌ๊ฐ 1์ฐจ ์ฐจ๋ถํ ๋ฐ์ดํฐ๋ณด๋ค ์ผ์ ํ ๊ฒ์ ํ์ธํ ์ ์๋ค.
# 2์ฐจ ์ฐจ๋ถ acf, pacf ํ์ธ
plot_acf(df.Depth_to_Groundwater_df_2)
plt.show()
plot_pacf(df.Depth_to_Groundwater_df_2)
plt.show()


ACF๋ ์์ฐจ 2๋ถํฐ ์ ๋จ๋ฉด ์์ ๊ฐ์ด ๋ค์ด์ค๊ณ PACF๋ ์์ฐจ 4๋ถํฐ ์ ๋ง๋ฉด ์์ ๋ค์ด์ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๋ฐ๋ผ์, p๋ 3 q๋ 1๋ก ์ค์ ํ์๋ค
train_df = df[['Date', 'Depth_to_Groundwater_df_2']]
train_df.set_index('Date', inplace = True)
train = train_df.loc['2009-01-01' : '2019-11-28']
test = train_df.loc['2019-12-05':'2020-06-25']
model = ARIMA(train['Depth_to_Groundwater_df_2'], order = (3,2,1))
model_fit = model.fit()
print(model_fit.summary())

AIC๊ฐ -507.6์ด ๋์๋๋ฐ AIC๋ 0์ ๊ฐ๊น์ธ์๋ก ์ฑ๋ฅ์ด ์ข๊ธฐ ๋๋ฌธ์ ๊ทธ๋ค์ง ์ข์ ๊ฒฐ๊ณผ๋ ์๋ ๊ฒ ๊ฐ๋ค
# ๋ค์ 30๊ฐ์ ๋ฐ์ดํฐ ์์ธก
pred = model_fit.forecast(steps = 30)
pred = pd.Series(pred, index = test.index)
fig, ax = plt.subplots(figsize = (15,5))
sns.lineplot(x = 'Date', y = 'Depth_to_Groundwater', data = train)
pred.plot(ax = ax, color = 'red', label = 'Predicted', legend = True)
test.plot(ax = ax, color = 'blue', legend = True)

์์ธก ๊ฒฐ๊ณผ๋ฅผ ์๊ฐํํ ๊ฒฐ๊ณผ, ์์๋๋ก ๋ณ๋ก ์ข์ง ์๋ค
endog_variable = 'Depth_to_Groundwater'
train_y = train[endog_variable]
# ํ๋ผ๋ฏธํฐ ์ต์ ํ
p = range(0,4)
d = range(0,3)
q = range(0,4)
pdq = list(itertools.product(p,d,q))
aic = []
for i in pdq:
model = ARIMA(train_y, order = i)
model_fit = model.fit()
print(f'ARIMA : {i} >> AIC : {round(model_fit.aic, 2)}')
aic.append(abs(round(model_fit.aic,2)))
optimal = [(pdq[i],j) for i,j in enumerate(aic) if j == min(aic)]
optimal
AIC ๊ฐ์ด 0์ ๊ฐ์ฅ ๊ฐ๊น์ด p,d,q ์กฐํฉ์ ์ฐพ๋ ์ฝ๋๋ค.
p = 1, d = 0, q = 0์ ์กฐํฉ์ด AIC ๊ฒฐ๊ณผ๊ฐ ๊ฐ์ฅ 0์ ๊ฐ๊น๊ฒ ๋์๋ค.

Ref
https://www.youtube.com/watch?v=abOIK40QvDA&t=640s
https://www.kaggle.com/code/iamleonie/intro-to-time-series-forecasting
https://dacon.io/competitions/official/236200/codeshare/9519 ( ์ต์ ์ ํ๋ผ๋ฏธํฐ ์ค์ ์ฝ๋ ์ฐธ๊ณ )
๋น์ ๊ณต์์ ๋ฐ์ดํฐ ๋ถ์ ๋
ํ ๋ธ๋ก๊ทธ๋ก
์ธ์ ๋ ํผ๋๋ฐฑ ํ์์
๋๋ค!