[๊ฐ๋ ์ ๋ฆฌ] ์๊ณ์ด ์ธ๊ณผ๊ด๊ณ ๋ถ์: Granger Causality
์๋ณธ ๊ฒ์๊ธ: https://velog.io/@euisuk-chung/๊ฐ๋ ์ ๋ฆฌ-์๊ณ์ด-๋ถ์-์ธ๊ณผ๊ด๊ณ-๋ถ์
์๋ ํ์ธ์๐ ์ง๋ ๋ฒ ํฌ์คํธ์์ โ์ธ๊ณผ๊ด๊ณ์ ์๊ด๊ด๊ณ์ ๊ฐ๋ โ(๋งํฌ)์ ๋ํด์ ์ดํด๋ณด์๋๋ฐ์.
์ค๋์ ์๊ณ์ด ๋ถ์์ ํต์ฌ ๊ฐ๋ ์ค ํ๋์ธ โ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ(Granger causality)โ์ ๋ํด ์์๋ณด๊ณ , ์ด๋ฅผ ์ค์ ๋ฐ์ดํฐ์ ์ ์ฉํด๋ณด๋ ์๊ฐ์ ๊ฐ์ ธ๋ณด๊ฒ ์ต๋๋ค.
์ค์ต์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ Kaggle ๋ฐ์ดํฐ ์ค ํ๋์ธ Advertising Sales Dataset
(๋งํฌ)๋ก, ํด๋น ๋ฐ์ดํฐ๋ฅผ ํตํด ๊ด๊ณ ์์ฐ์ด ๋งค์ถ์ ์ด๋ค ์ํฅ์ ๋ฏธ์น๋์ง ํ์ธํด๋ณด์ค ์ ์์ ๊ฒ๋๋คโญ
-
์ธ๊ณผ๊ด๊ณ vs ์๊ด๊ด๊ณ
๋จผ์ ๋ณต์ต ์ฐจ์์์ ๊ฐ๋จํ๊ฒ ์ธ๊ณผ๊ด๊ณ์ ์๊ด๊ด๊ณ์ ์ฐจ์ด๋ถํฐ ์์๋ด ์๋ค.
์ธ๊ณผ๊ด๊ณ (Causal Relationship)
์ ์
: ํ ์ฌ๊ฑด์ด ๋ค๋ฅธ ์ฌ๊ฑด์ ์ง์ ์ ์ผ๋ก ์ผ๊ธฐํ๋ ๊ด๊ณ์
: ํก์ฐ์ด ํ์ ๋ฐ๋ณ๋ฅ ์ ์ฆ๊ฐ์ํด
์๊ด๊ด๊ณ (Correlation)
์ ์
: ๋ ๋ณ์ ๊ฐ์ ์ ํ์ ๊ด๋ จ์ฑ์ ์ ๋์
: ์์ด์คํฌ๋ฆผ ํ๋งค๋๊ณผ ๋ฒ์ฃ์จ์ด ํจ๊ป ์ฆ๊ฐํ๋ ๊ฒฝํฅ (์ค์ ์์ธ์ ๋์ด ๋ ์จ์ผ ์ ์์)
์ฐจ์ด์
๋ฐฉํฅ์ฑ
: ์ธ๊ณผ๊ด๊ณ๋ ๋ฐฉํฅ์ด ์์ง๋ง, ์๊ด๊ด๊ณ๋ ๋ฐฉํฅ์ฑ์ด ์์ต๋๋ค.์์ธ๊ณผ ๊ฒฐ๊ณผ
: ์ธ๊ณผ๊ด๊ณ๋ ์์ธ๊ณผ ๊ฒฐ๊ณผ๋ฅผ ๋ช ํํ ๊ตฌ๋ถํ์ง๋ง, ์๊ด๊ด๊ณ๋ ๊ทธ๋ ์ง ์์ต๋๋ค.
-
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ(Granger causality)
๋ 1969๋
ํด๋ผ์ด๋ธ ๊ทธ๋์ ๊ฐ ์ ์ํ ๊ฐ๋
์ผ๋ก, ์๊ณ์ด ๋ฐ์ดํฐ์์์ ์์ธก ๊ฐ๋ฅ์ฑ์ ๊ธฐ๋ฐ์ผ๋ก ํ ์ธ๊ณผ๊ด๊ณ๋ฅผ ์๋ฏธํฉ๋๋ค.
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ์ ์ ์
(Def) X์ ๊ณผ๊ฑฐ ์ ๋ณด๊ฐ Y์ ๋ฏธ๋ ๊ฐ์ ์์ธกํ๋ ๋ฐ ํต๊ณ์ ์ผ๋ก ์ ์๋ฏธํ ๋์์ ์ค๋ค๋ฉด, โX๋ Y๋ฅผ ๊ทธ๋์ ์ธ๊ณผํ๋คโ๊ณ ๋งํฉ๋๋ค.
๐ฏ ์ด๋ ์ํ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ํํํ ์ ์์ต๋๋ค:
P(Y(t+1)โฃY(t),Y(tโ1),โฆ,X(t),X(tโ1),โฆ)โ P(Y(t+1)โฃY(t),Y(tโ1),โฆ)P(Y(t+1) | Y(t), Y(t-1), โฆ, X(t), X(t-1), โฆ) โ P(Y(t+1) | Y(t), Y(t-1), โฆ)P(Y(t+1)โฃY(t),Y(tโ1),โฆ,X(t),X(tโ1),โฆ)๎ โ=P(Y(t+1)โฃY(t),Y(tโ1),โฆ) |
์ด๋ PPP๋ ์กฐ๊ฑด๋ถ ํ๋ฅ ์ ๋ํ๋ ๋๋ค.
-
์ข๋ณ P(Y(t+1) Y(t), Y(t-1), ...
,X(t), X(t-1), ...
):- Y์ ๋ฏธ๋ ๊ฐ Y(t+1)์ ์์ธกํ ๋,
Y์ ๊ณผ๊ฑฐ ๊ฐ๋ค(Y(t), Y(t-1), ...)
๊ณผX์ ๊ณผ๊ฑฐ ๊ฐ๋ค(X(t), X(t-1), ...)
์ ๋ชจ๋ ์ฌ์ฉํ ์กฐ๊ฑด๋ถ ํ๋ฅ ์ ๋ํ๋ ๋๋ค.
- Y์ ๋ฏธ๋ ๊ฐ Y(t+1)์ ์์ธกํ ๋,
-
์ฐ๋ณ P(Y(t+1) Y(t), Y(t-1), ...
):- Y์ ๋ฏธ๋ ๊ฐ Y(t+1)์ ์์ธกํ ๋,
Y์ ๊ณผ๊ฑฐ ๊ฐ๋ค(Y(t), Y(t-1), ...)
๋ง์ ์ฌ์ฉํ ์กฐ๊ฑด๋ถ ํ๋ฅ ์ ๋ํ๋ ๋๋ค.
- Y์ ๋ฏธ๋ ๊ฐ Y(t+1)์ ์์ธกํ ๋,
-
๋ถ๋ฑํธ (โ ):
- ๋ ์กฐ๊ฑด๋ถ ํ๋ฅ ์ด ์๋ก ๋ค๋ฅด๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๐ก ์ ์์์ ์๋ฏธ:
- ๋ง์ฝ X๊ฐ Y๋ฅผ ๊ทธ๋์ ์ธ๊ณผํ๋ค๋ฉด, X์ ๊ณผ๊ฑฐ ๊ฐ๋ค์ ํฌํจํ์ฌ ์์ธกํ Y์ ๋ฏธ๋ ๊ฐ(์ข๋ณ)์ด Y์ ๊ณผ๊ฑฐ ๊ฐ๋ค๋ง์ผ๋ก ์์ธกํ ๊ฒฝ์ฐ(์ฐ๋ณ)์ ๋ค๋ฅผ ๊ฒ์ ๋๋ค.
- ์ฆ, X์ ์ ๋ณด๊ฐ Y์ ์์ธก์ ์ ์๋ฏธํ ์ํฅ์ ์ค๋ค๋ ๊ฒ์ ๋ํ๋ ๋๋ค.
๐ก ์ค์ ์ ์ฉ:
- ์ด ๊ฐ๋ ์ ํต๊ณ์ ์ผ๋ก ๊ฒ์ ํ๊ธฐ ์ํด, ๋ณดํต ์ ํ ํ๊ท ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ๋ ๊ฒฝ์ฐ(X ํฌํจ vs X ๋ฏธํฌํจ)์ ์์ธก ์ค์ฐจ๋ฅผ ๋น๊ตํฉ๋๋ค.
- F-๊ฒ์ ์ด๋ ๋ค๋ฅธ ํต๊ณ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ๋ ๋ชจ๋ธ ๊ฐ์ ์ฐจ์ด๊ฐ ์ ์๋ฏธํ์ง ํ๋จํฉ๋๋ค.
โ ๏ธ ์ฃผ์์ :
- ์ด๋ ์์ธก ๊ฐ๋ฅ์ฑ์ ๊ธฐ๋ฐํ ์ธ๊ณผ๊ด๊ณ์ด๋ฉฐ, ์ง์ ํ ์ธ๊ณผ๊ด๊ณ๋ฅผ ์๋ฒฝํ ์ฆ๋ช ํ์ง๋ ์์ต๋๋ค.
- ์จ๊ฒจ์ง ๋ณ์๋ ๊ณตํต ์์ธ ๋ฑ์ ๊ฐ๋ฅ์ฑ์ ํญ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค.
์ด์ฒ๋ผ ์ ์์์ ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ์ ๊ธฐ๋ณธ ์์ด๋์ด๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ํํํ๊ณ ์์ผ๋ฉฐ, ์๊ณ์ด ๋ฐ์ดํฐ ๋ถ์์์ ๋ณ์ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ดํดํ๋ ๋ฐ ์ค์ํ ๋๊ตฌ๋ก ์ฌ์ฉ๋ฉ๋๋ค.
-
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ vs ์ธ๊ณผ๊ด๊ณ
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ์ ์ผ๋ฐ์ ์ธ ์ธ๊ณผ๊ด๊ณ๋ ๋ค์๊ณผ ๊ฐ์ ์ฐจ์ด๊ฐ ์กด์ฌํฉ๋๋ค:
-
์ ์:
- ์ธ๊ณผ๊ด๊ณ: A๊ฐ B์
์ง์ ์ ์ธ ์์ธ
์ด ๋จ - ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ: A์ ๊ณผ๊ฑฐ ์ ๋ณด๊ฐ B์ ๋ฏธ๋๋ฅผ ์์ธกํ๋ ๋ฐ ๋์์ด ๋จ
- ์ธ๊ณผ๊ด๊ณ: A๊ฐ B์
-
๊ธฐ๋ฐ:
- ์ธ๊ณผ๊ด๊ณ: ๋ ผ๋ฆฌ์ , ์คํ์ ์ฆ๊ฑฐ์ ๊ธฐ๋ฐ
- ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ: ํต๊ณ์ ์์ธก๋ ฅ์ ๊ธฐ๋ฐ
-
ํด์:
- ์ธ๊ณผ๊ด๊ณ: โA๊ฐ B๋ฅผ ์ผ๊ธฐํ๋คโ
- ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ: โA๊ฐ B๋ฅผ ์์ธกํ๋ ๋ฐ ๋์์ด ๋๋คโ
-
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๋ชจํ
๋ชจํ์ ์ ์
์๊ฐ ์ ํ๊ด๊ณ
: ๊ณผ๊ฑฐ์ ์ฌ๊ฑด์ ํ์ฌ์ ์ฌ๊ฑด์ ์ ๋ฐํ ์ ์์ง๋ง, ๋ฏธ๋์ ์ฌ๊ฑด์ ํ์ฌ์ ์ฌ๊ฑด์ ์ ๋ฐํ ์ ์์ต๋๋ค.์ ์์ฑ
: ๋ฐ์ดํฐ๋ ์ ์์ฑ(stationary)์ ๊ฐ์ ธ์ผ ํฉ๋๋ค. ์ฆ, ํ๊ท ๊ณผ ๋ถ์ฐ์ด ์๊ฐ์ ๋ฐ๋ผ ์ผ์ ํด์ผ ํฉ๋๋ค.์ ๋ ฅ์์ฐจ
: ์์๋๋ ์์ฐจ๋งํผ์ ๊ณผ๊ฑฐ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ์ ๋ ฅ๋ณ์๋ก ์ฌ์ฉํด์ผ ํฉ๋๋ค.์ต์ข ์์ฐจ
: ์ ์ ํ ์์ฐจ๋ฅผ ์ ํํด์ผ ํฉ๋๋ค. ๋ณดํต ์ฐ ํ์ฐ ๋น๋์ 2~3๋ฐฐ๊น์ง ๊ณ ๋ คํฉ๋๋ค.
๋ชจํ์ ๊ฒ์
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๊ฒ์ ์ ๋ค์๊ณผ ๊ฐ์ ๋จ๊ณ๋ก ์ด๋ฃจ์ด์ง๋๋ค:
- ๊ท๋ฌด๊ฐ์ค ์ค์ : โX๋ Y๋ฅผ ๊ทธ๋์ ์ธ๊ณผํ์ง ์๋๋คโ
- ์ ํ ๋ชจ๋ธ๊ณผ ๋น์ ํ ๋ชจ๋ธ ๊ตฌ์ถ:
- ์ ํ ๋ชจ๋ธ: Y(t) = ฮฑ + ฮฒ1Y(t-1) + ฮฒ2Y(t-2) + โฆ + ฮฒp*Y(t-p) + ฮต
- ๋น์ ํ ๋ชจ๋ธ: Y(t) = ฮฑ + ฮฒ1Y(t-1) + โฆ + ฮฒpY(t-p) + ฮณ1X(t-1) + โฆ + ฮณpX(t-p) + ฮต
- F-ํต๊ณ๋ ๊ณ์ฐ
- p-value ํ์ธ ๋ฐ ๊ฒฐ๋ก ๋์ถ
ํ์ด์ฌ ์ฝ๋ ์์
statsmodels ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๊ฒ์ ์ ์ํํ ์ ์์ต๋๋ค:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import grangercausalitytests
# ์์ ๋ฐ์ดํฐ ์์ฑ
np.random.seed(1)
x = np.random.randn(1000)
y = np.random.randn(1000)
y[1:] += 0.5 * x[:-1] # X๊ฐ Y๋ฅผ ๊ทธ๋์ ์ธ๊ณผํ๋๋ก ์ค์
data = pd.DataFrame({'X': x, 'Y': y})
# ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๊ฒ์
result = grangercausalitytests(data[['Y', 'X']], maxlag=5)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
for lag, values in result.items():
print(f"Lag {lag}:")
print(f" F-statistic: {values[0]['ssr_ftest'][0]}")
print(f" p-value: {values[0]['ssr_ftest'][1]}")
-
๋ชจํ์ ์์ฉ
VAR์ ํ์ฉํ ์์ฉ
VAR์ด๋?
- VAR(Vector Autoregression)์
์ฌ๋ฌ ๋ณ์์ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๋์์ ๋ชจ๋ธ๋งํ๋ ๋ฐฉ๋ฒ
์ ๋๋ค. - ๊ฐ ๋ณ์๊ฐ ์์ ์ ๊ณผ๊ฑฐ ๊ฐ๊ณผ ๋ค๋ฅธ ๋ณ์๋ค์ ๊ณผ๊ฑฐ ๊ฐ์ ์ํด ์ํฅ์ ๋ฐ๋๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
VAR(p) ๋ชจ๋ธ (p์ฐจ ๋ฒกํฐ ์๊ธฐํ๊ท ๋ชจ๋ธ):
Yt=c+A1Ytโ1+A2Ytโ2+โฆ+ApYtโp+ฯตtY_t = c + A_1Y_{t-1} + A_2Y_{t-2} + โฆ + A_pY_{t-p} + \epsilon_tYtโ=c+A1โYtโ1โ+A2โYtโ2โ+โฆ+ApโYtโpโ+ฯตtโ
์ฌ๊ธฐ์:
- YtY_tYtโ ๋ ์์ t์์์ k์ฐจ์ ์๊ณ์ด ๋ฒกํฐ
- ccc ๋ k์ฐจ์ ์์ ๋ฒกํฐ
- AiA_iAiโ ๋ k ร k ๊ณ์ ํ๋ ฌ
- ฯตt\epsilon_tฯตtโ ๋ k์ฐจ์ ๋ฐฑ์ ์ก์ ๋ฒกํฐ
VAR์ ์ด๋ป๊ฒ ํ์ฉํด์ ์์ฉํ๋๊ฐ?
- ๋ณ์ ๊ฐ ๋์ ๊ด๊ณ ๋ถ์: VAR ๋ชจ๋ธ์ ์ฌ๋ฌ ๋ณ์ ๊ฐ์ ์ํธ์์ฉ์ ๋์์ ๊ณ ๋ คํ ์ ์์ต๋๋ค.
- ์ถฉ๊ฒฉ๋ฐ์ํจ์ ๋ถ์: ํ ๋ณ์์ ๋ณํ๊ฐ ๋ค๋ฅธ ๋ณ์์ ๋ฏธ์น๋ ์ํฅ์ ์๊ฐ์ ๋ฐ๋ผ ์ถ์ ํ ์ ์์ต๋๋ค.
- ์์ธก: ์ฌ๋ฌ ๋ณ์์ ๋ฏธ๋ ๊ฐ์ ๋์์ ์์ธกํ ์ ์์ต๋๋ค.
ํ์ด์ฌ ์ฝ๋ ์์:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from statsmodels.tsa.api import VAR
from statsmodels.tsa.stattools import adfuller
# ๋ฐ์ดํฐ ์ ์ํ (ํ์ํ ๊ฒฝ์ฐ)
def difference(data):
return data.diff().dropna()
# ADF ํ
์คํธ๋ก ์ ์์ฑ ํ์ธ
def adf_test(series):
result = adfuller(series)
print(f'ADF Statistic: {result[0]}')
print(f'p-value: {result[1]}')
# VAR ๋ชจ๋ธ ์ ์ฉ
model = VAR(data)
results = model.fit(maxlags=15, ic='aic')
# ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๊ฒ์
granger_results = results.test_causality('Y', 'X', kind='f')
print(granger_results.summary())
ARIMA๋ฅผ ํ์ฉํ ์์ฉ
ARIMA๋?
- ARIMA(AutoRegressive Integrated Moving Average)๋
๋จ์ผ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ธ๋ง
ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. - ์๊ธฐํ๊ท(AR), ์ฐจ๋ถ(I), ์ด๋ํ๊ท (MA) ์์๋ฅผ ๊ฒฐํฉํ์ฌ ๋ณต์กํ ์๊ณ์ด ํจํด์ ํฌ์ฐฉํฉ๋๋ค.
ARIMA(p,d,q) ๋ชจ๋ธ:
ฯ(B)(1โB)dXt=ฮธ(B)ฯตt\phi(B)(1-B)^d X_t = \theta(B)\epsilon_tฯ(B)(1โB)dXtโ=ฮธ(B)ฯตtโ
์ฌ๊ธฐ์:
- BBB ๋ ํํ ์ฐ์ฐ์ (BXt=Xtโ1BX_t = X_{t-1}BXtโ=Xtโ1โ)
- ddd ๋ ์ฐจ๋ถ ์ฐจ์
- ฯ(B)=1โฯ1Bโฯ2B2โโฆโฯpBp\phi(B) = 1 - \phi_1B - \phi_2B^2 - โฆ - \phi_pB^pฯ(B)=1โฯ1โBโฯ2โB2โโฆโฯpโBp (AR ๋คํญ์)
- ฮธ(B)=1+ฮธ1B+ฮธ2B2+โฆ+ฮธqBq\theta(B) = 1 + \theta_1B + \theta_2B^2 + โฆ + \theta_qB^qฮธ(B)=1+ฮธ1โB+ฮธ2โB2+โฆ+ฮธqโBq (MA ๋คํญ์)
- ฯตt\epsilon_tฯตtโ ๋ ๋ฐฑ์ ์ก์ ๊ณผ์
ARIMA๋ฅผ ์ด๋ป๊ฒ ํ์ฉํด์ ์์ฉํ๋๊ฐ?
- ๋จ๋ณ๋ ์๊ณ์ด ๋ถ์: ๊ฐ ๋ณ์์ ์์ฒด์ ์ธ ์๊ณ์ด ํน์ฑ์ ์์ธํ ๋ถ์ํ ์ ์์ต๋๋ค.
- ์์ธก: ๋จ์ผ ๋ณ์์ ๋ฏธ๋ ๊ฐ์ ์์ธกํ ์ ์์ต๋๋ค.
- ์ด์์น ํ์ง: ๋ชจ๋ธ์ ์์ธก๊ฐ๊ณผ ์ค์ ๊ฐ์ ์ฐจ์ด๋ฅผ ํตํด ์ด์์น๋ฅผ ํ์งํ ์ ์์ต๋๋ค.
ํ์ด์ฌ ์ฝ๋ ์์:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from statsmodels.tsa.arima.model import ARIMA
import matplotlib.pyplot as plt
# ARIMA ๋ชจ๋ธ ์ ์ฉ
model = ARIMA(data['Y'], order=(1,1,1))
results = model.fit()
# ์์ธก
forecast = results.forecast(steps=10)
# ๊ฒฐ๊ณผ ์๊ฐํ
plt.figure(figsize=(12,6))
plt.plot(data['Y'], label='Observed')
plt.plot(forecast, label='Forecast')
plt.legend()
plt.show()
๋ชจํ์ ํด์
๊ฒ์ ๊ฒฐ๊ณผ ํด์:
-
X๊ฐ Y์ ์ธ๊ณผ์ํฅ์ ์ฃผ๊ณ , Y๋ X์ ์ธ๊ณผ์ํฅ์ ์ฃผ์ง ์๋ ๊ฒฝ์ฐ
: X๊ฐ Y์ ์ธ๊ณผ์์ธ์ผ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. -
Y๊ฐ X์ ์ธ๊ณผ์ํฅ์ ์ฃผ๊ณ , X๋ Y์ ์ธ๊ณผ์ํฅ์ ์ฃผ์ง ์๋ ๊ฒฝ์ฐ
: Y๊ฐ X์ ์ธ๊ณผ์์ธ์ผ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. -
X์ Y๊ฐ ์๋ก ์ธ๊ณผ์ํฅ์ ์ฃผ๋ ๊ฒฝ์ฐ
: ์ 3์ ์ธ๋ถ๋ณ์๊ฐ ์ํฅ์ ์คฌ์ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค. -
X์ Y๊ฐ ์๋ก ์ธ๊ณผ์ํฅ์ ์ฃผ์ง ์๋ ๊ฒฝ์ฐ
: ๋ ๋ณ์ ๊ฐ ์ธ๊ณผ๊ด๊ณ๊ฐ ์๊ฑฐ๋, ๋ค๋ฅธ ํํ์ ๊ด๊ณ์ผ ์ ์์ต๋๋ค. -
์ค์ ๋ฐ์ดํฐ ๋ถ์์์
์ด์ ์ค์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ, VAR, ARIMA ๋ชจ๋ธ์ ์ ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
๋ฐ์ดํฐ ์๊ฐ
์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ ๋ฐ์ดํฐ์ ์ TV, ๋ผ๋์ค, ์ ๋ฌธ ๊ด๊ณ ์์ฐ๊ณผ ๊ทธ์ ๋ฐ๋ฅธ ๋งค์ถ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๊ณ ์์ต๋๋ค. ์ด 200๊ฐ์ ๊ด์ธก์น๊ฐ ์์ผ๋ฉฐ, ๊ฐ ๊ด์ธก์น๋ ๋ค์ ๋ณ์๋ค๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค:
- TV Ad Budget ($): TV ๊ด๊ณ ์์ฐ
- Radio Ad Budget ($): ๋ผ๋์ค ๊ด๊ณ ์์ฐ
- Newspaper Ad Budget ($): ์ ๋ฌธ ๊ด๊ณ ์์ฐ
- Sales ($): ๋งค์ถ
๋ฐ์ดํฐ ์ค๋น ๋ฐ ๋ถ์
๋จผ์ , ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ํฌํธํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํฉ๋๋ค.
ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ก๋
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ก๋
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')
from statsmodels.tsa.api import VAR
import statsmodels.tsa.api as smt
from statsmodels.tsa.stattools import grangercausalitytests
from statsmodels.tsa.stattools import adfuller
from statsmodels.tsa.arima.model import ARIMA
๋ฐ์ดํฐ ๋ก๋
1
2
3
4
5
6
# ๋ฐ์ดํฐ ๋ก๋ (๋ฐ์ดํฐ๋ ์ง์ ๋ค์ด ๋ฐ์์ฃผ์ธ์)
# https://www.kaggle.com/datasets/yasserh/advertising-sales-dataset
df = pd.read_csv("./Data/Advertising Budget and Sales.csv")
print(df.shape)
df.head()
์ ๊ทํ ๋ฐ ์๊ฐํ
1
2
3
4
5
6
7
variables = ['TV Ad Budget ($)', 'Radio Ad Budget ($)', 'Newspaper Ad Budget ($)', 'Sales ($)']
# ๊ฐ ๊ฐ์ ์ฒซ ๊ฐ์ผ๋ก ์ ๊ทํ
df['Sales ($)'] = df['Sales ($)'] / df['Sales ($)'].iloc[0]
df['TV Ad Budget ($)'] = df['TV Ad Budget ($)'] / df['TV Ad Budget ($)'].iloc[0]
df['Radio Ad Budget ($)'] = df['Radio Ad Budget ($)'] / df['Radio Ad Budget ($)'].iloc[0]
df['Newspaper Ad Budget ($)'] = df['Newspaper Ad Budget ($)'] / df['Newspaper Ad Budget ($)'].iloc[0]
โ ์ด? ์ ๊ฐ ์๋ ์ ๊ทํ๋ ์กฐ๊ธ ๋ค๋ฅธ๋ฐ์? => ๋ง์ต๋๋ค
- ์ด๋
์๋์ ๋ณํ ์ ๊ทํ(๋๋ ๊ธฐ์ค์ ์ ๊ทํ)
๋ผ๊ณ ๋ถ๋ฆฌ๋ฉฐ, ์ผ๋ฐ์ ์ธ ์ ๊ทํ ๋ฐฉ๋ฒ๊ณผ๋ ๋ค๋ฅธ ๋ชฉ์ ๊ณผ ํน์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค.- ์ด ๋ฐฉ๋ฒ์ ์ฃผ์ ํน์ง๊ณผ ์ผ๋ฐ ์ ๊ทํ์์ ์ฐจ์ด์ ์ ์ค๋ช ๋๋ฆฌ๊ฒ ์ต๋๋ค:
๐ถ ์๋์ ๋ณํ ์ ๊ทํ์ ๋ชฉ์
์๊ณ์ด ๋ฐ์ดํฐ ๋ถ์
: ์๊ฐ์ ๋ฐ๋ฅธ ๋ณํ๋ฅผ ๋ ์ฝ๊ฒ ํ์ ํ ์ ์๊ฒ ํฉ๋๋ค. ์ด๊ธฐ ๊ฐ ๋๋น ์ฆ๊ฐ ๋๋ ๊ฐ์๋ฅผ ์ง๊ด์ ์ผ๋ก ์ดํดํ ์ ์์ต๋๋ค.๋ณ์ ๊ฐ ์๋์ ๋ณํ ๋น๊ต
: ์๋ก ๋ค๋ฅธ ๋จ์๋ ์ค์ผ์ผ์ ๊ฐ์ง ๋ณ์๋ค์ ๋ณํ๋ฅผ ๋น๊ตํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.๊ทธ๋์ ์ธ๊ณผ์ฑ ๋ถ์์ ์ ์ฉ
: ๋ณ์๋ค ๊ฐ์ ์๋์ ์ธ ๋ณํ๋ฅผ ๋น๊ตํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด ์ธ๊ณผ๊ด๊ณ ๋ถ์์ ๋์์ ์ค๋๋ค.
๐ท ์ผ๋ฐ ์ ๊ทํ์์ ์ฐจ์ด์
๋ฐ์ดํฐ ๋ณํ ๊ด์
:
์๋์ ๋ณํ ์ ๊ทํ: ์ฒซ ๋ฒ์งธ ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๋ชจ๋ ๊ฐ์ ๋๋๋๋ค.
์ผ๋ฐ ์ ๊ทํ(์: Min-Max): ์ ์ฒด ๋ฐ์ดํฐ ๋ฒ์๋ฅผ ํน์ ๋ฒ์(์: 0-1)๋ก ๋ณํํฉ๋๋ค.
๊ฒฐ๊ณผ ํด์ ๊ด์
:
์๋์ ๋ณํ ์ ๊ทํ: ์ด๊ธฐ ๊ฐ ๋๋น ๋ณํ์จ์ ๋ํ๋ ๋๋ค.
์ผ๋ฐ ์ ๊ทํ: ์ ์ฒด ๋ฐ์ดํฐ ๋ฒ์ ๋ด์์์ ์๋์ ์์น๋ฅผ ๋ํ๋ ๋๋ค.
๋ฐ์ดํฐ ๋ถํฌ ๊ด์
:
์๋์ ๋ณํ ์ ๊ทํ: ์๋ ๋ฐ์ดํฐ์ ์๋์ ๋ณํ ํจํด์ ์ ์งํฉ๋๋ค.
์ผ๋ฐ ์ ๊ทํ: ๋ฐ์ดํฐ์ ์ ์ฒด์ ์ธ ๋ถํฌ๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
1
2
df.plot(figsize=(15,3))
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# matplotlib์ ๊ธฐ๋ณธ ์์ ์์ ์ฌ์ฉ
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
# ๊ฐ ๋ณ์๋ฅผ ๋ณ๋์ ์๋ธํ๋กฏ์ผ๋ก ๊ทธ๋ฆฌ๊ธฐ
fig, axes = plt.subplots(len(variables), 1, figsize=(15, 3*len(variables)))
fig.suptitle('Normalized Values Over Time (Subplots)', fontsize=16)
for i, var in enumerate(variables):
axes[i].plot(df.index, df[var], label=var, color=colors[i])
axes[i].set_title(var)
axes[i].set_xlabel('Index')
axes[i].set_ylabel('Normalized Value')
axes[i].legend()
axes[i].grid(True)
# y์ถ ๋ฒ์ ์ค์ (0๋ถํฐ ๋ฐ์ดํฐ์ ์ต๋๊ฐ๊น์ง)
axes[i].set_ylim(0, df[var].max() * 1.1) # ์ต๋๊ฐ์ 10% ์ฌ์ ์ถ๊ฐ
plt.tight_layout()
plt.show()
์ ์์ฑ ํ์ธ
๋ณธ๊ฒฉ์ ์ผ๋ก ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๊ฒ์
์ ์ํํ๊ธฐ์ ์์ ๋ฐ์ดํฐ๊ฐ ์ ์์ฑ(stationary)์ ๊ฐ์ง๋์ง ํ์ธ์ ํด์ผํฉ๋๋ค. ๊ทธ๋ ์ง ์๋ค๋ฉด ๋ณ๋๋ก ์ฐจ๋ถ์ ์ํํด์ฃผ์ด์ผ ํฉ๋๋ค.
(์์ ๊ฐ๋ ๋ด์ฉ ์ฐธ๊ณ )
- ์ ์์ฑ: ๋ฐ์ดํฐ๋ ์ ์์ฑ(stationary)์ ๊ฐ์ ธ์ผ ํฉ๋๋ค. ์ฆ, ํ๊ท ๊ณผ ๋ถ์ฐ์ด ์๊ฐ์ ๋ฐ๋ผ ์ผ์ ํด์ผ ํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from statsmodels.tsa.stattools import adfuller, grangercausalitytests
# ADF ํ
์คํธ ํจ์ ์ ์
def adf_test(timeseries):
result = adfuller(timeseries, autolag='AIC')
return pd.Series({'Test Statistic': result[0], 'p-value': result[1], 'Critical Values': result[4]})
adf_results = {var: adf_test(df[var]) for var in variables}
# ADF ํ
์คํธ ๊ฒฐ๊ณผ ์ถ๋ ฅ ๋ฐ ํด์
for var, result in adf_results.items():
print(f"\nADF Test Results for {var}:")
print(result)
if result['p-value'] <= 0.05:
print(f"ํด์: {var}๋ 5% ์ ์์์ค์์ ์ ์ ์๊ณ์ด์
๋๋ค.")
else:
print(f"ํด์: {var}๋ 5% ์ ์์์ค์์ ๋น์ ์ ์๊ณ์ด์
๋๋ค.")
์๋ ADF ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด, ๋ชจ๋ ๋ณ์๋ค์ด 5% ์ ์์์ค์์ ์ ์ ์๊ณ์ด๋ก ๋ํ๋ฌ์ต๋๋ค. ์ด๋ ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๋ถ์์ ์ํด ๋ณ๋์ ์ฐจ๋ถ์ด ํ์ํ์ง ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
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
26
27
28
# ๊ฒฐ๊ณผ
ADF Test Results for TV Ad Budget ($):
Test Statistic -14.158141
p-value 0.0
Critical Values {'1%': -3.4636447617687436, '5%': -2.876176117...
dtype: object
ํด์: TV Ad Budget ($)๋ 5% ์ ์์์ค์์ ์ ์ ์๊ณ์ด์
๋๋ค.
ADF Test Results for Radio Ad Budget ($):
Test Statistic -14.129897
p-value 0.0
Critical Values {'1%': -3.4636447617687436, '5%': -2.876176117...
dtype: object
ํด์: Radio Ad Budget ($)๋ 5% ์ ์์์ค์์ ์ ์ ์๊ณ์ด์
๋๋ค.
ADF Test Results for Newspaper Ad Budget ($):
Test Statistic -13.344195
p-value 0.0
Critical Values {'1%': -3.4636447617687436, '5%': -2.876176117...
dtype: object
ํด์: Newspaper Ad Budget ($)๋ 5% ์ ์์์ค์์ ์ ์ ์๊ณ์ด์
๋๋ค.
ADF Test Results for Sales ($):
Test Statistic -13.990162
p-value 0.0
Critical Values {'1%': -3.4636447617687436, '5%': -2.876176117...
dtype: object
ํด์: Sales ($)๋ 5% ์ ์์์ค์์ ์ ์ ์๊ณ์ด์
๋๋ค.
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๊ฒ์
๊ทธ๋ ๋ค๋ฉด ์ด์ ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๊ฒ์ ์ ํตํด ๊ฐ ๊ด๊ณ ์ฑ๋์ ์์ฐ์ด ๋งค์ถ์ ์ํฅ์ ๋ฏธ์น๋์ง ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import grangercausalitytests
from statsmodels.tsa.api import VAR
from statsmodels.tools.eval_measures import aic, bic
def optimal_lag(data, max_lag):
model = VAR(data)
results = {}
for lag in range(1, max_lag + 1):
result = model.fit(lag)
results[lag] = result.aic
return min(results, key=results.get)
def granger_causality(data, variables, max_lag=12, alpha=0.05):
results = {}
for i in range(len(variables)):
for j in range(len(variables)):
if i != j:
pair = (variables[i], variables[j])
opt_lag = optimal_lag(data[[variables[i], variables[j]]], max_lag)
granger_result = grangercausalitytests(data[[variables[i], variables[j]]], maxlag=opt_lag, verbose=False)
p_values = [granger_result[lag][0]['ssr_ftest'][1] for lag in range(1, opt_lag+1)]
results[pair] = {
'optimal_lag': opt_lag,
'p_values': p_values,
'significant': any(p < alpha for p in p_values)
}
plt.figure(figsize=(10, 6))
plt.plot(range(1, opt_lag+1), p_values, marker='o')
plt.axhline(y=alpha, color='r', linestyle='--')
plt.title(f'Granger Causality: {variables[i]} -> {variables[j]}')
plt.xlabel('Lag')
plt.ylabel('p-value')
plt.show()
return results
# ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ ๋ถ์ ์ํ
results = granger_causality(df, variables)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
for pair, result in results.items():
print(f"\nGranger Causality: {pair[0]} -> {pair[1]}")
print(f"Optimal lag: {result['optimal_lag']}")
print(f"Significant: {result['significant']}")
print(f"p-values: {result['p_values']}")
๊ฒฐ๊ณผํด์
- ์ ์๋ฏธํ ๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ:
- TV Ad Budget(X) -> Radio Ad Budget (Y):
2 lag
์์ ์ ์๋ฏธํจ. - TV Ad Budget(X) -> Sales (Y):
2 lag
์์ ์ ์๋ฏธํจ.
- ๋ค๋ฅธ ๊ด๊ณ๋ค:
- ๋๋ถ๋ถ์ ๊ด๊ณ๊ฐ ํต๊ณ์ ์ผ๋ก ๋ฌด์๋ฏธํจ.
- ์ฃผ์ ์ธ์ฌ์ดํธ:
TV ๊ด๊ณ ์์ฐ
์ด๋ผ๋์ค ๊ด๊ณ ์์ฐ
๊ณผ๋งค์ถ
์ ์ํฅ์ ๋ฏธ์น๋ ๊ฒ์ผ๋ก ๋ณด์.
์ด์ ์ด๋ฅผ ํ์ฉํด์ Sales Forecasting์ ๊ตฌ์ถํด๋ณด๊ฒ ์ต๋๋ค.
- VAR ๋ชจ๋ธ(๋๋ ARIMA ๋ชจ๋ธ) ์ฌ์ฉ:
- TV Ad Budget๊ณผ Sales๋ฅผ ํฌํจํ VAR ๋ชจ๋ธ(๋๋ ARIMA ๋ชจ๋ธ) ๊ตฌ์ถ
- ์ต์ lag๋ 2๋ก ์ค์
- ํน์ฑ ์ ํ:
- TV Ad Budget(X)์ ๋ ๋ฆฝ๋ณ์, Sales(Y)๋ฅผ ์ข ์๋ณ์๋ก ๋ชจ๋ธ๋งํด๋ณด๊ฒ ์ต๋๋ค.
Train/Test Split
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.api import VAR
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_squared_error
from math import sqrt
# ๋ฐ์ดํฐ ๋ก๋
df = pd.read_csv("./Data/Advertising Budget and Sales.csv")
df = df[['TV Ad Budget ($)', 'Sales ($)']]
df['Sales ($)'] = df['Sales ($)'] / df['Sales ($)'].iloc[0]
df['TV Ad Budget ($)'] = df['TV Ad Budget ($)'] / df['TV Ad Budget ($)'].iloc[0]
df.columns = ['tv', 'sales'] # ๊ฐ๋จํ๊ฒ ์ด๋ฆ ๋ณ๊ฒฝ
# ๋ฐ์ดํฐ ๋ถํ (80% ํ๋ จ, 20% ํ
์คํธ)
train_size = int(len(df) * 0.8)
train, test = df[:train_size], df[train_size:]
# ๊ทธ๋ํ ์ค์
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), sharex=True)
fig.suptitle('Train and Test Data Visualization')
# TV Ad Budget ๊ทธ๋ํ
ax1.plot(df.index[:train_size], train['tv'], label='Train')
ax1.plot(df.index[train_size:], test['tv'], label='Test')
ax1.axvline(x=train_size, color='r', linestyle='--', label='Train/Test Split')
ax1.set_ylabel('TV Ad Budget ($)')
ax1.legend()
# Sales ๊ทธ๋ํ
ax2.plot(df.index[:train_size], train['sales'], label='Train')
ax2.plot(df.index[train_size:], test['sales'], label='Test')
ax2.axvline(x=train_size, color='r', linestyle='--', label='Train/Test Split')
ax2.set_ylabel('Sales ($)')
ax2.legend()
# x์ถ ๋ ์ด๋ธ ์ค์
ax2.set_xlabel('Time')
plt.tight_layout()
plt.show()
VAR (Vector Autoregression) ๋ชจ๋ธ
์ด์ VAR ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ๋ณ์๋ค ๊ฐ์ ๋์ ๊ด๊ณ๋ฅผ ๋ถ์ํด๋ณด๊ฒ ์ต๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# USING VAR
lag = 2
# VAR ๋ชจ๋ธ
model_var = VAR(train)
results_var = model_var.fit(lag)
# VAR ๋์ ์์ธก
forecast_var = []
forecast_input_var = train.values[-lag:]
for i in range(len(test)):
fc = results_var.forecast(forecast_input_var, steps=1)
forecast_var.append(fc[0])
# ์ค์ test ๋ฐ์ดํฐ์ ์ด์ lag ๊ฐ์ผ๋ก forecast_input_var ์
๋ฐ์ดํธ
if i + 1 < len(test):
forecast_input_var = np.vstack([forecast_input_var[1:], test.iloc[i].values])
forecast_var = np.array(forecast_var)
rmse_var_sales = sqrt(mean_squared_error(test['sales'], forecast_var[:, 1]))
๋น๊ต๋ฅผ ์ํด SALES๋ง ๊ฐ์ง๊ณ ํ์ต์ ํ ARIMA ๋ชจ๋ธ์ ํ์ต์์ผ๋ณด๊ฒ ์ต๋๋ค!
ARIMA (AutoRegressive Integrated Moving Average) ๋ชจ๋ธ
๋ง์ง๋ง์ผ๋ก, ๋งค์ถ ๋ฐ์ดํฐ์ ๋ํด ARIMA ๋ชจ๋ธ์ ์ ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
train_sales = train['sales']
test_sales = test['sales']
# ARIMA ๋ชจ๋ธ
model_arima = ARIMA(train_sales, order=(lag, 0, 0))
results_arima = model_arima.fit()
# ๋์ ์์ธก์ ์ํ ARIMA
forecast_arima_dynamic = []
history = train_sales.tolist()
for t in range(len(test_sales)):
model_arima_dynamic = ARIMA(history, order=(lag, 0, 0))
model_fit_dynamic = model_arima_dynamic.fit()
yhat = model_fit_dynamic.forecast(steps=1)[0]
forecast_arima_dynamic.append(yhat)
history.append(test_sales.iloc[t])
rmse_arima_sales_dynamic = sqrt(mean_squared_error(test_sales, forecast_arima_dynamic))
๋ชจ๋ธ ๋น๊ต
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
print("\nModel Comparison:")
print(f"VAR Model RMSE: {rmse_var_sales:.5f}")
print(f"VAR Model MSE: {mse_var_sales:.5f}")
print(f"VAR Model MAE: {mae_var_sales:.5f}")
print("-"*50)
print(f"ARIMA Model RMSE: {rmse_arima_sales_dynamic:.5f}")
print(f"ARIMA Model MSE: {mse_arima_sales_dynamic:.5f}")
print(f"ARIMA Model MAE: {mae_arima_sales_dynamic:.5f}")
# Model Comparison:
# VAR Model RMSE: 0.23431
# VAR Model MSE: 0.05490
# VAR Model MAE: 0.19481
# --------------------------------------------------
# ARIMA Model RMSE: 0.23493
# ARIMA Model MSE: 0.05519
# ARIMA Model MAE: 0.18524
1
2
3
4
5
6
7
8
9
10
11
12
# ์์ธก ๊ฒฐ๊ณผ ์๊ฐํ
plt.figure(figsize=(12, 6))
plt.plot(test.index, test.sales, label='Actual Sales', color='black')
plt.plot(test.index, test.tv, label='Actual TV', color='orange', linestyle = '--')
plt.plot(test.index, forecast_var[:, 1], label='VAR Sales Forecast', color='blue')
plt.plot(test.index, forecast_arima_dynamic, label='Dynamic ARIMA Sales Forecast', color='red')
plt.legend()
plt.xlabel('Time')
plt.ylabel('Sales ($)')
plt.title('Sales Forecast Comparison: VAR vs Dynamic ARIMA')
plt.show()
๋ถ์ ํด์
์ ๊ณต๋ ์ฑ๋ฅ ์งํ์ ์๊ฐ์ ๊ฒํ ๋ฅผ ์ข ํฉํด ๋ณผ ๋, ํน๋ณํ ์ด๋ ํ ๋ชจ๋ธ์ด ๋ ์ฐ์ํ๋ค๊ณ ๊ฒฐ๋ก ๋ด๋ฆฌ๊ธฐ๋ ์ด๋ ต์ต๋๋ค. ๋ ๋ชจ๋ธ ๋ชจ๋ ๋น์ทํ ์์ค์ ์์ธก ์ฑ๋ฅ์ ๋ณด์ด๊ธฐ ๋๋ฌธ์, ์ต์ข ๋ชจ๋ธ ์ ํ์ ๋ค์๊ณผ ๊ฐ์ ์ถ๊ฐ์ ์ธ ์์๋ฅผ ๊ณ ๋ คํด์ผ ํฉ๋๋ค:
๋ชจ๋ธ ํด์์ฑ
: TV Ad Budget ๋ณ์๊ฐ Sales์ ์ค์ํ ์ํฅ์ ๋ฏธ์น๋ค๊ณ ํ๋จ๋๋ค๋ฉด VAR ๋ชจ๋ธ์ด ๋ ์ ํฉํ ์ ์์ต๋๋ค.๋ชจ๋ธ์ ๋ชฉ์
: ์์ธก์ ๋ชฉ์ ์ด ๋ฌด์์ธ์ง์ ๋ฐ๋ผ ๋ชจ๋ธ์ ์ ํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋จ์ํ ๊ณผ๊ฑฐ Sales ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ธกํ๊ณ ์ ํ๋ค๋ฉด ๋์ ARIMA ๋ชจ๋ธ์ด ๋ ์ ํฉํ ์ ์์ต๋๋ค.๋ณต์ก๋
: VAR ๋ชจ๋ธ์ ๋ค๋ณ๋ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ธ์ด ๋ ๋ณต์กํ ์ ์์ผ๋ฉฐ, ๋์ ARIMA ๋ชจ๋ธ์ ๋จ๋ณ๋ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ ์๋์ ์ผ๋ก ๋จ์ํ ์ ์์ต๋๋ค.๋ฐ์ดํฐ ๊ฐ์ฉ์ฑ
: ์ถ๊ฐ์ ์ธ ์ธ์ ๋ณ์๊ฐ ์์ ๊ฒฝ์ฐ VAR ๋ชจ๋ธ์ด ์ ๋ฆฌํ ์ ์์ต๋๋ค.
๋ฐ๋ผ์, ์ค์ ์ฌ์ฉ ๋ชฉ์ ๊ณผ ์ํฉ์ ๋ง์ถ์ด ๋ ๋ชจ๋ธ ์ค ์ ํฉํ ๊ฒ์ ์ ํํ๋ ๊ฒ์ด ๋ฐ๋์งํฉ๋๋ค.
๊ทธ๋์ ์ธ๊ณผ๊ด๊ณ, VAR, ARIMA ๋ชจ๋ธ์ ๊ฐ๊ฐ ์ฅ๋จ์ ์ด ์์ผ๋ฉฐ, ๋ฐ์ดํฐ์ ํน์ฑ๊ณผ ๋ถ์ ๋ชฉ์ ์ ๋ฐ๋ผ ์ ์ ํ ๋ชจ๋ธ์ ์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๋ฌํ ๊ธฐ๋ฒ๋ค์ ์ ํ์ฉํ๋ค๋ฉด, ๋ฐ์ดํฐ์ ์จ๊ฒจ์ง ์ธ์ฌ์ดํธ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋ ๋์ ๋น์ฆ๋์ค ์์ฌ๊ฒฐ์ ์ ๋ด๋ฆด ์ ์์ ๊ฒ์ ๋๋ค.
์ค๋๋ ๋์์ด ๋์ จ๊ธธ ๋ฐ๋ผ๋ฉฐ ์ ๋ ์ด๋ง ํ๋ก์ ํธ์ ์ ์ฉํ๋ฌ ๊ฐ๋ณด๊ฒ ์ต๋๋ค! โญ