2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

単位根の有無で変わる因果検定:ADF・KPSSとグレンジャー因果性をPythonで検証

Posted at

user:

グレンジャー因果性の定義と、単位根検定(ADF・KPSS)との関係について、理論的な背景と実務的な注意点を整理して解説してください。

assistant:

以下では、グレンジャー因果性の定義と、それに関係する単位根検定(ADF・KPSS)との関係性について、理論的背景と実務上の注意点を整理して解説します。


🔍 1. グレンジャー因果性とは?

■ 定義(Granger causality)

ある時系列変数 $X_t$ が、別の変数 $Y_t$ の将来値を予測するうえで統計的に有意な情報を提供する場合、「$X$ は $Y$ のグレンジャー因果性を持つ」と言います。

■ 数式による説明

次の2つのモデルを比較します:

帰無モデル(過去の $Y$ のみ):

$$
Y_t = \alpha_0 + \sum_{i=1}^{p} \alpha_i Y_{t-i} + \epsilon_t
$$

拡張モデル(過去の $Y$ と $X$):

$$
Y_t = \beta_0 + \sum_{i=1}^{p} \beta_i Y_{t-i} + \sum_{j=1}^{q} \gamma_j X_{t-j} + \eta_t
$$

→ このとき、$\gamma_j$ が全て0であるという帰無仮説を検定します。


🧠 2. グレンジャー因果性と単位根の関係

■ 単位根のある時系列とは?

  • 単位根(unit root)を持つ系列は**非定常(non-stationary)**です。
  • 非定常系列では、平均・分散・共分散が時間とともに変化します。

■ 非定常の影響

グレンジャー因果性の検定は回帰分析に基づくため、非定常なデータで行うと以下の問題が発生します:

問題点 説明
偽の回帰(spurious regression) 2つの無関係な非定常系列の間で、有意な回帰関係が見つかることがある(誤検出)。
F検定の不正確性 通常のF検定の分布が成立しないため、誤ったp値が導かれる。

🔧 3. 実務的な対応:単位根検定の役割

■ ADF検定(Augmented Dickey-Fuller Test)

  • 帰無仮説: 単位根あり(非定常)
  • 対立仮説: 定常

■ KPSS検定(Kwiatkowski–Phillips–Schmidt–Shin Test)

  • 帰無仮説: 定常
  • 対立仮説: 単位根あり(非定常)

✅ 実務上のポイント

  1. 両検定を併用することで、より堅牢な判断が可能(補完的な関係)。

  2. 単位根がある場合

    • 差分系列にして定常化してから検定を行う(例:1次差分)。
    • 共通の単位根がある場合、**共通トレンド(共積性)を考慮してVECM(ベクトル誤差修正モデル)**が必要になるケースも。

🧪 4. 実務での注意点まとめ

注意点 内容
単位根の確認 グレンジャー因果性検定前にADF・KPSS検定で定常性を確認。
差分の取りすぎ 差分化しすぎると意味のある因果関係が見えなくなる可能性あり。
ラグの選択 ラグの数(maxlag)選定も重要(AIC/BICで決定)。
多重共線性 過度なラグや多変数モデルで多重共線性が発生することがある。
スケールの調整 変数のスケールが極端に異なると不安定になることがある。

🧭 5. まとめ:実務フロー例

  1. 時系列プロットでトレンド/季節性の確認
  2. ADF・KPSS検定で定常性確認
  3. 非定常なら差分処理(またはVECMの検討)
  4. ラグ長選定(情報量基準など)
  5. グレンジャー因果性検定実施
  6. 結果の解釈とモデル評価

✏️ 参考資料

  • Granger, C. W. J. (1969). "Investigating Causal Relations by Econometric Models and Cross-spectral Methods".
  • Hamilton, J. D. (1994). Time Series Analysis.
  • Enders, W. (2014). Applied Econometric Time Series.

必要であれば、Pythonによる実装例もご提供できます。ご希望があればお知らせください。

user:

ありがとうございます。Pythonによる実装例もご提供ください。

assistant:

以下に、グレンジャー因果性検定の Python実装例 を、ADF・KPSS検定の実行からグレンジャー因果性の検定までを含めてご紹介します。


🔧 必要なライブラリのインストール(必要に応じて)

pip install statsmodels pandas numpy

📘 サンプル実装コード(解説付き)

import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import adfuller, kpss, grangercausalitytests
import matplotlib.pyplot as plt

# ダミーデータの生成
np.random.seed(42)
n = 200
time = np.arange(n)
x = np.cumsum(np.random.randn(n))  # 非定常なランダムウォーク
y = np.roll(x, 1) + np.random.randn(n) * 0.5  # xのラグがyに影響

df = pd.DataFrame({'X': x, 'Y': y})

# =========================
# 1. ADF・KPSS検定関数
# =========================
def test_stationarity(series, name="", alpha=0.05):
    print(f"▶ 検定対象:{name}")

    # ADF検定
    adf_result = adfuller(series)
    print(f"ADF検定 p値: {adf_result[1]:.4f}{'定常' if adf_result[1] < alpha else '非定常'}")

    # KPSS検定
    try:
        kpss_result = kpss(series, regression='c', nlags="auto")
        print(f"KPSS検定 p値: {kpss_result[1]:.4f}{'非定常' if kpss_result[1] < alpha else '定常'}")
    except Exception as e:
        print(f"KPSS検定 エラー: {e}")

    print("-" * 40)

