論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
平行トレンド仮定
Parallel Trends Assumption
因果推論
別称: 共通トレンド / parallel trends

🔖 キーワード索引

この用語と一緒に検索・参照されやすいタグ。 関連ページに飛ぶときの手がかりにも使えます。

#因果推論#DiD#平行トレンド#検証#観察データ

各語の説明がある章へのリンク:

反実仮想 事前トレンド検定(年度×群の交互作用) イベントスタディ プラセボ検定 対照群の選び方 尺度依存(水準か対数か) 検出力不足と「有意差なし」 予期(anticipation)効果 Staggered adoption と TWFE Honest DiD 合成統制法 固定効果 DID(PanelOLS)

💡 30秒で分かる結論

🍰 まずはやさしく

データの動きが同じ方向に向かうという約束です。

ある対策の効果を正しく測るために使います。

スマホの利用時間をクラスで比べる時に役立ちます。

この章では結論を短くまとめて解説します。

平行トレンド仮定は、 差分の差(DiD)法における核心仮定。 「介入が無ければ処置群と対照群は平行に推移したはず」。

ここまでが要点です。 ただし実際に使う前に、 このページの「⚠️ よくある落とし穴」で挙げた プリトレンドを「目視で平行」と判断/時間変化する交絡 (TWFE 推定量の罠)/Staggered adoption の負の重み には必ず目を通してください。 つまずくのは知識が無いときより、 知ってはいたが確認を飛ばしたときです。

📍 文脈:「平行トレンド仮定」はどんな場面で出てくる?

🍰 まずはやさしく

分析の説得力を決める大切なルールです。

本当の原因を突き止めるために使います。

部活の新しい練習法で成績が変わったか調べます。

この用語がどんな場面で登場するかを説明します。

本サイトの政策効果分析(最低賃金、 教育改革等)で頻出。 観察データから因果を語る数少ない手段の一つで、 仮定の妥当性が論文の説得力を左右します。

このページでは SSDSE-B-2026 の 47 都道府県 × 12 年度(2012〜2023)のパネルを使い、 東京圏 4 都県と東北 6 県、 三大都市圏と残りの県などの群分けで、 事前トレンドの検定・イベントスタディ・プラセボ検定を実際に計算する。 どの群分けも実在の政策ではなく、 仮定の確かめ方を学ぶための例示である。

🎨 直感で掴む

🍰 まずはやさしく

並走する陸上競技のようなイメージです。

もし対策をしなかったらどうなったかを考えます。

テスト勉強法を変えなかった時の点数を想像します。

直感的にイメージを掴むための例を紹介します。

🎨 平行トレンドが「成り立つ」 と「成り立たない」 ケースの判別図

平行トレンドの判別は、 統計検定だけでなく事前期間のトレンドプロットを目で見る ことも重要です。 以下に典型 4 パターンを整理します。

パターン事前トレンドDID 有効性対応
① 理想的処理群・対照群とも同じ傾き○ 標準 DID 可そのまま実行
② 平行ずれ傾きは同じ、 切片が違う○ DID で吸収そのまま実行
③ 発散傾向処理群がもともと急減× DID 不可Honest DID / Synthetic Control
④ 収束傾向差が縮まっていく× DID 不可マッチング DID

SSDSE-B-2026 では、 東京圏(2014〜2019 年度に総人口が年 +0.42%)と東北(同 −0.89%)のように人口の動きが違う群を比較する場合、 ③ が出やすい(🐍 の事前トレンド検定)。 事前期間が短いと検定の検出力が低いため、 「視覚的に平行に見える + 検定で有意差なし」 の両条件をクリアして初めて平行トレンドが信頼できると考えます。

📝 DID 実装前チェックリスト — 11 項目

SSDSE などの公的データで DID を回す前に、 必ず以下 11 項目を確認しましょう。

  1. 処理群と対照群を明確に定義したか(曖昧な境界がないか)
  2. 処理タイミング (intervention timing) は全群同じか、 staggered か
  3. 事前期間が 3 年以上あるか(最低限の検出力)
  4. 事前期間トレンドのプロットを描いて目視で平行性を確認したか
  5. 事前期間で「年度 × group」 の交互作用項検定を行ったか
  6. プラセボ検定(偽の処理タイミング) で τ ≒ 0 を確認したか
  7. 外れ値(東京や沖縄のような特異県) の影響を感度分析したか
  8. 標準誤差を群レベル(県クラスタ) でロバストに計算したか
  9. 処理の anticipation 効果(公表前期間の行動変化) を考慮したか
  10. 共通ショック(COVID-19、 リーマンショック) の年と重なっていないか確認したか
  11. 結果の頑健性を Honest DID / Synthetic DID で再確認したか

11 項目すべてクリアして初めて、 「平行トレンドのもと推定された政策効果は τ である」 と論文・レポートに書けます。 教育用 SSDSE 演習でも、 これらの確認手順を再現することで、 因果推論の方法論を身体化できます。

📖 実際の応用事例 — 平行トレンドが検証された有名研究

DID 推定が広く認知されたのは、 1994 年の Card-Krueger の最低賃金研究が画期となります。 ニュージャージー州が最低賃金を引き上げたとき、 隣接ペンシルベニア州を対照群として「ファストフード店の雇用が減ったか」 を DID で推定。 古典理論では雇用減少が予測されていましたが、 実際には雇用は減らなかったという衝撃的な発見をもたらしました。 この研究で David Card は 2021 年ノーベル経済学賞を受賞しました。

研究処理対照平行トレンド検証
Card-Krueger (1994)NJ 最賃引上げ隣接 PA 州事前期間の雇用率推移で確認

これらの研究の共通点は、 「処理が外生的に決まった」 こと、 「事前期間のトレンドプロットを論文に必ず掲載した」 こと、 そして「複数の感度分析(プラセボ検定、 別対照群との比較)」 を行ったことです。 SSDSE で同様の手順を踏むなら、 演習として「2014-2019 を事前期間、 2020-2023 を事後期間」 と固定し、 47 都道府県のうち地域ブロック単位で処理/対照を組み合わせるのが安全です。

📋 平行トレンド仮定 — 30 秒サマリーカード

項目内容
定義DID で「処理がなかった場合のトレンドが処理群・対照群で等しい」 と仮定すること
数式$E[Y_{0,t} - Y_{0,t-1} \mid D=1] = E[Y_{0,t} - Y_{0,t-1} \mid D=0]$
検証方法事前期間でトレンド差を OLS の交互作用項で検定、 視覚的に平行性確認、 プラセボ検定
破れたらSynthetic Control / Honest DID / Synthetic DID / マッチング DID へ切替
Pythonstatsmodels.formula.api / linearmodels.panel.PanelOLS / DoubleML
SSDSE 演習縦断 2012-2023 で 47 県を地域ブロック単位に組み、 事前期間 8 年分で検定

平行トレンド仮定は「観察データから因果効果を推定する」 ための最も古典的かつ強力な仮定の一つです。 完全な検証は不可能で、 事前期間のトレンドプロット + 検定 + プラセボの三点セットは「崩れている証拠」を見つける道具であって、 成り立つことの証明にはなりません。 因果推論の入り口として、 必ず手を動かして体感してください。

🧭 追加メモ — 仮定検証の補足理論

平行トレンド仮定が「観察できる事前期間」 だけで検証されるという制約は、 因果推論の根本的な「反実仮想は観察不可能」 という問題を反映しています。 これに対応する 4 つの考え方を整理します。

  1. extrapolation 仮説: 「事前期間で平行だったから、 事後期間でも平行だったはず」 という外挿。 短期の DID では比較的妥当だが、 長期では構造変化の影響で疑わしい。
  2. bounding 法: 平行トレンド完全成立を仮定せず、 「事前期間で観察されたトレンド差の最大値」 を事後にも許容し、 効果推定値の信頼区間を「正直に」 広げる方法(Honest DID)。
  3. 機械学習補正: DoubleML や Causal Forest を用い、 「観察された共変量で説明できる部分は除去した上での平行トレンド」 を仮定する。 SSDSE のような多変量データで有効。
  4. 感度分析: 「平行トレンドの violation がどれくらいなら結論が反転するか」 を計算し、 violation の現実性と比較。 Rambachan-Roth の論文に詳細手順。

