Qiita記事(**「Python × 公開経済データで学ぶ マクロ経済学 入門(3)」**)
いいですね — 記事を読み込んだ上で「中身を丁寧に噛み砕いて」解説します。下は要点→コードの動き→得られた結果の読み方→統計的注意点と改良案、という順で整理しました。参照元はすべて該当Qiita記事です。(Qiita)
1) 記事の目的と構成(サマリ)
この記事(「Python × 公開経済データで学ぶ マクロ経済学 入門(3)」)は、World Bank の公開データを wbdata で取得して(GDP と構成要素)、日本を例に 時系列的な「予測因果」=グレンジャー因果性 を調べるワークフローを示しています。特に1975–2024年データを取得し、日本を 1975–2000(前期) と 2001–2024(後期) に分けて、主要6指標(GDP, Consumption, Investment, Gov_Spending, Exports, Imports) の全変数ペアに対してグレンジャー検定の p 値行列を返す実装を載せ、それを解釈しています。(Qiita)
2) 実際のコード(ポイント解説)
データ取得周り
-
wbdata.get_dataframe(...)により World Bank 指標を年次(freq="Y")で取得する関数get_gdp_and_related_data()(記事内ではget_japan_economic_data()等の類似実装)を用意しています。インジケーター(例:NY.GDP.MKTP.CD= GDP)と出力整形(Year列作成)まで含めた一連の処理です。記事のコードを参照してください。(Qiita)
国名/国コードの辞書化
-
wbdata.get_countries()で取得したメタデータから「Aggregates(集計地域)」を除き、iso2Code ↔ nameのマッピングを作って、国コード/国名の変換ヘルパーを用意しています(複数国で拡張しやすい設計)。(Qiita)
グレンジャー検定の実装
-
statsmodels.tsa.stattools.grangercausalitytests()を用い、全ての(caused, causing)ペアについてmaxlag=2(記事例)で検定を回しています。戻り値からssr_ftestの p 値(test_result[max_lag][0]["ssr_ftest"][1])を取り出し、結果を pivot して「行:被説明変数、列:説明変数」の p 値マトリクスにしています。検定の仕様や内部的に返るテスト群については statsmodels のドキュメント参照が便利です。(Qiita)
出力
-
p < 0.05を「グレンジャー因果が統計的に有意」とする判断基準を採用(記事中でも明記)。結果は pandas DataFrame(行列)として出して可視化やネットワーク化に使える形にしています。(Qiita)
3) 記事で得られた結果(要点の読み取り)
記事に掲載された p 値行列の要点(抜粋)は次の通りです。元の数値は記事の表を参照してください。(Qiita)
前期(1975–2000) の特徴
-
Exports → Consumption(p ≈ 0.0038)、逆向きConsumption → Exports(p ≈ 0.0030)など 双方向の有意関係 が複数見られる。 -
Gov_Spending → ExportsやGov_Spending → Importsのように 政府支出が外需や輸入を牽引 するような有意性も観察される。 - 全体として 外需(輸出・輸入)が消費や GDP と密に結びつくネットワーク(複雑な相互作用)がみられます。(Qiita)
後期(2001–2024) の特徴
-
Investment → Consumption(p ≈ 0.020)、Investment → GDP(p ≈ 0.006)やGDP → Investment(p ≈ 0.0067)など 「投資—GDP—消費」の関係が相対的に目立つ。 - 一方で
Exports → Consumption等、かつて有意だった外需関連の因果が 消えている(p が大きい) 場合が多い(例:Exports → Consumption の p ≈ 0.82)。 - 要するに「前期は外需を含む複雑な相互依存ネットワーク、後期は投資が中心になった単純化された構造に見える」という解釈が記事の結論です。(Qiita)
4) 統計的・計量的な注意点(重要)
この記事は良い出発点ですが、グレンジャー因果の解釈と検定には注意点が多く、結果をそのまま構造的因果(政策因果)と読むのは危険です。主要な注意点と対応策を列挙します。
-
Granger因果は「予測的因果(predictive causality)」であり因果(構造的因果)とは別物。
→ 「X が Y をグレンジャー因果する」とは「X の過去値が Y を予測する情報を持つ」こと。因果のメカニズム証明ではありません(記事もその点は暗に示唆)。(Statology) -
非定常性(unit root)と単位根検定の欠如
- マクロ年次系列(GDP 等)はトレンドや単位根を持ちやすく、非定常なデータでそのままグレンジャー検定を行うと偽陽性/偽陰性を招きます。まず ADF(Augmented Dickey–Fuller)などで単位根検定 を行い、非定常なら差分や対数差分、あるいは VECM などで扱うべきです。statsmodels の
adfuller参照。(statsmodels.org)
- マクロ年次系列(GDP 等)はトレンドや単位根を持ちやすく、非定常なデータでそのままグレンジャー検定を行うと偽陽性/偽陰性を招きます。まず ADF(Augmented Dickey–Fuller)などで単位根検定 を行い、非定常なら差分や対数差分、あるいは VECM などで扱うべきです。statsmodels の
-
共積分(cointegration)
- 系列が非定常かつ共に単位根を持ちつつ線形結合が定常である(cointegrated)場合は 単純な Granger 検定より VECM(誤差修正モデル) を用いるのが妥当です(
statsmodels.tsa.stattools.coint/VECM)。(statsmodels.org)
- 系列が非定常かつ共に単位根を持ちつつ線形結合が定常である(cointegrated)場合は 単純な Granger 検定より VECM(誤差修正モデル) を用いるのが妥当です(
-
ラグ長の選択(maxlag の固定は危険)
- 記事は
max_lag=2を使っていますが、ラグ選択は AIC/BIC 等でデータごとに決めるべきです。VAR のselect_order()を使って最適ラグを確認すると良いです。(statsmodels.org)
- 記事は
-
サンプルサイズの問題(有効サンプルが小さい)
- 前期:1975–2000 は 26 観測、後期:2001–2024 は 24 観測(年次データ)。ラグを入れるとさらに有効 n が減るため、検定のパワーや p 値の安定性に注意が必要です(小サンプルゆえの不確実性)。(Qiita)
-
多重検定(multiple testing)
- 全ペア(6×5 = 30 件弱)を同時に検定するため 偽陽性 が増えます。Benjamini–Hochberg(FDR)や Bonferroni 等で補正することを強く推奨します(
statsmodels.stats.multitest.multipletestsに実装あり)。(statsmodels.org)
- 全ペア(6×5 = 30 件弱)を同時に検定するため 偽陽性 が増えます。Benjamini–Hochberg(FDR)や Bonferroni 等で補正することを強く推奨します(
-
構造変化(structural breaks)
- 2000 年前後は日本経済にとって(失われた十年→政策変化→グローバル化など)構造変化しやすい時期です。分割自体は良いアイデアですが、分割点を事前仮定するか検証(構造変化検定)するかは検討すべきです。(Qiita)
5) 実務的な改良案(すぐ使えるチェックリストとコード方針)
以下は記事のワークフローに「統計的により堅牢な前処理」を付けるための具体案(要約+コードスニペット案)。
ワークフロー(推奨)
- 生データ取得(記事と同じ) → 2. ログ変換(必要なら) → 3. 単位根検定(ADF)→ 4-a 非定常なら差分(Δ) or 4-b 共積分なら VECM → 5. VARでラグ選択(AIC/BIC)→ 6. Granger検定(選ばれたラグ)→ 7. p 値補正(FDR 等)→ 8. 可視化(ヒートマップ・ネットワーク)→ 9. 感度分析(別ラグ/別期間/ブートストラップ)
主なコードヒント(擬似コード)
from statsmodels.tsa.stattools import adfuller, grangercausalitytests, coint
from statsmodels.tsa.api import VAR
from statsmodels.stats.multitest import multipletests
import numpy as np, pandas as pd
# 1) 単位根検定関数
def check_stationarity(series, alpha=0.05):
stat, p, *_ = adfuller(series.dropna(), autolag='AIC')
return p < alpha, p # True=stationary
# 2) ラグ選択(VAR)
model = VAR(df) # df: 各列が系列
sel = model.select_order(maxlags=6)
best_lag = sel.aic # あるいは bic
# 3) 全ペアでGranger(選ばれたlagを使う)
# ... (grangercausalitytests を使う)
# 4) p値補正(FDR)
pvals = np.array(all_pvals) # flatten
rej, p_adjusted = multipletests(pvals, alpha=0.05, method='fdr_bh')[:2]
(adfuller, VAR.select_order, multipletests の各関数は statsmodels ドキュメント参照)(statsmodels.org)
6) 可視化・発展アイデア(分析の深掘り)
-
ヒートマップ:p 値行列(または
-log10(p))をヒートマップにして前期/後期で比較。 - ネットワーク図:有意リンクのみをエッジにしたグラフ(NetworkX)で、中心性(degree / eigenvector)を測ると「中心変数」が視覚的にわかる。
-
VAR / インパルス応答(IRF):有意なペアが見つかったら VAR を推定してショックの動学的効果(impulse response)を見る。
statsmodelsの VAR/IRF 機能が使えます。(statsmodels.org)
7) 記事の結論に対する私見(簡潔)
- 記事の結論(前期は外需中心で複雑、後期は投資中心に単純化)はデータから読み取れる示唆として説得力がありますが、上に挙げた検定前処理(単位根・共積分の確認、ラグ選択、多重検定補正)を入れてロバストネスを確認するとより説得力が増します。記事自体は「良い実務的テンプレ」として非常に有用で、次のステップ(VAR/VECM、ネットワーク可視化、他国比較)に自然につながります。(Qiita)
必要なら、この記事のコードをベースにして以下のうち どれを優先的に実装するか を選んでください(すぐにコードを書いて差分を提示します):
- ADF による単位根検定&自動差分化(非定常なら差分を取る)を追加するパイプライン。
- VAR の
select_order()でラグを自動決定してから Granger を回す改良(各国・各期間ごと)。 - 多重検定補正(FDR)を入れて有意リンクだけを出力する仕組み。
- 結果のネットワーク可視化(NetworkX+matplotlib)を追加。
- 他国(US, CN, DE など)への一括実行&比較レポート出力。
やるならどれを先にやりますか?(「全部やって」と言っていただければ、優先度つけて順にサンプル実装を示します。)
Discussion