# 検定実行
test_stationarity(df["X"], name="X")
test_stationarity(df["Y"], name="Y")

# =========================
# 2. 差分系列の作成(必要に応じて)
# =========================
df_diff = df.diff().dropna()
test_stationarity(df_diff["X"], name="X(差分)")
test_stationarity(df_diff["Y"], name="Y(差分)")

# =========================
# 3. グレンジャー因果性検定(差分系列に対して)
# =========================
print("▶ グレンジャー因果性検定(X → Y)")
granger_result = grangercausalitytests(df_diff[['Y', 'X']], maxlag=5, verbose=True)

📝 実行結果の解釈

  • ADF検定:p値が 小さいほど 「定常」と判断される。
  • KPSS検定:p値が 大きいほど 「定常」と判断される。
  • 両方の結果が一致すると定常性の信頼度が高い。
▶ 検定対象:X
ADF検定 p値: 0.7543 → 非定常
KPSS検定 p値: 0.0321 → 非定常
  • グレンジャー因果性検定の出力には、各ラグにおけるF値・p値などが出力されます。

    • XY に因果性を持つかは、p値が 0.05 未満のラグが存在するかで判断できます。

📦 補足:結果をDataFrame形式で整理

def extract_granger_pvals(result_dict, cause, effect):
    pvals = []
    for lag, res in result_dict.items():
        pval = res[0]['ssr_ftest'][1]
        pvals.append({"lag": lag, "p-value": pval})
    df_pvals = pd.DataFrame(pvals)
    df_pvals["causality"] = f"{cause}{effect}"
    return df_pvals

df_pval = extract_granger_pvals(granger_result, "X", "Y")
print(df_pval)

✅ 実務での応用

  • 実データに適用する前に、必ず定常性検定を実施する。
  • 差分化やVECMの検討を含めたワークフローを組む。
  • ラグ長選択を AIC/BICで自動選択させたい場合、VAR モデルの select_order() を使う方法もあります。

💡 ご希望があれば…

  • VARVECM モデルのグレンジャー因果性検定
  • 複数変数間の因果ネットワーク可視化
  • pandas でまとめた因果検定のレポート自動化

など、さらに応用的な実装も可能です。お気軽にお知らせください。

user:

ありがとうございます。最初のコードの結果は次のようになりました。

▶ 検定対象:X
ADF検定 p値: 0.1696 → 非定常
KPSS検定 p値: 0.0135 → 非定常
----------------------------------------
▶ 検定対象:Y
ADF検定 p値: 0.2292 → 非定常
KPSS検定 p値: 0.0146 → 非定常
----------------------------------------
▶ 検定対象:X(差分)
ADF検定 p値: 0.0000 → 定常
KPSS検定 p値: 0.1000 → 定常
----------------------------------------
▶ 検定対象:Y(差分)
ADF検定 p値: 0.0000 → 定常
KPSS検定 p値: 0.1000 → 定常
----------------------------------------
▶ グレンジャー因果性検定(X → Y)

Granger Causality
number of lags (no zero) 1
ssr based F test:         F=334.6113, p=0.0000  , df_denom=195, df_num=1
ssr based chi2 test:   chi2=339.7592, p=0.0000  , df=1
likelihood ratio test: chi2=197.8305, p=0.0000  , df=1
parameter F test:         F=334.6113, p=0.0000  , df_denom=195, df_num=1

Granger Causality
number of lags (no zero) 2
ssr based F test:         F=247.4290, p=0.0000  , df_denom=192, df_num=2
ssr based chi2 test:   chi2=507.7448, p=0.0000  , df=2
likelihood ratio test: chi2=251.1025, p=0.0000  , df=2
parameter F test:         F=247.4290, p=0.0000  , df_denom=192, df_num=2

Granger Causality
number of lags (no zero) 3
ssr based F test:         F=198.4179, p=0.0000  , df_denom=189, df_num=3
ssr based chi2 test:   chi2=617.3000, p=0.0000  , df=3
likelihood ratio test: chi2=278.9051, p=0.0000  , df=3
parameter F test:         F=198.4179, p=0.0000  , df_denom=189, df_num=3

Granger Causality
number of lags (no zero) 4
ssr based F test:         F=150.8955, p=0.0000  , df_denom=186, df_num=4
ssr based chi2 test:   chi2=632.7878, p=0.0000  , df=4
likelihood ratio test: chi2=281.9227, p=0.0000  , df=4
parameter F test:         F=150.8955, p=0.0000  , df_denom=186, df_num=4

Granger Causality
number of lags (no zero) 5
ssr based F test:         F=124.4738, p=0.0000  , df_denom=183, df_num=5
ssr based chi2 test:   chi2=659.7794, p=0.0000  , df=5
likelihood ratio test: chi2=287.4721, p=0.0000  , df=5
parameter F test:         F=124.4738, p=0.0000  , df_denom=183, df_num=5

assistant:

ありがとうございます。ご提示いただいた結果を踏まえて、理論的背景と実務的な観点から解釈を整理します。


✅ 結果のサマリーとその意味

📌 単位根検定の結果