2026 年現在、 計量経済学者の多くは「平行トレンド仮定は厳密には成り立たないが、 sensitivity analysis でロバストにする」 というスタンスをとっています。 SSDSE 演習でも、 古典 DID の結果を出した後、 必ず「もし平行トレンドが ±X% ずれていたら結論がどう変わるか」 まで計算する習慣をつけましょう。

最後に重要な注意: 平行トレンド仮定は「処理効果の異質性 (heterogeneity)」 ともセットで考える必要があります。 ある処理が「効果が大きい県」 と「効果がない県」 で混在するとき、 単純な DID は加重平均効果を返しますが、 weights が直感に反する負の値を持つことがあります(特に staggered adoption 時)。 これが Goodman-Bacon (2021) の指摘した DID の落とし穴で、 2020 年以降の文献で大きな議論となりました。

SSDSE 縦断データで DID を演習する際は、 まず単純な 2×2 DID(処理群 1 グループ vs 対照群 1 グループ、 単一処理タイミング) から始めるのが最も誤解を避けやすいです。 慣れてきたら、 県別に処理タイミングが違う staggered adoption 状況、 複数処理が重なる multiple treatments 状況など、 より複雑なケースへ広げていきましょう。 そのとき、 「平行トレンドが何を意味するか」 という出発点を絶対に忘れないことが肝心です。

🖼 図で見る平行トレンド仮定(R654 補強)

ここでは平行トレンド仮定の理解を視覚的に深めるため、 SSDSE-B-2026 都道府県データから 3 種類の図を提示します。 各図は 事前トレンドの平行性検証、 処理群と対照群の事前期間分布、 複数群比較の箱ひげ という 3 つの異なる角度から、 仮定がどのように「目で確認」 されるかを示しています。

図 1: 処理群と対照群の事前トレンド(散布図)

このプロットでやること: SSDSE-B-2026 から、 仮想的に「政策処理を 2018 年度に受けた都市部 5 都府県(2012 年度の人口 1〜5 位: 東京・神奈川・大阪・愛知・埼玉)」 と「対照群の地方部 5 県(43〜47 位: 福井・徳島・高知・島根・鳥取)」 を比較。 出生数(A4101)の 1 県平均を 2012〜2023 年度で折れ線にし、 事前期間 2012〜2017 年度に平行に推移しているかを視認します(2018 年度に実際の政策があったわけではありません)。

都市部 5 都府県と地方部 5 県の出生数(1 県平均)の推移。左は水準、右は 2012 年度 = 100 の指数

読み方: 横軸が年度、 縦軸が出生数(左: 人、 右: 2012 年度 = 100)。 処理群(青)・対照群(オレンジ) の 2 群の傾きが平行なら、 平行トレンド仮定の信頼度が高い。 この組み合わせでは、 事前期間の傾きが水準で −770 人/年 と −106 人/年(1 県平均)、 指数でも −1.01/年 と −1.89/年 で、 2017 年度には 94.4 と 90.1 に開いている。 どちらの尺度でも平行とは言えず、 「対照群を反実仮想として使う」 という DID の前提が崩れるサインです。

実務 Tips: 散布図は事前期間 5 年以上をプロットするのが理想。 短すぎると偶然の一致と区別できません。 また、 同じスケールで縦軸を表示すること(処理群と対照群を別の y 軸にしない) が重要です。 別軸にすると平行に「見えてしまう」 視覚的トリックが生じます。

図 2: 事前期間における出生数の分布(ヒストグラム)

このプロットでやること: SSDSE-B-2026 で、 処理群と対照群の事前期間の「水準」 と「ばらつき」 を比較。 ヒストグラムで両群の分布形状を重ねて表示し、 「そもそも比較可能なくらい似た集団か」 を確認します。

事前期間 2012〜2017 年度の出生数のヒストグラム。都市部 5 都府県は中央値 69,392、地方部 5 県は中央値 5,323

読み方: 横軸が出生数(人、 対数目盛)、 縦軸が件数(各群 5 県 × 6 年度 = 30 件)。 図 1 と同じ 2 群では、 中央値が 69,392 と 5,323 で 13.0 倍離れ、 分布はまったく重ならない。 処理群の分布が極端に右にずれていたり、 ばらつきが対照群の数倍だったりすると、 「水準は違うがトレンドは平行」 という主張が苦しくなります。 平行トレンド仮定は「水準が同じ」 を要求しませんが、 「水準が極端に違う場合、 トレンドの解釈も難しくなる」 のは事実です。

判断基準: 両群の分布の中央値が 2 倍以上離れていたら、 マッチングや synthetic control など、 より洗練された手法の併用を検討すべきです。 SSDSE 演習では「東京・大阪のような大都市」 と「地方県」 を混ぜるとこの問題が起きやすいので、 群分けの際に注意してください。

図 3: 複数群での事前トレンド差(箱ひげ図)

このプロットでやること: SSDSE-B-2026 を 2012 年度の人口順位で 4 グループに分け(処理群 = 1〜5 位、 対照 A = 43〜47 位、 対照 B = 6〜20 位、 対照 C = 21〜42 位)、 事前期間の出生数の前年比(2013〜2017 年度の 5 年分、 県 × 年)を箱ひげ図で比較。 中央値と四分位範囲が群間で揃っていれば、 どの対照群を選んでも平行トレンドが成り立つ証拠となります。

処理群・対照 A/B/C の 4 群について、2013〜2017 年度の出生数の前年比を並べた箱ひげ図

読み方: 横軸が群(処理・対照 A/B/C)、 縦軸が年次成長率(%)。 箱の中央値と高さ(IQR) が群間でほぼ揃っていれば、 「どの対照を選んでも平行トレンドは保証される」 と言えます。 逆に処理群だけ中央値が外れているなら、 平行トレンド違反の疑いが強い。 実データでは中央値が処理群 −1.78%、 対照 A −2.89%、 対照 B −2.41%、 対照 C −2.29% で、 都市部の出生数は他の 3 群より減り方が緩い。 箱の高さ(IQR)は対照 A が 4.22 ポイントと最も広く、 5 県の小さな群では年ごとの揺れが大きい。

応用: この箱ひげ図は「どの対照群を採用すべきか」 の判断材料にもなります。 処理群と中央値が最も近い対照群を選ぶことで、 平行トレンド仮定の妥当性を高められます。 ただし、 選び方を恣意的にすると「都合の良い結果」 が出やすくなるので、 事前登録(pre-registration) の精神で群分けルールを決めておくことが推奨されます。

🧠 深掘り — 平行トレンド仮定の理論背景(R654 補強)

平行トレンド仮定は、 統計学的には「処理群の counterfactual outcome trend(もし処理を受けなかったらどう推移したか) は、 観察された対照群の outcome trend で代替できる」 という主張に対応します。 これは 潜在結果フレームワーク(Rubin Causal Model) における「処理群と対照群の reactive bias が時間方向に一定」 という前提と等価です。

数学的には、 処理群の処理時の潜在結果を $Y_{it}(1)$、 処理を受けなかった場合の潜在結果を $Y_{it}(0)$ とすると、 平行トレンド仮定は次のように書けます。 $E[Y_{it}(0) - Y_{i,t-1}(0) \mid D_i = 1] = E[Y_{it}(0) - Y_{i,t-1}(0) \mid D_i = 0]$。 つまり「処理を受けなかった場合の outcome 変化の期待値」 が、 処理群と対照群で等しい。 これが「平行」 の正式な数学的意味です。

この仮定の重要な性質は scale-dependence です。 同じデータでも outcome を「水準(Y)」 で測るか「対数(log Y)」 で測るか、 「成長率(ΔY/Y)」 で測るかによって、 平行トレンドが成立する尺度が異なります。 SSDSE で出生数を扱う場合、 都市と地方では水準が 10 倍以上違うことがあるので、 log 変換が推奨されることが多いです。 ただし log は 0 や負の値を扱えないので、 outcome の性質を踏まえて選ぶ必要があります。

また、 平行トレンド仮定は 「処理がランダムに割り当てられた」 という強い仮定の弱体版 です。 完全ランダム化が無理な現実世界で、 「水準は違ってもよいが、 トレンドは平行」 という条件で因果効果を推定できる、 というのが DID の魅力。 ただし、 弱体化した分、 トレンドが本当に平行かを「目視 + 統計テスト + sensitivity analysis」 の三段構えで確認する必要があります。

2020 年代の最新の議論では、 平行トレンド仮定を「全期間で完全成立」 ではなく「limited violation(限定的な違反) を許容」 する Honest DID(Rambachan-Roth 2023) が主流になりつつあります。 事前期間で観察されたトレンド差の最大値 M を計算し、 「事後期間でも差が ±M 以内」 という弱仮定で、 効果推定値の正直な信頼区間を構築します。 SSDSE のような短期パネルでも適用可能で、 R や Python の HonestDID パッケージで実装できます。

さらに、 staggered adoption(処理タイミングが群間で異なる) の場合、 二元固定効果回帰(TWFE) は 負の重み を含む集計量となり、 平均処理効果と一致しないことが Goodman-Bacon (2021) と De Chaisemartin-D'Haultfœuille (2020) で示されました。 これに対する処方箋として、 Callaway-Sant'Anna (2021) の did パッケージ、 Borusyak et al. (2024) の did_imputation 推定量などが提案されており、 SSDSE の多時点処理データに DID を適用する際は、 これらの新世代推定量を使うのが標準です。

最後に、 平行トレンド仮定は 「対照群選択の妥当性」 と表裏一体 です。 「対照群を変えたら結果が変わる」 のは仮定違反のサイン。 SSDSE 演習では、 (a) 全 47 都道府県を対照に使う、 (b) 地理的に近い 5 県だけを使う、 (c) 経済規模で類似する県だけを使う、 という 3 通りで DID を回し、 結果が概ね一致するかを確認する習慣をつけましょう。 結果が極端に変わるなら、 「どの対照群が反実仮想として最も妥当か」 を改めて議論する必要があります。

📋 理解度チェック — 平行トレンド仮定を本当に分かったか(R654 補強)

以下の 8 問は、 平行トレンド仮定を実務で正しく使えるかを問うチェックリストです。 すべてに即答できれば、 DID 分析を「形式的に回す」 段階から「自分で妥当性を判断する」 段階へ進めたサインです。 答えは下の解説欄を参照してください。

  1. Q1: 平行トレンド仮定は「処理群と対照群の水準が同じ」 という主張か? Yes / No で答え、 理由を 1 文で述べよ。
  2. Q2: 事前期間 3 年のデータで平行トレンドを「視覚的に」 確認するのは妥当か? 短すぎる場合の代替案を 1 つ挙げよ。
  3. Q3: SSDSE-B-2026 で「人口の多い 5 県」 を処理群、 「人口の少ない 5 県」 を対照群にすると、 平行トレンド仮定はどう脅かされるか?
  4. Q4: 処理群の outcome を log 変換すると、 平行トレンド仮定の成立しやすさはどう変わるか? 利点と欠点を 1 つずつ挙げよ。
  5. Q5: 事前期間の傾きを処理群と対照群で比較する Granger テストの帰無仮説は何か? 棄却された場合の意味は?
  6. Q6: Honest DID(Rambachan-Roth 2023) は古典 DID と何が違うか? 一言で要約せよ。
  7. Q7: Staggered adoption の場合、 TWFE 回帰の問題点は何か? 代替推定量を 1 つ挙げよ。
  8. Q8: SSDSE で DID を演習する際、 「平行トレンドが成り立っていない」 と判断したらどう対応すべきか? 3 ステップで述べよ。

解説(答え)

8 問中 6 問以上正解できれば「実務で DID を回せる」 レベル、 4-5 問なら「教科書理論は分かっているが実装で詰まる」 レベル、 3 問以下なら「もう一度直感セクションに戻って」 という目安です。 SSDSE の縦断データを使った演習を 3 回ほど通せば、 自然と全問正解できるようになります。

🎮 触って理解する

平行トレンド仮定の核心は「処置前トレンドの傾きが両群で等しいか」です。 ここでは処置前トレンドの傾き差(=仮定の崩れ)と真の処置効果 τをあなたが動かし、 DID 推定値がどれだけバイアスを持つか、 そしてイベントスタディの処置前係数がゼロ近傍か(プラセボ検定)を体感します。 計算はすべて解析式どおり正確です。

💡 上のグラフを上下にドラッグ/スワイプしても傾き差 δ を変えられます(タッチ対応)。

真の処置効果 τ
5.0
DID 推定値
5.0
バイアス(推定−真値)
0.0

イベントスタディ:処置時点を基準にした係数 βk

基準は処置直前 k=−1(β−1=0 に固定)。 処置前(k<0)の点がゼロ線の近くに並べばプラセボ検定に合格=平行トレンドを支持。 δ を動かすと処置前の点がゼロから傾いて離れる様子が見えます。

🧠 いま体感したことの言語化

⚠️ よくある落とし穴

🚀 発展:仮定が疑わしいときの武器

関連ページ:差分の差分法(DID)/パネル因果推論/固定効果/自然実験。 (イベントスタディ・合成統制法は本用語集に独立ページがまだ無いため、 リンクではなく用語として示しています。)

📐 定義・数式

🍰 まずはやさしく

数式で表した厳密なルールです。

計算して正しく答えを出すために使います。

買い物で使う金額の変化を数式にします。

記号の意味と数式の読み方を詳しく解説します。

【平行トレンドの数学的表現】
$$ \mathbb{E}[Y_{i,t}(0) - Y_{i,t-1}(0) \mid D_i = 1] = \mathbb{E}[Y_{i,t}(0) - Y_{i,t-1}(0) \mid D_i = 0] $$
「介入を受けなかった場合の変化量」が処置群・対照群で等しい。 これがないと DiD は因果を識別しない。

🔬 数式を言葉で読み解く — 数式を「言葉」に翻訳

Y_{i,t}(0)
i が時点 t で介入を受けなかった場合の潜在的結果
D_i
処置ダミー(1=処置群, 0=対照群)
Pre-period
介入前期間(仮定検証に使う)
Post-period
介入後期間(効果測定)
ATT
処置群への平均処置効果

🔬 数式を言葉で読み解く — DID の平行トレンド仮定

平行トレンド仮定の式 $E[Y_{0,t} - Y_{0,t-1} \mid D=1] = E[Y_{0,t} - Y_{0,t-1} \mid D=0]$ は、 短いですが、 各記号が因果推論の「反実仮想 (counterfactual)」 を表現する核心です。 数式を言葉で読み解くと、 次のような構造です。

記号読み意味SSDSE 例 (人口政策 DID)
$Y_{0,t}$ワイ・ゼロ・ティー処理を受けなかった場合の時点 t の潜在結果(観察できない反実仮想)「2020 年に政策がなかった場合の出生率」
$D$ディー処理の有無 (1 = 処理群、 0 = 対照群)出生支援策を導入した県 = 1
$Y_{0,t} - Y_{0,t-1}$変化量処理なしでの「自然な時間変化」(トレンド)少子化の進行幅
$E[\cdot \mid D=1]$条件付き期待値処理群における平均政策導入県の平均的な変化

数式を言葉で読み解く視点 1: 反実仮想の等価性 この式は、 「処理を受けた群が処理を受けなかった場合の変化幅は、 実際に処理を受けなかった群の変化幅と等しい」 という主張です。 つまり対照群の時間変化が「処理群の counterfactual トレンド」 の代理になるという仮定。 これが破れると DID 推定はバイアスを持ちます。

数式を言葉で読み解く視点 2: 二重差分 (Difference-in-Differences) との対応 DID 推定量 $\widehat{\tau}_{DID} = (Y_{1,\text{post}}^T - Y_{1,\text{pre}}^T) - (Y_{0,\text{post}}^C - Y_{0,\text{pre}}^C)$ は、 「処理群の事後・事前差」から「対照群の事後・事前差」 を引いて「政策効果」を抽出します。 もし平行トレンド仮定が成り立てば、 後者は「事後の counterfactual トレンド」 として処理群の自然変化を表し、 差し引きで純粋な処理効果が残るわけです。