変数 ADF p値 KPSS p値 判定
X 0.1696 0.0135 非定常(両検定一致)
Y 0.2292 0.0146 非定常(両検定一致)
X(差分) 0.0000 0.1000 定常(両検定一致)
Y(差分) 0.0000 0.1000 定常(両検定一致)

➡️ 非定常な元データを差分することで定常性を獲得できたため、差分系列に基づくグレンジャー因果性検定は適切に行えます。


📌 グレンジャー因果性検定(X → Y)

ラグ数 F値(ssr F test) p値
1 334.6113 0.0000
2 247.4290 0.0000
3 198.4179 0.0000
4 150.8955 0.0000
5 124.4738 0.0000

➡️ **どのラグでも p値が0.0000(5%有意水準で有意)**なので、
➡️ 「X は Y に対してグレンジャー因果性を持つ」と結論づけられます。


📘 実務的なインプリケーション

🧩 1. 非定常データを直接使わない

元の X, Y はともに非定常(トレンドあり)。そのまま使うと「偽の因果性(spurious causality)」を検出してしまうリスクがあります。

→ 今回は差分系列に変換してから検定したため、妥当な因果推定ができています。


🧩 2. ラグ数の解釈と選び方

  • 今回のように すべてのラグで有意という結果は、X が過去にわたり強く Y に影響している可能性を示唆。
  • ラグ数は VAR モデルで AIC/BIC を使って選ぶのがベストプラクティス。
from statsmodels.tsa.api import VAR

model = VAR(df_diff)
lag_selection = model.select_order(maxlags=10)
print(lag_selection.summary())

🧩 3. Y → X の因果性も確認すべき

Granger因果性は非対称的なので、Y → X の方向についても同様に検定しておくと、因果ネットワーク全体が把握できます。

# Y → X の因果性を検定
grangercausalitytests(df_diff[['X', 'Y']], maxlag=5, verbose=True)

✅ 結論

  • XはYに対してグレンジャー因果性を持つと判断できる(差分系列において)。
  • 非定常性の処理(差分)と事前検定は極めて重要。
  • 実務では、相互方向の検定やラグ選択の最適化も合わせて行うことで、信頼性の高い因果構造の解釈が可能になります。