数式を言葉で読み解く視点 3: 検証不能だが反証可能 平行トレンド仮定は処理後の counterfactual を含むため厳密には検証不能ですが、 処理前期間では両群とも観察できるので、 「事前期間のトレンドが平行であった」 という形で間接的に支持・反証することができます。 これが pre-trend test の役割。

🧮 実値で計算してみる

2 群×2 期の DiD 推定の構造:

群\期介入前介入後差
処置群100130+30
対照群100110+10
差の差——+20 = ATT

「平行トレンドが成り立つ」前提で、 +20 が介入の因果効果。 介入前のトレンドが既にズレていれば +20 は信用できない。

🧮 SSDSE 縦断データで平行トレンドを検証 — 47 県の出生数

このコードでやること: SSDSE-B-2026 (2012-2023 縦断) の出生数を用い、 「東京圏(東京・神奈川・埼玉・千葉)」 を処理群、 「東北 6 県」 を対照群と仮設定して、 事前期間の平行トレンドが成り立つかを線形回帰の交互作用項で検定します。

📥 入力例: SSDSE-B-2026.csv の出生数列を年・地域 別パネル形式へ整形

年度 地域 出生数 group 0 2014 東京都 110629 treat 1 2014 青森県 8853 control 2 2015 東京都 113194 treat ... 9 2023 福島県 9019 control
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import pandas as pd
import statsmodels.formula.api as smf

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': '年度', 'Prefecture': '地域', 'A4101': '出生数'})

treat = ['東京都', '神奈川県', '埼玉県', '千葉県']
control = ['青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県']
df = df[df['地域'].isin(treat + control)].copy()
df['group'] = df['地域'].isin(treat).astype(int)

# 事前期間(〜2019 年)で平行トレンドを検定
pre = df[df['年度'] < 2020]
model = smf.ols('出生数 ~ 年度 * group', data=pre).fit()
print(model.summary().tables[1])

📤 実行例

============================================================================== coef std err t P>|t| [0.025 0.975] ------------------------------------------------------------------------------ Intercept 6.746e+05 2.05e+06 0.330 0.743 -3.4e+06 4.75e+06 年度 -329.6825 1015.817 -0.325 0.746 -2352.857 1693.492 group 1.765e+06 3.24e+06 0.545 0.587 -4.68e+06 8.21e+06 年度:group -846.0526 1606.147 -0.527 0.600 -4044.972 2352.867 ==============================================================================

💬 結果の読み方 交互作用項「年度:group」の係数 −846.1 が「事前トレンドの傾き差」 で、 東京圏 4 都県の出生数は東北 6 県より年 846 人ずつ速く減っていた計算になる(2012〜2019 の 7 年で約 5,900 人)。 p = 0.600 で 有意ではない が、 標準誤差 1,606 は係数の約 2 倍あり、 同じ群の中で東京都と千葉県のように出生数の桁が違う県を並べているため検出力がほとんど無い。 「差がない」 と言える根拠ではないので、 次の event study で年ごとの差の動きを確かめてから DID に進む。 もし交互作用項が有意なら、 そもそも DID は使えない(dynamic DID や event study が必要)。

📊 イベントスタディプロット — 平行トレンドを「見る」

このコードでやること: 平行トレンドの仮定を統計的検定だけでなく年ごとの係数で確認する event study の係数表を作ります。 SSDSE 縦断データで、 基準年 2019 と各年の 2 時点 DID の係数 τ を並べ(図にするなら τ ± 1.96·se を年ごとに線でつなぐ)、 「事前は平行、 事後は処理効果で乖離」 が現れるかを確認します。

📥 入力例: 年度 × 地域 のパネル、 処理タイミング = 2020 年

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pandas as pd
import statsmodels.formula.api as smf

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': '年度', 'Prefecture': '地域', 'A4101': '出生数'})
treat = ['東京都', '神奈川県', '埼玉県', '千葉県']
control = ['青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県']
df = df[df['地域'].isin(treat + control)].copy()
df['group'] = df['地域'].isin(treat).astype(int)

# 基準年 2019 に対し、各年ダミー × group の係数を推定
years = sorted(df['年度'].unique())
coefs = []
for y in years:
    if y == 2019:                      # 基準年そのものは比較相手がないので 0 に固定
        coefs.append((y, 0.0, 0.0))
        continue
    sub = df[df['年度'].isin([2019, y])].copy()
    sub['post'] = (sub['年度'] == y).astype(int)
    m = smf.ols('出生数 ~ post + group + post:group', data=sub).fit()
    coefs.append((y, m.params['post:group'], m.bse['post:group']))

cdf = pd.DataFrame(coefs, columns=['年度', 'τ', 'se'])
print(cdf.round(1).to_string(index=False))

📤 実行例

年度 τ se 2012 6365.2 15165.9 2013 6634.3 15512.7 2014 5970.7 15790.7 2015 7020.1 16088.7 2016 5528.5 16127.6 2017 3905.2 15900.6 2018 2869.4 15799.2 2019 0.0 0.0 2020 -1186.3 15258.8 2021 -3279.7 14935.7 2022 -5194.5 14596.5 2023 -7210.8 14184.9

💬 結果の読み方 事前期間の τ は 2012 年 6,365 → 2015 年 7,020 → 2018 年 2,869 と基準年 2019 に向けて下がり続けており、東京圏 4 都県の出生数(2012 年平均 72,176 人 → 2019 年 63,488 人)が東北 6 県(10,946 人 → 8,623 人)より人数ベースで速く減っていたことを示す。2020 年以降の −1,186 → −7,211 は、この事前からの下り坂がそのまま延びた形に近く、「事前は平行・事後だけ乖離」という形にはなっていない。se は 14,000〜16,000 と τ の数倍あるのでどの年も 0 と区別できないが、それは平行の証明ではなく、県ごとの出生数の桁が違いすぎて検出力が無いということ。水準の差が大きい群どうしなら、出生数の対数や出生率に直してから比べるのが筋。

🧪 プラセボ検定 — 「偽の処理」を入れて頑健性チェック

このコードでやること: 平行トレンドの仮定が成り立つなら、 「実際には何も起きていない年に偽の処理を入れた DID」 は効果ゼロを推定するはず。 SSDSE 縦断で、 処理年を 2017 年と偽設定して τ を計算し、 「偽効果」 が出るか確認します。

📥 入力例: 2012-2019 の事前期間のみを用い、 仮想処理年 = 2017

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import pandas as pd
import statsmodels.formula.api as smf

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': '年度', 'Prefecture': '地域', 'A4101': '出生数'})
treat = ['東京都', '神奈川県', '埼玉県', '千葉県']
control = ['青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県']
# 事前期間(〜2019 年)だけを使い、偽の処理年 2017 を仮定
df = df[df['地域'].isin(treat + control) & (df['年度'] < 2020)].copy()

df['group'] = df['地域'].isin(treat).astype(int)
df['placebo_post'] = (df['年度'] >= 2017).astype(int)

m = smf.ols('出生数 ~ placebo_post * group', data=df).fit()
print(m.summary().tables[1])

📤 実行例

====================================================================================== coef std err t P>|t| [0.025 0.975] -------------------------------------------------------------------------------------- Intercept 1.069e+04 2944.962 3.630 0.001 4825.999 1.66e+04 placebo_post -1433.5111 4809.103 -0.298 0.766 -1.1e+04 8144.649 group 6.117e+04 4656.394 13.136 0.000 5.19e+04 7.04e+04 placebo_post:group -4045.5389 7603.860 -0.532 0.596 -1.92e+04 1.11e+04 ======================================================================================

💬 結果の読み方 placebo_post:group の係数 = -4045.5、 p = 0.596 で 有意でない。 つまり「事前期間内の偽の処理タイミング」 では有意な効果は検出されない。 ただし係数の向き(2017 年以降に東京圏側が約 4,000 人余分に減る)は上の event study で見えた事前の下り坂と同じで、 標準誤差 7,604 が大きいために有意にならないだけとも読めるので、 これだけで平行トレンドの裏付けとはしない。 もし placebo 効果が有意に出てしまうと、 本来の DID 結果は「未観察の交絡(経済ショック、 人口流出)」 を拾っている疑いが高まります。

🧮 数式に値を入れて手で計算する: 平行トレンド検証

合成データで政策前 3 期の処置/対照群トレンドを比較する。

Step 1: 群別データ

期処置対照差
t=-31082
t=-212102
t=-114122

Step 2: トレンド差

処置 変化 = 14-10 = 4 対照 変化 = 12-8 = 4 群間差は一定 (=2) → 平行トレンド成立 DID 仮定 OK

🐍 Python で再現

1
2
3
4
5
6
7
import numpy as np
treat = np.array([10, 12, 14])
ctrl = np.array([8, 10, 12])
diff = treat - ctrl
print(f"群間差: {diff}")
print(f"差の分散: {diff.var()}")
print(f"平行: {diff.var() < 0.01}")

📤 実行結果

群間差: [2 2 2] 差の分散: 0.0 平行: True

💬 手計算 (Step 2) と Python 出力が完全一致。 完全平行。

🐍 Python 実装

🎯 解説: SSDSE-B-2026 を読み込み、 「東京・大阪・愛知」を仮想的な処置群、 2022 年以降を介入後期間(post)と定義して DiD(差の差)回帰を実行する。 交互作用項 did の係数が ATT(処置群への平均処置効果)として平行トレンド仮定の下で因果効果に解釈できる。
📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import pandas as pd
import statsmodels.formula.api as smf

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year'})
# 仮想的な処置群フラグ(東京・大阪・愛知 を処置群とする例)
df['treated'] = df['Prefecture'].isin(['東京都', '大阪府', '愛知県']).astype(int)
df['post']    = (df['year'] >= 2022).astype(int)
df['did']     = df['treated'] * df['post']
model = smf.ols('A4101 ~ treated + post + did', data=df).fit()
print(model.summary().tables[1])  # did の係数が ATT
📥 入力例: data/raw/SSDSE-B-2026.csv(47 都道府県 × 12 年 = 564 行の年次パネル) 使用列: Prefecture(都道府県)/ year(年度)/ A4101(出生数) 処置群: 東京都・大阪府・愛知県 / post: 2022 年以降
📤 実行例(実測) coef std err t P>|t| [0.025 0.975] ------------------------------------------------------------------------------ Intercept 1.609e+04 674.593 23.847 0.000 1.48e+04 1.74e+04 treated 6.248e+04 2670.116 23.400 0.000 5.72e+04 6.77e+04 post -3491.5545 1652.408 -2.113 0.035 -6737.230 -245.879 did -1.014e+04 6540.421 -1.551 0.122 -2.3e+04 2704.143 → 交互作用項 did が ATT。p = 0.122 で有意ではないので、 「処置群だけに効果があった」とは言えない。
💬 読み方: 交互作用項 did が処置効果(ATT)。 実測では did = -1.014e+04、 p = 0.122 で、 処置群(東京・大阪・愛知)で 2022 年以降に出生数(A4101)が対照群比で有意に動いたとは言えない。 仮に有意だったとしても、 平行トレンド仮定(介入前のトレンドが処置群と対照群で平行)が成立して初めて因果効果と解釈できる。 必ずプリトレンド可視化で検証すること。

▶ 実行 を押せばこのページの中でそのまま動きます(ライブラリもデータも同梱済みで、 準備は要りません)。 手元の Python に移して動かすときは pip install numpy pandas scikit-learn scipy statsmodels が必要です。 読んでいるデータは data/raw/SSDSE-B-2026.csv。 日本語を含むので encoding='cp932' の指定を落とさないでください。

🐍 Python 実装 — 完全強化版

🎯 解説: 処理群を東京圏 4 都県、 対照群を東北 6 県として、 事前期間 2014〜2019 年の log(総人口) に「年度 × 処理群」の交互作用を入れた OLS を当て、 事前トレンドの差(pre-trend)を検定する。 標準誤差は県クラスタで計算する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import numpy as np
import statsmodels.formula.api as smf

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
treat = ['東京都', '神奈川県', '埼玉県', '千葉県']                     # 処理群: 東京圏 4 都県
control = ['青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県']   # 対照群: 東北 6 県
pre = df[df['Prefecture'].isin(treat + control)
         & df['SSDSE-B-2026'].between(2014, 2019)].copy()          # 事前期間 2014〜2019 年
pre['year'] = pre['SSDSE-B-2026'] - 2014
pre['treat'] = pre['Prefecture'].isin(treat).astype(int)
pre['log_pop'] = np.log(pre['A1101'].astype(float))
print('行数 =', len(pre), '(10 都県 × 6 年)')

# 平行トレンド仮定の代表的計算: 事前期間の「年度 × 処理群」交互作用(トレンドの差)を検定
m = smf.ols('log_pop ~ year * treat', data=pre).fit(
    cov_type='cluster', cov_kwds={'groups': pre['Prefecture']})   # 同じ県の 6 年分を 1 クラスタに
b = m.params
print(f'対照群の傾き year       = {b["year"]:+.5f}(年 {b["year"]*100:+.2f}%)')
print(f'処理群の傾き year+交互作用 = {b["year"] + b["year:treat"]:+.5f}(年 {(b["year"] + b["year:treat"])*100:+.2f}%)')
print(f'トレンドの差 year:treat  = {b["year:treat"]:+.5f}  p = {m.pvalues["year:treat"]:.4g}')
📥 入力例: data/raw/SSDSE-B-2026.csv 使用列: Prefecture、 SSDSE-B-2026(年度)、 A1101(総人口) 対象: 東京圏 4 都県 + 東北 6 県 × 2014〜2019 年(60 行)
📤 実行例(実測) 行数 = 60 (10 都県 × 6 年) 対照群の傾き year = -0.00892(年 -0.89%) 処理群の傾き year+交互作用 = +0.00415(年 +0.42%) トレンドの差 year:treat = +0.01308 p = 6.848e-10

💬 事前期間の 6 年間で、 東北 6 県の総人口は年 0.89% ずつ減り、 東京圏 4 都県は年 0.42% ずつ増えていた。 傾きの差は年 1.31% ポイントで p = 6.8e-10 と、 「事前トレンドの差なし」ははっきり棄却される。 この 2 群で 2020 年以降を DiD にかけると、 もともとの 1.3% ポイントの開きが毎年そのまま「処理効果」に上乗せされるので、 対照群を東北 6 県にする設計自体を見直すか、 群ごとのトレンドを入れたモデルにする必要がある。

用途別の追加実装:

🎯 解説: 2023 年・47 都道府県の総人口と出生数を標準化し、 k-means で 4 クラスタに分類して都道府県類型を作る。 DiD 解析で「比較可能な対照群」を選ぶ前処理の例。
📥 入力例: data/raw/SSDSE-B-2026.csv(2023 年・47 都道府県) 使用列: A1101(総人口)、 A4101(出生数) 前処理: StandardScaler(平均 0、 分散 1)
1
2
3
4
5
6
7
8
9
10
# 標準化と簡易クラスタリングの例(2023 年・47 都道府県)
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

d = df[df['SSDSE-B-2026'] == 2023].copy()
X = d[['A1101', 'A4101']].astype(float).values
Xs = StandardScaler().fit_transform(X)
km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(Xs)
d['cluster'] = km.labels_
print(d[['Prefecture', 'A1101', 'A4101', 'cluster']].head(10))
📤 実行例(実測) Prefecture A1101 A4101 cluster 0 北海道 5092000 24430 3 12 青森県 1184000 5696 0 24 岩手県 1163000 5432 0 36 宮城県 2264000 12328 0 48 秋田県 914000 3611 0 60 山形県 1026000 5151 0 72 福島県 1767000 9019 0 84 茨城県 2825000 14898 0 96 栃木県 1897000 9958 0 108 群馬県 1902000 9950 0