必要であれば、以下もサポートできます:

  • 相互方向を含めた因果関係のマトリクス化・可視化(ヒートマップなど)
  • グレンジャー因果性に基づくネットワーク構造図(networkx, pyvis, plotly
  • VECM(共積分を持つ非定常系列用)による因果分析

ご希望があればお知らせください!

user:

すみません、「単位根」とか「差分系列に変換」のあたりが、まだよく分からないので、詳しく教えていただけますか?

assistant:

もちろんです!「単位根」や「差分系列に変換する」といった概念は時系列分析の基礎でありつつ、直感的にわかりにくいところでもあります。ここではできるだけわかりやすく、直感的に説明します。


🌱 単位根とは何か?(やさしく解説)

■ 時系列データの「定常」とは?

  • 定常(stationary) とは、時間が経っても「性質が変わらない」データのことです。

    • 平均が一定(上下にゆらぐけど、大きく変化しない)
    • 分散が一定(ブレの大きさが変わらない)
    • 自己相関が時間に依存しない

例:株価の「変化率」や、気温の「季節調整済みデータ」などは、定常に近い場合があります。


■ 非定常な時系列(=単位根がある)

  • 時間とともに平均が変わっていく
  • 長期的に上がり続けたり、下がり続けたりする
  • これは「ランダムウォーク」と呼ばれることもあります。

📉 例:ランダムウォークのイメージ

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
n = 100
noise = np.random.randn(n)
rw = np.cumsum(noise)

plt.plot(rw)
plt.title("非定常な時系列:ランダムウォーク(単位根あり)")
plt.show()

👆上記のように、ブレながらどんどん上がっていく時系列は「単位根がある=非定常」です。


🧮 単位根のある系列をどうするの?→ 差分!

■ 差分系列とは?

単純に「前の値との差」を取る操作です。

$$
\Delta X_t = X_t - X_{t-1}
$$

■ 差分の効果:ランダムウォーク → 定常に!

diff_rw = np.diff(rw)

plt.plot(diff_rw)
plt.title("差分系列(定常になる)")
plt.axhline(y=0, color='gray', linestyle='--')
plt.show()

👆 差分をとることで、上下のブレは残るものの、平均が安定して**「定常」な時系列になります**。


🔎 なぜ定常にしないといけないの?

グレンジャー因果性検定や回帰分析など、多くの時系列モデルは「データが定常であること」を前提にして作られています。

❌ 非定常なデータを使うと…

  • 時間の経過による「自然な変化」まで因果関係として誤検出する(偽の因果性
  • モデルが「うまく当てはまってるように見えて、まったく意味がない」

🧪 検定による判断方法

■ ADF検定(Augmented Dickey-Fuller)

  • 帰無仮説:「単位根がある」(=非定常)
  • p値が 小さい(< 0.05) → 定常!

■ KPSS検定

  • 帰無仮説:「定常である」
  • p値が 大きい(> 0.05) → 定常!

➡️ この2つを両方見ることで補完的に判断できます。


✍️ まとめ(図解的に)

概念 意味 モデルに使える?
単位根あり 非定常。平均や分散が変化する 累積降水量、株価、人口など ❌ そのまま使えない
差分系列 前との差を取った定常な時系列 株価の変化量、温度変化など ✅ 使える

💬 イメージで理解する一言

「単位根」は、時系列が流されていく力のこと。
「差分」は、その流れを打ち消して、安定させる道具です。


❓補足:じゃあ差分しすぎたらどうなるの?

  • 差分を取りすぎると、データの意味がわからなくなったり、本来の関係性が消えてしまうことも。
  • 「1階差分(1回だけ差分)」で定常になるならそれがベストです。

ご希望があれば、実際に np.cumsumdiff() を使った可視化・実験など、Notebookベースの解説付き教材形式にもできますので、ぜひお知らせください!

user:

なるほど、ありがとうございます。最初のコードを実行すると、次のようなワーニングが出たので、ワーニングが出ないように修正したコードを書いていただけますか?

/tmp/ipython-input-1-2550209205.py:27: InterpolationWarning: The test statistic is outside of the range of p-values available in the
look-up table. The actual p-value is greater than the p-value returned.

  kpss_result = kpss(series, regression='c', nlags="auto")
/tmp/ipython-input-1-2550209205.py:27: InterpolationWarning: The test statistic is outside of the range of p-values available in the
look-up table. The actual p-value is greater than the p-value returned.

  kpss_result = kpss(series, regression='c', nlags="auto")
/usr/local/lib/python3.11/dist-packages/statsmodels/tsa/stattools.py:1556: FutureWarning: verbose is deprecated since functions should not print results
  warnings.warn(

assistant:

ありがとうございます。いただいたワーニングは以下のように分類できます:


❗ ワーニングの内容と対応方法

InterpolationWarning(from kpss()

InterpolationWarning: The test statistic is outside of the range of p-values available in the look-up table.
  • 原因:KPSS 検定の test statistic が p値テーブルの範囲外(特に 小さい 場合)になると出るワーニング。
  • 実害はなしですが、ワーニングを非表示にしたい場合は warnings モジュールで抑制できます。

FutureWarning(from grangercausalitytests()

FutureWarning: verbose is deprecated since functions should not print results
  • 原因verbose=True は今後非推奨になる予定。
  • 対応verbose=False にして出力を抑え、必要な結果だけ抽出して表示するのが推奨されます。

✅ 修正版コード(ワーニング抑制&出力整理)

以下に、ワーニングを出さず、必要な結果のみ表示するよう改良したコードを示します:

import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import adfuller, kpss, grangercausalitytests
import matplotlib.pyplot as plt
import warnings

# --- ワーニング非表示設定 ---
warnings.filterwarnings("ignore", category=UserWarning)  # KPSS InterpolationWarningなどを非表示
warnings.filterwarnings("ignore", category=FutureWarning)

# --- データ生成 ---
np.random.seed(42)
n = 200
x = np.cumsum(np.random.randn(n))
y = np.roll(x, 1) + np.random.randn(n) * 0.5
df = pd.DataFrame({'X': x, 'Y': y})

# --- 定常性検定関数(改良版) ---
def test_stationarity(series, name="", alpha=0.05):
    print(f"▶ 検定対象:{name}")

    # ADF
    adf_p = adfuller(series)[1]
    print(f"ADF検定 p値: {adf_p:.4f}{'定常' if adf_p < alpha else '非定常'}")

    # KPSS
    try:
        kpss_p = kpss(series, regression='c', nlags="auto")[1]
        print(f"KPSS検定 p値: {kpss_p:.4f}{'非定常' if kpss_p < alpha else '定常'}")
    except Exception as e:
        print(f"KPSS検定 エラー: {e}")

    print("-" * 40)

# --- 差分系列作成 ---
df_diff = df.diff().dropna()

# --- 検定実行 ---
test_stationarity(df["X"], name="X")
test_stationarity(df["Y"], name="Y")
test_stationarity(df_diff["X"], name="X(差分)")
test_stationarity(df_diff["Y"], name="Y(差分)")

# --- グレンジャー因果性(改良版) ---
def run_granger_test(df, cause, effect, max_lag=5):
    print(f"▶ グレンジャー因果性検定:{cause}{effect}")
    result = grangercausalitytests(df[[effect, cause]], maxlag=max_lag, verbose=False)
    
    for lag, res in result.items():
        f_pval = res[0]['ssr_ftest'][1]
        print(f"Lag {lag}: p値 = {f_pval:.4f}{'因果性あり' if f_pval < 0.05 else '因果性なし'}")

# 実行
run_granger_test(df_diff, cause="X", effect="Y")

📌 このコードの改善点まとめ

改善点 内容
warnings.filterwarnings() KPSSとFutureWarningを抑制
verbose=False grangercausalitytests() の将来警告に対応
✅ 出力整理 重要な p値と判定だけを簡潔に表示
✅ エラー安全性 KPSSで例外が出てもクラッシュしない設計

📎 出力例(再掲)

▶ 検定対象:X
ADF検定 p値: 0.1696 → 非定常
KPSS検定 p値: 0.0135 → 非定常
----------------------------------------
▶ グレンジャー因果性検定:X → Y
Lag 1: p値 = 0.0000 → 因果性あり
Lag 2: p値 = 0.0000 → 因果性あり
...

ご希望があれば、次は以下のような拡張も可能です:

  • 因果性の結果を pandas DataFrameにして保存・可視化
  • 相互因果性を含む ヒートマップ
  • 他の変数ペアに対しても一括検定する関数

必要に応じてお申し付けください!

user:

ありがとうございました。2つ目の、 extract_granger_pvals 関数を含むコードの結果は次のとおりでした。

lag       p-value causality
0    1  3.526483e-44     X → Y
1    2  7.206021e-54     X → Y
2    3  3.821488e-58     X → Y
3    4  2.915012e-57     X → Y
4    5  5.986990e-57     X → Y

assistant:

ご報告ありがとうございます。その結果から読み取れる重要な点と、実務的な解釈のポイントを以下に整理します。


結果の読み取り

lag p-value causality
1 3.5e-44 X → Y
2 7.2e-54 X → Y
3 3.8e-58 X → Y
4 2.9e-57 X → Y
5 6.0e-57 X → Y
  • すべてのラグで p-value が極めて小さい(≪ 0.05)
    X の過去の値が Y に統計的に有意な影響を与えている(Granger因果がある)と結論づけられます。

  • ラグを増やしても p-value はほぼ変わらない(むしろ安定して小さい)
    → 適切なラグ数はある程度小さくても因果関係は検出できる可能性がある(ただし、モデルのAIC/BICなどでのラグ選択は別途考慮が必要)。


🔍 実務的な解釈・注意点

観点 解説
因果の方向 今回は「X → Y」の因果性があるという結果。逆方向(Y → X)は別途検定する必要があります(双方向性の確認)。
p-value の過信に注意 非定常系列のままだと p-value の正確性が保証されないため、事前の単位根検定(ADF/KPSS)で系列の定常性を確認し、必要に応じて差分を取るのが重要です。
多重検定問題 ラグを複数試す場合は、有意水準を調整する(例:ボンフェローニ補正)なども考慮すると堅牢です。
ラグの解釈 経済データなどでは、ラグが「1ヶ月前」「1四半期前」など具体的な時間を示すため、ドメイン知識に基づくラグ選択も重要です。

📌 補足:Y → X の因果性も調べたいときは?

同じ extract_granger_pvals() 関数で、XY を逆にすればOKです:

extract_granger_pvals(df_diff, 'Y', 'X', max_lag=5)

これにより、「Yの過去がXを予測するか?」という逆方向の因果性を検定できます。


必要であれば、この結果をプロットで可視化するコード(棒グラフやp-valueの折れ線グラフ)も提供できますので、気軽にお知らせください。

user:

ありがとうございます。VAR や VECM モデルのグレンジャー因果性検定について教えてください。

assistant:

こちらこそありがとうございます。それでは、VAR(Vector Autoregression)VECM(Vector Error Correction Model) におけるグレンジャー因果性検定について、理論・手法・実装の観点からわかりやすく解説します。


🔁 1. VARモデルとグレンジャー因果性

❓ 基本概念

  • VARモデルは、複数の時系列変数が互いにラグ付きで影響を与えるような線形モデルです。
  • 各変数が、自分自身と他の変数の過去の値で説明されます。
  • グレンジャー因果性検定は、**「他の変数の過去が自分の予測に有意に貢献するか」**を調べるテストです。

📌 数式イメージ(2変数 VAR(𝑝) の例):

$$
\begin{aligned}
Y_t &= a_{10} + \sum_{i=1}^{p} a_{11,i} Y_{t-i} + \sum_{i=1}^{p} a_{12,i} X_{t-i} + \varepsilon_{1,t} \
X_t &= a_{20} + \sum_{i=1}^{p} a_{21,i} Y_{t-i} + \sum_{i=1}^{p} a_{22,i} X_{t-i} + \varepsilon_{2,t}
\end{aligned}
$$

  • ここで、$X$ のラグ項が $Y$ の予測精度を有意に高めるかを検定します。

🧮 2. 実装:PythonでのVARグレンジャー因果性検定

import pandas as pd
from statsmodels.tsa.api import VAR
from statsmodels.tsa.stattools import adfuller
import numpy as np

# サンプルデータ(適宜差分を取る)
np.random.seed(0)
n = 200
e1 = np.random.normal(size=n)
e2 = np.random.normal(size=n)
X = np.cumsum(e1)  # 単位根あり
Y = 0.3 * np.roll(X, 1) + e2  # XがYに因果影響を持つ

df = pd.DataFrame({'X': X, 'Y': Y})

# 差分系列に変換(定常性が必要)
df_diff = df.diff().dropna()

# VARモデルのフィッティング
model = VAR(df_diff)
results = model.fit(maxlags=5, ic='aic')

# グレンジャー因果性検定(例:X→Y)
granger_result = results.test_causality(caused='Y', causing='X', kind='f')
print(granger_result.summary())

⚖️ 3. VECMとグレンジャー因果性

💡 なぜVECMが必要か?

  • 時系列が非定常かつ共積している場合(例:差分は定常でも水準は非定常)、単純なVARは誤った推論をします。
  • この場合、VECM(誤差修正モデル)を使います。

📌 VECMの構造

VECMは、VARを差分に変換したモデルに「水準のズレ(誤差修正項)」を追加したものです:

$$
\Delta Y_t = \Pi Y_{t-1} + \sum_{i=1}^{p-1} \Gamma_i \Delta Y_{t-i} + \varepsilon_t
$$

  • $\Pi$ が 共積行列。Rank($\Pi$) が0 < r < k なら共積関係あり
  • $\Gamma_i$ は短期効果。これがグレンジャー因果性の評価対象です。

🧪 4. PythonでのVECMグレンジャー因果性検定

from statsmodels.tsa.vector_ar.vecm import VECM, select_order, select_coint_rank

# 1. 適切なラグと共積数を選定
lag_order = select_order(df, maxlags=5, deterministic="ci")
print("Lag order:\n", lag_order)

coint_rank = select_coint_rank(df, det_order=0, k_ar_diff=lag_order.aic)
print("Cointegration Rank:\n", coint_rank)

# 2. VECMモデル構築とフィット
vecm_model = VECM(df, k_ar_diff=lag_order.aic, coint_rank=coint_rank.rank, deterministic="ci")
vecm_res = vecm_model.fit()

# 3. グレンジャー因果性の検定(例:X → Y)
granger_test = vecm_res.test_granger_causality(causing='X', caused='Y', kind='wald')
print(granger_test)

🛠 実務的な注意点

観点 VARモデル VECMモデル
定常性 必須(差分または変換) 非定常でも可(ただし共積)
グレンジャー因果性検定の対象 ラグ項の有意性(F/Wald検定) 差分項の係数の有意性(Wald)
前提チェック 単位根検定(ADF等) 単位根+共積検定(Johansen等)
誤用リスク 非定常のまま使うと誤推定 Rank設定ミスで誤解

🧾 まとめ

  • VARモデルでは、定常な時系列同士で因果性を調べる。
  • VECMモデルでは、非定常で共積している系列に対して、短期・長期の因果効果を区別して調べられる。
  • モデル選択には、**単位根検定(ADF/KPSS)共積検定(Johansen)**が重要。
  • 実装は statsmodels ライブラリで対応可能。

ご希望があれば、結果解釈やグラフ可視化、VECM構造の可視化なども対応できます。お気軽にどうぞ。

user:

ありがとうございます。2. 実装:PythonでのVARグレンジャー因果性検定の結果は次のとおりでした。

Granger causality F-test. H_0: X does not Granger-cause Y. Conclusion: reject H_0 at 5% significance level.
========================================================
Test statistic Critical value p-value         df        
--------------------------------------------------------
         10.45          2.629   0.000 (3, np.int64(378))
--------------------------------------------------------

assistant:

ありがとうございます。表示された結果から、グレンジャー因果性検定における X → Y の因果関係 について、以下のように読み取れます。


✅ 検定結果の解釈

  • 帰無仮説 (H₀):XはYをグレンジャー因果しない(=Xの過去はYの将来を予測するのに有用ではない)
  • 対立仮説 (H₁):XはYをグレンジャー因果する

🔍 結果の要点

指標 結果 解釈
検定統計量 10.45 観測されたF統計量。大きいほどH₀を棄却しやすい。
臨界値(5%) 2.629 有意水準5%におけるF分布の臨界値
p値 0.000 非常に小さい → H₀を強く棄却
自由度 (df) (3, 378) numerator, denominator の自由度(ラグ3使用)
結論 H₀を棄却 → XはYをグレンジャー因果すると判断できる

📌 注意点と補足

1. 単位根や共通トレンドへの注意

  • 時系列が非定常(単位根あり)なままだと、この検定結果は誤判定の恐れがあります。

  • 対処方法:

    • 単位根検定(ADF, KPSS)で定常性を確認する
    • 非定常なら 差分をとる(通常は1階差分)
    • 2変数がともにI(1)で、**共通トレンド(共積性)**があるなら、**VECM(共分散制約付きVAR)**を使うべき

2. ラグ選択が重要

  • 自由にラグを指定すると、過剰に当てはまりやすくなり、偽の因果関係が見えることがあります。
  • VAR.select_order() を使って AIC/BIC などで最適ラグを決定するのが実務的

3. 因果方向と因果強度は別物

  • 検定はあくまで「過去の情報の有用性」を見ているだけで、真の因果メカニズムを保証するものではありません。
  • 因果の強さや意味を知りたいなら、回帰係数の大きさや影響度も確認しましょう。

📘 関連コード(再掲)

以下は、statsmodels を使ったVARでのグレンジャー因果性検定のコードです:

import pandas as pd
from statsmodels.tsa.api import VAR

# データ読み込み
df = pd.read_csv("your_timeseries.csv", index_col=0, parse_dates=True)

# 差分系列に変換(必要なら)
df_diff = df.diff().dropna()

# VARモデルのラグ数を自動選択
model = VAR(df_diff)
lag_order = model.select_order().selected_orders['aic']  # AICベース

# モデルフィッティング
model_fitted = model.fit(lag_order)

# グレンジャー因果性検定(H0: X は Y をグレンジャー因果しない)
# 検定形式: does 'X' Granger-cause 'Y'?
granger_test = model_fitted.test_causality(caused='Y', causing='X', kind='f')

# 結果表示
print(granger_test.summary())

ご希望であれば、VECM によるグレンジャー因果性検定のコード例もご紹介できます。興味がありますか?

user:

ありがとうございます。先に4. PythonでのVECMグレンジャー因果性検定のコードを教えてもらっていましたので、それを実行した結果がこちらです。

Lag order:
 <statsmodels.tsa.vector_ar.var_model.LagOrderResults object. Selected orders are: AIC -> 0, BIC -> 0, FPE -> 0, HQIC ->  0>
Cointegration Rank:
 Johansen cointegration test using trace test statistic with 5% significance level
=====================================
r_0 r_1 test statistic critical value
-------------------------------------
  0   2          173.9          15.49
  1   2         0.6889          3.841
-------------------------------------
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipython-input-5-2514508369.py in <cell line: 0>()
     13 
     14 # 3. グレンジャー因果性の検定(例:X → Y)
---> 15 granger_test = vecm_res.test_granger_causality(causing='X', caused='Y', kind='wald')
     16 print(granger_test)

TypeError: VECMResults.test_granger_causality() got an unexpected keyword argument 'kind'

assistant:

ありがとうございます。vecm_res.test_granger_causality() のエラーは、kind='wald' という引数が statsmodelsVECMResults.test_granger_causality() に存在しないために発生しています。


✅【解決策】

kind='wald' は不要なので 削除 してください。以下のように書き換えれば、正常に動作します。

# グレンジャー因果性の検定(例:X → Y)
granger_test = vecm_res.test_granger_causality(causing='X', caused='Y')
print(granger_test)

🧠 補足:VECMでのグレンジャー因果性とは?

VECMでは以下の2種類の因果性が検定されます:

  1. 短期的因果性(差分項の係数がゼロでないか)
  2. 長期的因果性(誤差修正項の係数がゼロでないか)

test_granger_causality() は、差分項に関する Wald 検定を行うことで 短期的グレンジャー因果性 を評価しています。
長期的な因果関係を知りたい場合は、alpha(調整係数)やbeta(共通トレンド)の推定結果から判断します。


📘 おまけ:最新版の仕様確認方法

statsmodels のドキュメントやソースコードで関数の定義を確認するのが確実です:

help(vecm_res.test_granger_causality)

他にもエラーや疑問があれば、お気軽に聞いてください。

user:

ありがとうございます。VECMについては、また後日詳しくお聞きしますね。ここまでの内容をブログに記録したいので、タイトル案をいくつか提案していただけますか?

assistant:

もちろんです!以下に、これまでの内容(グレンジャー因果性検定・VARとVECMの違い・Python実装結果など)を踏まえたブログタイトル案をいくつかご提案します:


🔍 検定の基礎と実装を押さえる系

  1. 「グレンジャー因果性とは何か?VAR・VECMモデルで理解する因果の流れ」
  2. 「Pythonで実践!グレンジャー因果性検定の基本と応用」
  3. 「VAR vs VECM:グレンジャー因果性の見方とPythonによる実装」

🧪 結果・検定プロセスにフォーカスした実践系

  1. 「グレンジャー因果性検定をPythonで実装してみた:VARとVECMでどう違う?」
  2. 「因果か相関か?Pythonで検証するグレンジャー因果性」
  3. 「Pythonで学ぶ時系列の因果分析:VARとVECMの検定プロセス」

🧠 理解を深める学術寄りタイトル

  1. 「因果性を統計的に検証する:グレンジャー因果性検定の理論と実装」
  2. 「時系列分析の要:グレンジャー因果性とVAR・VECMの比較検討」

💡 ライトで実践的なトーン

  1. 「グレンジャー因果性ってなに?Pythonで試す因果の探り方」
  2. 「XがYを引き起こす?Pythonで検証する因果関係」

必要に応じて、タイトルに副題(サブタイトル)も追加できます。たとえば:

「Pythonで実践!グレンジャー因果性検定の基本と応用」
― VARとVECMモデルによる時系列因果分析入門

ご希望のトーン(技術寄り、読みやすさ重視、実践重視など)を教えていただければ、さらに調整できます!

user:

グレンジャー因果性の定義と、単位根検定(ADF・KPSS)との関係についてお聞きしたのが最初ですので、それを踏まえたタイトルにしていただけると嬉しいです。

assistant:

承知しました!
グレンジャー因果性の定義」と「単位根検定(ADF・KPSS)との関係」という理論面の出発点を踏まえたうえで、そこからVAR/VECMやPython実装に進んだ流れを反映したブログタイトル案を以下にご提案します。


🧠 理論+実装の流れを意識した構成

  1. 「グレンジャー因果性の定義から始める時系列分析:ADF・KPSS検定とPython実装まで」
  2. 「因果性とは何か?ADF・KPSSで確認する単位根とグレンジャー因果性の関係」
  3. 「単位根の有無で変わる因果検定:ADF・KPSSとグレンジャー因果性をPythonで検証」
  4. 「グレンジャー因果性と単位根検定の接点とは?時系列因果分析の全体像を掴む」
  5. 「グレンジャー因果性を本当に理解する:ADF・KPSSとVAR/VECMモデルで実装検証」

📊 技術ブログ風の副題付き構成

  1. 「グレンジャー因果性の定義と単位根検定の関係」
     ― ADF・KPSSとPythonで進める時系列因果分析の基本

  2. 「グレンジャー因果性とは?単位根があるときないときでどう違うのか」
     ― ADF・KPSS、VAR、VECMで探る因果関係の実態


🔍 深掘りスタイルの研究寄りトーン

  1. 「グレンジャー因果性検定の理論的基盤:単位根検定(ADF/KPSS)との関係を解きほぐす」
  2. 「グレンジャー因果性の正しい理解のために:非定常性と統計的因果の接点を探る」

どのトーン(入門・実践・研究寄り)が一番しっくりきそうでしょうか?
気に入ったタイトルをベースにサブタイトル調整や構成案のご提案も可能です!

user:

「単位根の有無で変わる因果検定:ADF・KPSSとグレンジャー因果性をPythonで検証」でいきたいと思います。このタイトルに沿って、今回の内容のまとめを詳しく書いてください。

assistant:

かしこまりました!
「単位根の有無で変わる因果検定:ADF・KPSSとグレンジャー因果性をPythonで検証」というタイトルに沿って、今回の内容のまとめを詳しく書きます。


単位根の有無で変わる因果検定:ADF・KPSSとグレンジャー因果性をPythonで検証

はじめに

時系列分析における因果関係の検証は、経済学や金融、気象学など多様な分野で重要なテーマです。
その代表的な方法が「グレンジャー因果性検定」で、ある時系列がもう一方の未来の値を予測できるかを統計的に判定します。

しかし、時系列データの性質によって検定結果の信頼性が大きく変わることをご存じでしょうか?
特に「単位根の有無(系列の定常性)」は因果検定の前提条件として極めて重要です。

本記事では、

  • 単位根とは何か、
  • それを調べるための代表的な検定(ADF検定・KPSS検定)、
  • 単位根の影響を考慮したグレンジャー因果性検定の理論と実務、
  • そしてPythonによる実装例

を通じて、「単位根の有無で変わる因果検定」の全体像を丁寧に解説します。


1. 単位根とは? — 時系列の定常性の概念

1-1. 定常性と非定常性

時系列データの定常性とは、時間が変わっても「平均」や「分散」、「自己相関の構造」が変わらない性質を指します。
対して、非定常な系列は、平均が時間とともに変動したり、分散が不安定だったりします。

1-2. 単位根とは?

非定常系列の典型例が**単位根過程(ランダムウォーク)**で、自己回帰係数が1に近い(あるいは等しい)モデルです。
単位根が存在する時系列は「過去の影響が永久に残りやすい」という性質があり、そのまま分析すると統計的誤りを招く恐れがあります。


2. 単位根検定:ADF検定とKPSS検定の役割

単位根の有無を判定する代表的な検定が以下の2つです。

検定名 帰無仮説 判定基準
Augmented Dickey-Fuller(ADF)検定 単位根が存在する(非定常) p値 < 0.05で単位根なし(定常)と判断
KPSS検定 定常である p値 > 0.05で定常と判断

この2つは互いに補完的であり、両方の検定を組み合わせて系列の性質を総合的に判断します。


3. グレンジャー因果性検定と単位根の関係

グレンジャー因果性検定は系列が定常であることを前提にしています。
もし非定常のまま因果性を検定すると、トレンドの影響で「偽の因果関係」を検出しやすくなります。

対策

  • 非定常系列は差分を取り定常化する
    → 差分系列でグレンジャー因果性検定を行うのが基本

  • 共積分関係(長期均衡関係)がある場合はVECMモデルを利用する


4. Pythonでの検証例

4-1. 単位根検定(ADF・KPSS)

from statsmodels.tsa.stattools import adfuller, kpss

def test_stationarity(series, name=""):
    adf_p = adfuller(series)[1]
    kpss_p = kpss(series, regression='c', nlags='auto')[1]
    print(f"{name} - ADF p-value: {adf_p:.4f}, KPSS p-value: {kpss_p:.4f}")
  • ADFはp値が小さければ定常、KPSSはp値が大きければ定常と判断します。

4-2. 差分を取る例

df_diff = df.diff().dropna()

4-3. グレンジャー因果性検定

from statsmodels.tsa.stattools import grangercausalitytests

grangercausalitytests(df_diff[['Y','X']], maxlag=5, verbose=False)
  • 差分をとった定常系列で検定します。

5. VARモデルとVECMモデルでの因果性検定

  • VARモデル
    定常系列に対して使用し、ラグ付きの多変量回帰モデルを構築。
    グレンジャー因果性は「ある変数の過去の値が他変数の予測に有意か」をF検定などで判断。

  • VECMモデル
    非定常かつ共積関係がある系列に適用。
    長期均衡と短期変動を同時にモデル化し、短期のグレンジャー因果性を検定。

Pythonのstatsmodelsで両モデルの実装と検定が可能です。


6. まとめ

  • 単位根の有無を正しく見極めることは、時系列の因果関係検定の第一歩
  • ADF検定・KPSS検定を併用し、系列の定常性を確認。
  • 非定常なら差分系列に変換し、定常化してからグレンジャー因果性検定を行う。
  • 共積関係があるならVECMを検討する。
  • Pythonのstatsmodelsで、単位根検定からグレンジャー因果性検定まで一貫して実施可能。

おわりに

今回の記事では、単位根の有無が因果検定結果に与える影響と、その対処法を理論とPython実装例を通じて理解しました。
正しく時系列の性質を踏まえた分析が、信頼性の高い因果推論につながることをぜひ覚えておいてください。


もし補足のコード例や応用編(VECMの詳細、ラグ選択基準の解説など)が必要でしたらお気軽にお声がけください!

user:

ありがとうございました!

assistant:

どういたしまして!お役に立てて嬉しいです😊
また何かあればいつでも気軽に聞いてくださいね。ブログ執筆、応援しています!✨

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?