💬 表示された先頭 10 行では北海道だけが 3 番で、東北 6 県と北関東 3 県はすべて 0 番に入った。47 県全体では 0 番が 37 県、3 番が北海道・千葉・静岡・兵庫・福岡の 5 道県、1 番が埼玉・神奈川・愛知・大阪の 4 府県、2 番が東京都だけになる。直前の検定で使った処理群の東京圏 4 都県は 1・2・3 番の 3 つに散り、対照群の東北 6 県はすべて 0 番なので、2 群は規模の面でもそもそも似ていない。同じクラスタ内から処理・対照を選ぶなら、東京圏の比較相手は大阪・愛知などになる。

🐍 linearmodels で DID — パネルデータ専用ライブラリ

このコードでやること: 計量経済学パッケージ linearmodels の PanelOLS を使い、 SSDSE 縦断データで固定効果付き DID を推定します。 これにより、 「県固有の時間不変な交絡(地形、 文化、 産業構造)」 を吸収できる、 より厳密な DID が実行できます。

📥 入力例: 47 県 × 10 年のパネル、 県と年度を MultiIndex

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import pandas as pd
from linearmodels.panel import PanelOLS

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': '年度', 'Prefecture': '地域', 'A4101': '出生数'})
treat = ['東京都', '神奈川県', '埼玉県', '千葉県']
control = ['青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県']
df = df[df['地域'].isin(treat + control)].copy()
df['D'] = (df['地域'].isin(treat) & (df['年度'] >= 2020)).astype(int)

df = df.set_index(['地域', '年度'])
m = PanelOLS.from_formula('出生数 ~ D + EntityEffects + TimeEffects', data=df)
res = m.fit(cov_type='clustered', cluster_entity=True)
print(res.summary)

📤 実行例

PanelOLS Estimation Summary ================================================================================ Dep. Variable: 出生数 R-squared: 0.6044 Estimator: PanelOLS R-squared (Between): -0.0803 No. Observations: 120 R-squared (Within): 0.6229 Date: Sat, Sep 26 2026 R-squared (Overall): -0.0740 Time: 10:55:06 Log-likelihood -1061.6 Cov. Estimator: Clustered F-statistic: 149.72 Entities: 10 P-value 0.0000 Avg Obs: 12.000 Distribution: F(1,98) Min Obs: 12.000 Max Obs: 12.000 F-statistic (robust): 26.439 P-value 0.0000 Time periods: 12 Distribution: F(1,98) Avg Obs: 10.0000 Min Obs: 10.0000 Max Obs: 10.0000 Parameter Estimates ============================================================================== Parameter Std. Err. T-stat P-value Lower CI Upper CI ------------------------------------------------------------------------------ D -9004.5 1751.2 -5.1419 0.0000 -1.248e+04 -5529.3 ============================================================================== F-test for Poolability: 1565.9 P-value: 0.0000 Distribution: F(20,98) Included effects: Entity, Time

💬 結果の読み方 県固定効果 + 時間固定効果を入れた DID 推定値 τ = -9004 (95% CI: -12480 ~ -5529、 p < 0.0001)。 標準誤差を「県クラスタ」 でロバスト計算しており、 同一県の時間相関を考慮済み。 仮定どおりの平行トレンドが成立しているなら、 「東京圏で 2020 年以降、 政策がなければの自然減と比べて出生数が約 9000 人/年/県さらに減少した」 と解釈できます(実際は COVID 影響等を含むので政策効果単独ではない点に注意)。 ただし上の event study のとおり事前期間から群間差は年 846 人前後のペースで縮んでおり、 事前期間と事後期間の中心(2015.5 年と 2021.5 年)の 6 年分だけでも約 5,100 人は、 この事前の下り坂の延長で説明できてしまう。

⚠️ 平行トレンド仮定固有の落とし穴(実装での詰みポイント 4 件)

下の「実務で本当に困る 7 件」「拡張手法」と重ならない、 SSDSE-B-2026 のような都道府県パネルで DiD を実装する瞬間に詰まる典型を 4 件追加で示す。

❌ プリトレンドを「目視で平行」と判断
折れ線を 2 本並べて「平行に見える」では検証にならない。 SSDSE-B-2026 で処理群 (例: 大阪) と対照群 (例: 兵庫) を比較するなら、 (year × treated) 交互作用係数を事前期間で 0 と検定し、 95%CI を Honest DID で報告する。 目視は p-hacking の温床。
❌ 時間変化する交絡 (TWFE 推定量の罠)
介入と同時に別の政策ショックが起きると識別不可。 SSDSE-B-2026 だと COVID-19 (2020〜) と他政策が同時期に起きており、 TWFE が ATT を表さない (Goodman-Bacon 2021)。 Callaway-Sant'Anna で群×時点別 ATT(g,t) に分解する。
❌ Staggered adoption の負の重み
2 段階以上の処理タイミング (例: 47 県で異なる政策施行年) で TWFE は「すでに処理済み群が対照群として使われる」歪みを持ち、 平均 ATT に負の重みが付く (de Chaisemartin 2020)。 二期間 DiD に分解するか dCDH 推定量を使う。
❌ Anticipation 効果で事前期間が汚染
介入を予期した行動変化があると、 「事前期間」 にも処理効果が混入し、 プリトレンド検定が見かけ上 OK でも実は両方歪んでいる。 公示 / 法案提出時点を t=0 として定義し直し、 anticipation lag を変数に組み込む。
🛡 防御策まとめ:① 事前 3 期間以上のサンプルを確保、 ② TWFE と Callaway-Sant'Anna 両方で推定し違いを報告、 ③ Honest DID で「仮定の脆さ」を信頼区間に織り込む、 ④ 共通ショック (COVID 等) は placebo test で必ず検査、 の 4 点を pipeline に固定する。

⚠️ 平行トレンド仮定の落とし穴 — 実務で本当に困る 7 件

  1. 事前トレンド検定の low power — 期間が短い・ノイズが大きいと、 本当に違いがあっても検出できない。 「p > 0.05 だから平行」 とは断定できない。
  2. 処理予期効果 (anticipation) — 政策発表前にエージェントが行動を変えると、 事前期間にも処理効果が混ざる。 「公示前期間」 を厳密に定義する。
  3. Staggered adoption — 処理タイミングが群ごとに違うと標準 DID は negative weights を持ち、 平均効果が誤推定される。 Callaway-Sant'Anna 推定量を使う。
  4. 外れ値による視覚的判断ミス — 1 県の極端な変動で「平行に見えない」 と誤判定するケース。 ロバスト推定や trim を併用する。
  5. 線形性の仮定 — 「年度: group の交互作用 = 0」検定は線形トレンドのみ検証する。 二次トレンドや構造変化は別途検査が必要。 (約 115 文字)
  6. 処理群選択バイアス — 処理は無作為割付でないので、 「もともと違うトレンドの群」 同士を比べている可能性。 マッチングで揃える。
  7. 共通ショックの存在 — COVID-19 のように両群を同時に襲うショックがあると、 DID の差は「処理 + 群差ショック」 で混ざる。 placebo で要確認。 (約 115 文字)

🆕 平行トレンド仮定の現代的拡張 — Synthetic DID / Honest DID

2020 年代に入り、 平行トレンド仮定の脆弱性に対応する新手法が次々登場しています。 主要な 3 系統を整理します。

手法提唱年アイデア対応する弱点
Synthetic Control2003 (Abadie)対照群を加重平均で「合成」し、 処理前ぴったり合わせる対照群選択の恣意性
Synthetic DID2021 (Arkhangelsky 他)DID と Synthetic Control を融合、 時間重みも最適化事前トレンド差の頑健化
Honest DID2023 (Rambachan-Roth)事前トレンド差の最大幅を許容し、 信頼区間を「正直に」 拡げる平行トレンドの完全成立を仮定しない
Callaway-Sant'Anna2021処理タイミングが異なる群の効果を分けて推定Staggered adoption の negative weights
de Chaisemartin-D'Haultfœuille2020TWFE 推定量が一般 ATT を表さない問題を診断TWFE の解釈問題

これらの手法は、 平行トレンド仮定が「グレースケール」 の問題 — 厳密には成り立たないかもしれないが、 そのズレが結果にどれくらい効くか — として扱うパラダイムシフトを反映しています。 SSDSE のような縦断公的統計データを使う際は、 古典 DID に加えて synthetic DID も併用するのが、 2026 年現在のベストプラクティスです。

📜 平行トレンド仮定の歴史と DID の発展

DID の起源はジョン・スノウ (John Snow) による 1854 年ロンドンコレラ流行調査に遡ります。 スノウは「水源の違う 2 地域の死亡率変化」 を比較し、 飲料水中のコレラ菌仮説を裏付けました。 これは事実上「平行トレンドの仮定」 を暗黙に置いた最初の準実験です。

年代人物・出来事貢献
1854ジョン・スノウロンドンコレラ調査で DID 的発想
1985Ashenfelter & Card職業訓練効果の DID 推定で現代的定式化
1994Card & Krueger最低賃金引上げの雇用への効果を DID で分析
2003AbadieSynthetic Control 法を提唱
2020-22Callaway/Sant'Anna 他Staggered DID の理論再整備
2021CardDID 実証研究でノーベル経済学賞

2021 年 David Card のノーベル経済学賞は、 平行トレンド仮定に基づく DID 推定の経済学・社会科学への決定的な影響を認めた出来事です。 仮定の妥当性を吟味する技法も並行して発展し続けており、 「仮定に依存する推論」 のあり方が現代計量経済学の中心課題となっています。

🗺 概念マップ

中央の平行トレンド(parallel trends)は DID 推定の前提であり、 その確かめ方として 処置前トレンド比較(群ごとの傾きを並べる)、 処置群×時点交互作用(傾きの差を回帰で検定する)、 event-study 検定(時点ごとの係数が処置前にゼロ付近か見る)がつながる。 仮定が疑わしいときの出口として、 処置時期がずれる場合の Callaway-Sant'Anna 推定量と、 対照群を重み付きで作り直す合成統制法へ橋が架かる。

parallel trends DID 推定の前提 event-study 検定 処置群×時点交互作用 処置前トレンド比較 Callaway-Sant'Anna 合成統制法へ橋渡し

🔗 隣接手法への橋渡し

平行トレンド仮定は DID 推定の前提条件であり、 仮定が破れた場合に隣接手法へ移行する判断軸として機能する。

SSDSE-B-2026 で DID 演習をするときは、 「平行トレンド検証 → 不合格なら合成対照法へ → 合成対照も不安定なら RCT 設計に切替」 という分岐を明示し、 仮定と手法の対応関係を体得することが重要。

🌳 手法選択フロー

DID を使う前に、 平行トレンド仮定について次の順に確かめる。

  1. 事前期間は何年あるか:処置前が 1〜2 年しかないと傾きを比べられない。 SSDSE-B-2026 で 2020 年度を処置とすれば事前は 2012〜2019 年度の 8 年。
  2. どの尺度で比べるか:県の規模が桁違いなら、 人数のまま比べると大きい県に検定が支配される。 対数(変化率)で比べるか、 率の指標に直す(⚠️ 追記解説②の⑤)。
  3. 事前トレンドは平行か:年度 × 群の交互作用とイベントスタディで確かめる。
    • 傾きの差がはっきりある(東京圏 vs 東北 6 県の総人口で年 1.31 ポイント、 p = 6.8e-10)→ 対照群を選び直す(傾きの近い県どうしを組む、 🧮 追記解説④では差 0.024 ポイント・p = 0.231)か、 合成統制法へ。
    • 有意差なしでも検出力が低い(事前の係数の標準誤差が係数の数倍)→ 「平行の証明」とは扱わず、 Honest DiD で違反の大きさを変えたときの結論の変化を報告する。
  4. 処置の時期は群ごとにずれるか:ずれるなら単純な TWFE は使わず、 Callaway-Sant'Anna などの推定量にする。
  5. 処置と同時に別のショックがないか:2020 年度のように全国的なショックと重なるなら、 偽の処置年のプラセボ検定と、 処置の影響を受けない別の結果変数で効果がゼロになるかを確かめる。

🧭 追記解説①:直感 ― 「観測できない反事実」をどう埋めるか

既存の「🎨 直感で掴む」ではレーンの比喩で全体像を示しました。 ここでは別の角度から、 平行トレンド仮定が「反事実(counterfactual)の穴埋め規則」であることを掘り下げます。

DiD が答えたい問いは「処置群に処置がなかったら、 結果はどう推移したか」です。 しかしその世界は絶対に観測できません(同じ主体を同時に処置あり/なしの両方で観測できない、 因果推論の根本問題)。 平行トレンド仮定は、 この観測不能な穴を「対照群が実際に描いた変化量(傾き)で埋めてよい」と宣言する規則です。 だからこそ DiD は「水準の差」ではなく「差の差(変化量の差)」を効果とみなします。

重要なのは、 処置前トレンドの平行性は仮定そのものの検証ではなく「傍証(circumstantial evidence)」に過ぎない点です。 裁判で言えば、 現場から容疑者の指紋が出たようなもの。 有力な状況証拠ではあるが、 犯行を直接目撃したわけではありません。 処置前で平行だったという事実は、 「処置後も平行だっただろう」という信念を補強するだけで、 証明はしません。

💡 一文でいうと:平行トレンド仮定とは「対照群の変化量を、 処置群の反事実の変化量として借用する」という約束であり、 処置前の平行性はその約束が妥当そうだと示す傍証にすぎない。

⚠️ 追記解説②:落とし穴(重要)― 平行に見えても安心できない7つの理由

平行トレンドは「検定に通ったから OK」で済む仮定ではありません。 既存の落とし穴セクションと重複しない角度で、 特に誤解されやすい7点を整理します。

落とし穴なぜ危険か対処の方向
① 検証不能性反事実(処置がなかった処置群)は原理的に観測できない。 「証明」は不可能で、 できるのは傍証集めだけ。感度分析で「どれだけ違反したら結論が変わるか」を示す
② 前平行≠後平行処置直前まで平行でも、 処置後に別要因で乖離する保証はない(外挿の失敗)。別対照群・別期間での頑健性確認
③ 対照群の選択恣意的に「平行に見える群」を選ぶと確証バイアス。 選び方で結論が動く。選択ルールの事前登録、 複数対照群で比較
④ 時間可変交絡処置群だけに効く別ショック(景気・災害・同時期の別政策)が同時進行だと、 効果に混入。共変量調整・イベント時系列の精査
⑤ 関数形依存水準 $Y$ で平行でも対数 $\log Y$ では非平行(逆も然り)。 平行性は尺度に依存する。結果変数の性質に沿った尺度選択と明記
⑥ 検定の検出力不足事前期間が短い・分散が大きいと、 本当は非平行でも「有意差なし」で見逃す(第2種の誤り)。検出力・信頼区間を報告、 「有意差なし≠平行」と自覚
⑦ 予期(anticipation)効果政策の事前公表で、 処置前に主体が行動を変え、 処置前トレンドが歪む。公表時点を処置時点とする、 直前期を基準から外す

特に強調したいのは⑤と⑥です。 ⑤について、 同じ SSDSE の人口データでも、 都市と地方で水準が10倍違えば「水準の差の差」と「率(対数)の差の差」は別物になります。 「平行トレンドが成り立つかどうか」はデータではなく尺度の選択と一体である、 という点は初学者が最も見落とします。 ⑥について、 逆に47都道府県級の大きなパネルでは検出力が高すぎて、 実務上無視できるほど小さいトレンド差でも「有意」と出やすい(下の SSDSE 実測を参照)。 「p 値が小さい=致命的な違反」でも「p 値が大きい=平行が保証された」でもありません。 傾きの差の大きさを効果量と並べて解釈することが不可欠です。

🧪 実データで確かめる — 水準と対数で、 傾きの差の向きが逆になる

⑤ の「平行性は尺度に依存する」を、 SSDSE-B-2026 の出生数で確かめる。 出生数が 1 県平均 6〜7 万人の東京圏と 1 万人前後の東北では、 同じ「1 年で 5% 減」でも人数では東京圏の減り方が何倍も大きく見える。

🎯 このコードでやること:🧮 と同じ東京圏 4 都県と東北 6 県で、 2012〜2019 年度の出生数の傾きの差(年度 × 群の交互作用)を、 人数のままと対数に直した場合の 2 通りで推定する。 県の固定効果を入れ、 標準誤差は県ごとのクラスタにする。

📥 入力例 SSDSE-B-2026 から 10 都県 × 2012〜2019 年度(80 行) 年度 都道府県 出生数 2019 東京都 101,818 2019 青森県 7,170 … 処置群 treat=1: 埼玉・千葉・東京・神奈川 / 対照群 treat=0: 東北 6 県
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
import numpy as np
import statsmodels.formula.api as smf

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
TREAT = ['埼玉県', '千葉県', '東京都', '神奈川県']                          # 処置群(東京圏)
CTRL = ['青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県']          # 対照群(東北 6 県)
d = df[df['都道府県'].isin(TREAT + CTRL) & df['年度'].between(2012, 2019)].copy()
d['treat'] = d['都道府県'].isin(TREAT).astype(int)
d['t'] = d['年度'] - 2012
d['log出生数'] = np.log(d['出生数'])

for y, label in [('出生数', '水準(人)'), ('log出生数', '対数')]:
    m = smf.ols(f'{y} ~ t*treat + C(都道府県)', data=d).fit(
        cov_type='cluster', cov_kwds={'groups': d['都道府県']})
    b0, b1 = m.params['t'], m.params['t:treat']
    print(f'{label:8s} 対照群の傾き {b0:9.4f}  処置群との傾きの差 {b1:9.4f}  p = {m.pvalues["t:treat"]:.3f}')

g = d.groupby(['treat', '年度'])['出生数'].mean().unstack(0)
print('2012→2019 の 1 県平均: 東京圏', int(g.loc[2012, 1]), '→', int(g.loc[2019, 1]),
      f'({g.loc[2019,1]/g.loc[2012,1]-1:+.1%})', '/ 東北', int(g.loc[2012, 0]), '→', int(g.loc[2019, 0]),
      f'({g.loc[2019,0]/g.loc[2012,0]-1:+.1%})')
📤 実行例(実測) 水準(人) 対照群の傾き -329.6825 処置群との傾きの差 -846.0526 p = 0.000 対数 対照群の傾き -0.0347 処置群との傾きの差 0.0152 p = 0.002 2012→2019 の 1 県平均: 東京圏 72175 → 63487 (-12.0%) / 東北 10946 → 8623 (-21.2%)

💬 人数のままだと東京圏の傾きは東北より年 846 人急(差 −846.05、 p < 0.001)で、 「東京圏のほうが速く減っている」。 対数に直すと符号が逆になり、 東京圏の減り方は東北より年 1.52 ポイント緩い(差 +0.0152、 p = 0.002)。 実際 2012→2019 の 1 県平均は東京圏 −12.0%、 東北 −21.2% で、 率で見れば東北のほうが速く減っている。 同じデータでも、 どちらの尺度で平行を求めるかで「どちらの群が速く減っているか」まで入れ替わる。 どちらの尺度でも平行でないので、 この 2 群の DID はどちらの尺度でも事前の傾きの差を効果と取り違える。 なお 🧮 の交互作用検定(p = 0.600)は県の固定効果を入れず、 県どうしの出生数の桁の違いが誤差に入っていたため差を検出できなかった。 クラスタは 10 県しかないので、 p 値はおおよその目安として読む。

🚀 追記解説③:発展 ― 前平行を疑い、頑健化する現代的ツール

「平行トレンドは厳密には成り立たない」を出発点に、 2010年代後半以降の計量経済学が整えてきた道具立てを俯瞰します。 用語は本サイトの関連ページ(下節)と対応します。

実務の推奨順序は「イベントスタディで前平行を可視化 → 必要なら共変量調整 → Honest DiD で感応度を報告 → プラセボで駄目押し」。 単一の p 値に頼らず、 複数の角度から仮定の妥当性を束ねるのが現代的作法です。

🧮 追記解説④:SSDSE-B-2026 実測 ― 対照群の選び方で結論が動く

落とし穴③(対照群の選択)と⑥(検出力)を、 SSDSE-B-2026(47都道府県 × 2012-2023、 cp932)の実データで確認します。 結果変数は総人口 A1101 の対数 $\log(\text{A1101})$、 処置前期間を 2012-2019 とし、 各群の年率トレンド(対数の年次傾き)と、 都道府県固定効果を入れた「年次 × 群」交互作用項の $p$ 値を比較しました(数値はすべて実測。 群分けは教材用の例示)。

対比(処置群 vs 対照群)処置群 傾き/年対照群 傾き/年差交互作用 p平行性
三大都市圏8県 vs 残り39県+0.169%-0.544%0.713 pt<0.001✗ 明確に違反
東北6県 vs 中国5県-0.843%-0.511%0.332 pt<0.001✗ 違反
中位傾きで揃えた10県 vs 10県-0.499%-0.475%0.024 pt0.231○ 棄却されず

読み取り。 経済構造が違う群(都市圏 vs 地方、 東北 vs 中国)を機械的にぶつけると、 処置前トレンドはそもそも平行でない(差 0.3〜0.7 ポイント/年、 $p<0.001$)。 一方、 処置前の傾きが近い都道府県どうしをマッチングして群を作ると、 傾き差は 0.024 ポイント/年まで縮まり、 交互作用は非有意($p=0.231$)になります。 同じデータでも「誰を対照にするか」で平行トレンドの成否が反転するという、 落とし穴③の生きた実例です。

同時に検出力(落とし穴⑥)の注意も見えます。 47都道府県 × 8年という比較的大きなパネルでは、 わずか 0.3 ポイント/年の傾き差でも $p<0.001$ になります。 逆に、 マッチング後に「$p=0.231$ だから平行」と早合点するのも禁物で、 非有意は「違反を検出できなかった」以上を意味しません。 傾き差の大きさ(0.024 pt/年は実務的に無視できる水準か)まで含めて判断してください。 なお、 ここで対数を用いたのは落とし穴⑤への配慮です。 水準(人)のままだと都市部の大きな値に検定が支配され、 別の結論になり得ます。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import pandas as pd, numpy as np
import statsmodels.formula.api as smf

# SSDSE-B-2026: cp932 / 2行目の英語ヘッダをskip
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'Year'})
pre = df[(df['Year'] >= 2012) & (df['Year'] <= 2019)].copy()
pre['logpop'] = np.log(pre['A1101'])
pre['yearc'] = pre['Year'] - 2012

# 三大都市圏を処置群に見立てた例(傾きが全く違う=前平行が破れる)
T = ['埼玉県','千葉県','東京都','神奈川県','愛知県','大阪府','京都府','兵庫県']
pre['grp'] = pre['Prefecture'].isin(T).astype(int)

# 県固定効果 + 年次×群 の交互作用が事前トレンド差の検定
m = smf.ols('logpop ~ yearc*grp + C(Prefecture)', data=pre).fit()
print(m.params['yearc:grp'], m.pvalues['yearc:grp'])  # 係数≈0.00713, p<0.001
📤 実行例(実測) 0.007134324420646543 3.6400556841632995e-37

💬 yearc:grp の係数 0.00713 は、log 人口の年あたり変化が三大都市圏 8 都府県ではそれ以外より 0.0071 大きい、つまり毎年およそ 0.7 ポイントずつ成長率の差が開いていることを表す。2012〜2019 の 7 年で積み上げると約 5% の差になり、p=3.6e-37 は前平行トレンドがはっきり崩れていることを示す。ただしこの p は県内の年次相関を無視した通常の標準誤差によるもので過小になりがちなので、cov_type='cluster' で県単位にクラスタリングしても差が残るかを確かめるとよい。

※ 上記の傾き・p 値は SSDSE-B-2026 の実測値です。 処置群/対照群の分け方は概念説明のための架空の設定(実在の政策処置ではありません)。