論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
差分の差分法(DiD)
Difference-in-Differences (DiD)
処置群と対照群の前後差を比較する準実験的因果推論手法。共通トレンド仮定が鍵。
因果推論DiDDiD差分の差分DID
📍 文脈💡 30秒結論

📍 あなたが今見ているもの

論文中に 「差分の差分法(DiD)」として登場する用語。

差分の差分法(DiD) とは:処置群と対照群の前後差を比較する準実験的因果推論手法。共通トレンド仮定が鍵。

💡 30秒で分かる結論

📖 包括的解説 — この概念を完全マスター

📍 学習の3ステップ

  1. 定義を理解する:この概念は何か? 数式や条件を確認
  2. 具体例を見る:実データ(SSDSE 等)で計算してみる
  3. 応用する:自分のデータに適用、 結果を解釈

🔧 Python実装パターン

🎯 解説: DID(差の差分析)は政策効果を測る手法。 SSDSE-B-2026 を 2 時点で見立て、 「処置群(政策実施県)と対照群の差」の「処置前後の差」を比較する。 トレンド共通の仮定が成立する場合のみ妥当。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 基本パターン
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import seaborn as sns

# データ読み込み
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932')

# 基本統計量
df.describe()

# 可視化
sns.pairplot(df[['食料費', '教育費', '住居費']])
plt.show()
📥 入力例: data/raw/SSDSE-B-2026.csv 処置群: 東京・大阪・愛知(仮想政策実施) 対照群: その他 44 県 指標: 1人当たり県民所得
📤 実行例: 処置群 (Before): 380 万円 処置群 (After): 410 万円 (+30) 対照群 (Before): 290 万円 対照群 (After): 310 万円 (+20) DID = +30 - +20 = +10 万円
💬 読み方: DID 推定値 +10 万円が「政策の純効果」と解釈される。 ただし「もし政策がなかったら処置群も対照群と同じトレンドだった」という共通トレンド仮定が必要。 違反すれば偽の効果を誤検出する。

📚 統計概念マップでの位置

このページの上にある3つの概念マップ(関係マップ、 包含マップ、 ツリーマップ)でこの概念の位置づけが視覚的に分かります。 関連手法を辿って学習を進めましょう。

🎯 SSDSE-B-2026 で挑戦

統計データ活用コンペティションのSSDSE-B-2026データは、 47都道府県の社会経済データ。 この概念を使って以下のような分析ができます:

💡 よく使うコマンド集

機能 Python (pandas) Python (scipy)
要約統計df.describe()stats.describe()
平均df.mean()np.mean()
標準偏差df.std()np.std()
相関df.corr()stats.pearsonr()
t検定stats.ttest_ind()
回帰stats.linregress()
分布フィッティングstats.norm.fit()

🚧 一般的な落とし穴と対策

📊 結果報告の標準フォーマット

🌐 関連分野での応用

🎓 さらに学ぶための文献

🔗 統計用語ネットワーク

この概念は、 他の多くの統計概念と密接に関連しています。 ジャストインタイム型学習では、 必要に応じて関連用語へジャンプしながら全体像を構築します。

主要な関連概念のグループ

グループ 主要概念
記述統計平均、 中央値、 最頻値、 分散、 標準偏差、 共分散、 相関係数
可視化ヒストグラム、 散布図、 箱ひげ図、 ヒートマップ
推測統計標本平均、 標準誤差、 信頼区間、 p値、 有意水準
確率分布正規分布、 t分布、 χ²分布、 F分布、 二項分布
仮説検定t検定、 F検定、 χ²検定、 ノンパラ検定
回帰単回帰、 重回帰、 OLS、 Ridge、 LASSO
分類ロジスティック回帰、 決定木、 SVM、 k-NN
教師なし学習クラスタリング、 PCA、 因子分析
時系列ARIMA、 VAR、 指数平滑法、 自己相関
因果推論DiD、 IV、 傾向スコア、 交絡変数
前処理標準化、 正規化、 欠損値処理、 多重共線性対策
評価R²、 残差、 CV、 RMSE、 効果量

学習順序の推奨

  1. 記述統計(平均、 分散、 標準偏差)
  2. 可視化(ヒストグラム、 散布図)
  3. 確率分布(正規分布)
  4. 推測統計(標準誤差、 信頼区間、 p値)
  5. 仮説検定(t検定、 χ²検定)
  6. 相関と回帰(単回帰、 重回帰)
  7. 多変量解析(PCA、 クラスタリング)
  8. 機械学習(決定木、 RF、 NN)
  9. 時系列・因果推論(応用)

📝 実践練習 — SSDSE-B-2026 で挑戦

初級課題

  1. 東北6県の家計食料費の基本統計量を計算
  2. 食料費のヒストグラムを描く
  3. 食料費と教育費の散布図を描く
  4. 都道府県を「東日本/西日本」に分け、 平均を比較

中級課題

  1. 家計支出 5項目で相関行列を作成、 ヒートマップ可視化
  2. 食料費 → 教育費の単回帰を実行、 残差分析
  3. 家計5項目で PCA を実施、 バイプロット表示
  4. k-means (k=3) で都道府県をクラスタリング、 解釈

上級課題

  1. 地域別の家計パターンに有意差があるか ANOVA で検定
  2. 重回帰で教育費を予測、 多重共線性を VIF で確認
  3. Ridge/LASSO で正則化、 CV で α を最適化
  4. 階層クラスタリングと Ward 法で都道府県を分類、 デンドログラム作成

📚 統計学習の総合ガイド

🎯 学習目標

このページの概念をマスターすることで、 以下のスキルが身につきます:

📊 SSDSE-B-2026 データの構造

このコンペの主要データセット(SSDSE-B-2026)の構造:

🔍 主要な変数群

カテゴリ 変数例
人口総人口、 年齢別人口、 性別人口
人口動態出生数、 死亡数、 合計特殊出生率、 婚姻数
気候気温、 降水量、 降水日数
教育幼小中高校数、 教員数、 生徒数、 大学進学率
経済求職件数、 求人件数、 旅館数
医療病院数、 診療所数、 歯科診療所
家計消費支出、 食料費、 住居費、 教育費等の項目別

💡 ジャストインタイム型学習

このガイドは「必要なときに必要な知識」を提供する設計:

🛠️ Python データサイエンス環境

🎯 解説: DID を回帰で推定するには「処置ダミー × 時期ダミー」の交差項の係数を見る。 統計検定(t 検定)で効果の有意性も確認できる。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 必須ライブラリのインストール
pip install pandas numpy scipy statsmodels scikit-learn matplotlib seaborn

# 標準的なインポート
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_squared_error

# 日本語表示の設定(matplotlib)
plt.rcParams['font.family'] = 'Hiragino Sans'
plt.rcParams['axes.unicode_minus'] = False

# データ読み込み(SSDSE は cp932 エンコーディング)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932')
print(df.shape)
print(df.head())
print(df.describe())
📥 入力例: data/raw/SSDSE-B-2026.csv formula = '所得 ~ 処置 + 時期 + 処置*時期'
📤 実行例: Coefficients: 処置 +90.0 (処置群と対照群の常時差) 時期 +20.0 (時間トレンド) 処置*時期 +10.0 ★DID 推定値 p (DID) = 0.032
💬 読み方: 交差項の係数 +10 が DID 効果、 p < 0.05 で有意。 標準誤差はクラスタロバスト(県でクラスタリング)にするのが標準。 サンプルサイズが小さいと検出力が弱い。

🌟 効果的なEDAテンプレート

🎯 解説: 共通トレンド仮定を視覚的に確認する。 処置前の期間で処置群と対照群が並行に動いていれば、 仮定を支持。 並行でなければ DID の前提が崩れる。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def quick_eda(df, target=None):
    """探索的データ分析の基本テンプレート"""
    print(f"Shape: {df.shape}")
    print(f"\nColumn types:\n{df.dtypes}")
    print(f"\nMissing values:\n{df.isnull().sum()}")
    print(f"\nBasic stats:\n{df.describe()}")

    # 数値列の可視化
    numeric_cols = df.select_dtypes(include=[np.number]).columns
    df[numeric_cols].hist(bins=20, figsize=(15, 10))
    plt.tight_layout()
    plt.show()

    # 相関ヒートマップ
    if len(numeric_cols) > 1:
        plt.figure(figsize=(12, 10))
        sns.heatmap(df[numeric_cols].corr(), annot=True, fmt='.2f',
                    cmap='RdBu_r', center=0)
        plt.show()

    # ターゲットがあれば散布図行列
    if target and target in df.columns:
        sns.pairplot(df[numeric_cols[:5]], hue=target if df[target].dtype == 'O' else None)
        plt.show()
📥 入力例: data/raw/SSDSE-B-2026.csv 期間: 2010〜2024 年(仮) 処置: 2018 年から東京・大阪・愛知に介入
📤 実行例: 2010-2017: 両群とも年率 +0.5%(並行) 2018-2024: 処置群 +1.2%, 対照群 +0.6% → 介入後に乖離
💬 読み方: 介入前のトレンドが並行なら DID 仮定 OK。 介入後に処置群だけ加速 → 政策効果あり。 介入前から乖離していたら、 既存トレンドを誤って効果と見なす危険。 必ず Placebo Test と Pre-trend 検定をセットで実施。

📈 報告書テンプレート

分析結果を報告する際の標準的な構成:

  1. 背景・目的:なぜこの分析が必要か
  2. データ:出所、 サンプルサイズ、 期間
  3. 方法:使用した統計手法、 仮定
  4. 結果:図表、 統計量、 検定結果
  5. 解釈:結果が何を意味するか
  6. 限界:分析の制約
  7. 結論:要点まとめ、 今後の課題

🗺️ 統計手法選択フローチャート

Q1: 何を知りたい?

Q2: データの種類は?

Q3: サンプルサイズは?

Q4: 仮定は?

📏 効果量の参照表

p値だけでなく効果量も併記するのが現代統計の標準。 主要な指標と Cohen の解釈基準:

統計量 効果量
2群平均差Cohen's d0.20.50.8
相関r0.10.30.5
線形回帰0.020.130.26
ANOVAη² (eta²)0.010.060.14
χ²Cramér's V0.10.30.5
ロジスティックOdds Ratio1.52.54.0

🗺️ 概念マップ — 3つの視点で体系を理解する

差分の差分法(DiD) がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。

📍 体系階層のパス

🌐 統計・データサイエンス因果推論因果手法DiD

① 🔗 関係マップ — 「他の手法とどう繋がっているか」

中心の概念から放射状に、 前提・兄弟・発展形・応用先などの関係性を矢印で結びます。 横の繋がりを見るのに最適。 ノードをドラッグ、 ホイールでズーム、 クリックで遷移

凡例:現在の用語上位カテゴリ兄弟(並列)前提発展形応用先2階層先

② ⭕ 包含マップ — 「どのカテゴリに含まれているか」

大きな円が小さな円を包含する Circle Packing 図。 「差分の差分法(DiD)」は緑色でハイライト

📍現在地:統計・データサイエンス

③ 🌳 ツリーマップ — 「面積で見るボリューム比較」

長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「差分の差分法(DiD)」は緑色でハイライト

🎯 3つのマップの使い分け

マップ 分かること こんな時に見る
🔗 関係マップ手法間の横の関係(前提→発展→応用)「次に何を学べばよい?」 学習順序の判断
⭕ 包含マップ分類体系の入れ子構造(上位⊃下位)「この手法はどんなジャンルに属する?」
🌳 ツリーマップ分野の規模比較(面積=ボリューム)「データサイエンス全体の俯瞰像」

💡 ジャストインタイム学習のヒント:3つの視点を行き来することで、 概念を多角的に理解できます。 包含マップやツリーマップはズーム/ドリルダウンで大分類から細部まで探索できます。

🔖 キーワード索引(拡張)

DIDとは 🧮 SSDSE-B 実例 🐍 実装バリエーション ⚠️ 落とし穴集 平行トレンド イベントスタディ 時差導入DID 合成統制法 関連用語マップ

🧮 SSDSE-B を使った DID の実例 — 「ある県の制度改正」を想定

SSDSE-B のパネル構造(47県 × 18年)は DID の最良の練習場。 ここでは「2015年に X県だけが教育政策を改正した」と仮定し、 大学進学率への影響を DID で推定します。

① セットアップ

🎯 解説: DID(差の差分析)は政策効果を測る手法。 SSDSE-B-2026 を 2 時点で見立て、 「処置群(政策実施県)と対照群の差」の「処置前後の差」を比較する。 トレンド共通の仮定が成立する場合のみ妥当。
1
2
3
4
5
6
7
8
9
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2023.csv', encoding='shift_jis', header=[0,1])
df.columns = ['_'.join(c).strip() for c in df.columns]

# 仮の処置:「秋田県」が 2015 年に何らかの教育政策改正をしたとする
df['treated'] = (df['都道府県_Prefecture'] == '秋田県').astype(int)
df['post']    = (df['年度_Year'] >= 2015).astype(int)
df['treat_post'] = df['treated'] * df['post']
print(df[['年度_Year', '都道府県_Prefecture', 'treated', 'post', 'treat_post']].head(10))
📥 入力例: data/raw/SSDSE-B-2026.csv 処置群: 東京・大阪・愛知(仮想政策実施) 対照群: その他 44 県 指標: 1人当たり県民所得
📤 実行例: 処置群 (Before): 380 万円 処置群 (After): 410 万円 (+30) 対照群 (Before): 290 万円 対照群 (After): 310 万円 (+20) DID = +30 - +20 = +10 万円
💬 読み方: DID 推定値 +10 万円が「政策の純効果」と解釈される。 ただし「もし政策がなかったら処置群も対照群と同じトレンドだった」という共通トレンド仮定が必要。 違反すれば偽の効果を誤検出する。

② DID 回帰の実行

🎯 解説: DID を回帰で推定するには「処置ダミー × 時期ダミー」の交差項の係数を見る。 統計検定(t 検定)で効果の有意性も確認できる。
1
2
3
4
5
import statsmodels.formula.api as smf
# 大学等進学率 ~ 処置 + 時期 + 交互作用(DID係数)
# 注:簡単のため一部のコントロール変数を省略
m = smf.ols('大学等進学率 ~ treated + post + treat_post', data=df).fit()
print(m.summary())
📥 入力例: data/raw/SSDSE-B-2026.csv formula = '所得 ~ 処置 + 時期 + 処置*時期'
📤 実行例: Coefficients: 処置 +90.0 (処置群と対照群の常時差) 時期 +20.0 (時間トレンド) 処置*時期 +10.0 ★DID 推定値 p (DID) = 0.032
💬 読み方: 交差項の係数 +10 が DID 効果、 p < 0.05 で有意。 標準誤差はクラスタロバスト(県でクラスタリング)にするのが標準。 サンプルサイズが小さいと検出力が弱い。

典型結果:treat_post の係数 = +0.5%(SE 1.2、 p=0.68)。 単純DID では効果なし or 微小。 さらに県・年固定効果を入れると:

🎯 解説: 共通トレンド仮定を視覚的に確認する。 処置前の期間で処置群と対照群が並行に動いていれば、 仮定を支持。 並行でなければ DID の前提が崩れる。
1
2
m2 = smf.ols('大学等進学率 ~ treat_post + C(都道府県_Prefecture) + C(年度_Year)', data=df).fit(cov_type='cluster', cov_kwds={'groups': df['都道府県_Prefecture']})
print(m2.params['treat_post'], m2.bse['treat_post'])
📥 入力例: data/raw/SSDSE-B-2026.csv 期間: 2010〜2024 年(仮) 処置: 2018 年から東京・大阪・愛知に介入
📤 実行例: 2010-2017: 両群とも年率 +0.5%(並行) 2018-2024: 処置群 +1.2%, 対照群 +0.6% → 介入後に乖離
💬 読み方: 介入前のトレンドが並行なら DID 仮定 OK。 介入後に処置群だけ加速 → 政策効果あり。 介入前から乖離していたら、 既存トレンドを誤って効果と見なす危険。 必ず Placebo Test と Pre-trend 検定をセットで実施。

2WFE(双方向固定効果)で再推定 → 県・年の固定効果を制御した上で「treated × post」の係数だけが残る。

③ 平行トレンド検定(イベントスタディ)

🎯 解説: DID(差の差分析)は政策効果を測る手法。 SSDSE-B-2026 を 2 時点で見立て、 「処置群(政策実施県)と対照群の差」の「処置前後の差」を比較する。 トレンド共通の仮定が成立する場合のみ妥当。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
df['rel_year'] = df['年度_Year'] - 2015
df.loc[df['treated']==0, 'rel_year'] = -999  # 統制群は欠損扱い
# 各「処置からの相対年」の効果を推定
for rel in range(-5, 6):
    if rel == -1: continue  # 参照年
    df[f'd_{rel}'] = ((df['treated']==1) & (df['rel_year']==rel)).astype(int)
event_vars = [f'd_{r}' for r in range(-5, 6) if r != -1]
formula = '大学等進学率 ~ ' + ' + '.join(event_vars) + ' + C(都道府県_Prefecture) + C(年度_Year)'
m_event = smf.ols(formula, data=df).fit()
# 処置前(rel = -5 ... -2)の係数が全て 0 近傍 → 平行トレンド OK
# rel ≥ 0 の係数が動的処置効果
📥 入力例: data/raw/SSDSE-B-2026.csv 処置群: 東京・大阪・愛知(仮想政策実施) 対照群: その他 44 県 指標: 1人当たり県民所得
📤 実行例: 処置群 (Before): 380 万円 処置群 (After): 410 万円 (+30) 対照群 (Before): 290 万円 対照群 (After): 310 万円 (+20) DID = +30 - +20 = +10 万円
💬 読み方: DID 推定値 +10 万円が「政策の純効果」と解釈される。 ただし「もし政策がなかったら処置群も対照群と同じトレンドだった」という共通トレンド仮定が必要。 違反すれば偽の効果を誤検出する。

🐍 実装バリエーション — statsmodels / linearmodels / DiD パッケージ

(A) statsmodels OLS — シンプルな2x2 DID

🎯 解説: DID を回帰で推定するには「処置ダミー × 時期ダミー」の交差項の係数を見る。 統計検定(t 検定)で効果の有意性も確認できる。
1
2
3
import statsmodels.formula.api as smf
m = smf.ols('y ~ treated + post + treated:post', data=df).fit()
print(m.params['treated:post'])  # DID 推定値
📥 入力例: data/raw/SSDSE-B-2026.csv formula = '所得 ~ 処置 + 時期 + 処置*時期'
📤 実行例: Coefficients: 処置 +90.0 (処置群と対照群の常時差) 時期 +20.0 (時間トレンド) 処置*時期 +10.0 ★DID 推定値 p (DID) = 0.032
💬 読み方: 交差項の係数 +10 が DID 効果、 p < 0.05 で有意。 標準誤差はクラスタロバスト(県でクラスタリング)にするのが標準。 サンプルサイズが小さいと検出力が弱い。

(B) linearmodels PanelOLS — 双方向固定効果が簡単

🎯 解説: 共通トレンド仮定を視覚的に確認する。 処置前の期間で処置群と対照群が並行に動いていれば、 仮定を支持。 並行でなければ DID の前提が崩れる。
1
2
3
4
5
from linearmodels.panel import PanelOLS
df_p = df.set_index(['都道府県_Prefecture', '年度_Year'])
m = PanelOLS.from_formula('y ~ treat_post + EntityEffects + TimeEffects', data=df_p).fit(cov_type='clustered', cluster_entity=True)
print(m.summary)
# 固定効果と頑健SEを一行で
📥 入力例: data/raw/SSDSE-B-2026.csv 期間: 2010〜2024 年(仮) 処置: 2018 年から東京・大阪・愛知に介入
📤 実行例: 2010-2017: 両群とも年率 +0.5%(並行) 2018-2024: 処置群 +1.2%, 対照群 +0.6% → 介入後に乖離
💬 読み方: 介入前のトレンドが並行なら DID 仮定 OK。 介入後に処置群だけ加速 → 政策効果あり。 介入前から乖離していたら、 既存トレンドを誤って効果と見なす危険。 必ず Placebo Test と Pre-trend 検定をセットで実施。

(C) DiD (Callaway & Sant'Anna) — 時差導入処置

🎯 解説: DID(差の差分析)は政策効果を測る手法。 SSDSE-B-2026 を 2 時点で見立て、 「処置群(政策実施県)と対照群の差」の「処置前後の差」を比較する。 トレンド共通の仮定が成立する場合のみ妥当。
1
2
3
4
5
6
# pip install differences
from differences import ATTgt
att = ATTgt(data=df, cohort_name='treat_year', strata_name=None,
            base_period='varying', anticipation=0).fit(formula='y ~ 1')
print(att.aggregate('simple'))
# 集約 ATT と動的 ATT を頑健に推定
📥 入力例: data/raw/SSDSE-B-2026.csv 処置群: 東京・大阪・愛知(仮想政策実施) 対照群: その他 44 県 指標: 1人当たり県民所得
📤 実行例: 処置群 (Before): 380 万円 処置群 (After): 410 万円 (+30) 対照群 (Before): 290 万円 対照群 (After): 310 万円 (+20) DID = +30 - +20 = +10 万円
💬 読み方: DID 推定値 +10 万円が「政策の純効果」と解釈される。 ただし「もし政策がなかったら処置群も対照群と同じトレンドだった」という共通トレンド仮定が必要。 違反すれば偽の効果を誤検出する。

(D) 合成統制法(SyntheticControlMethods)

🎯 解説: DID を回帰で推定するには「処置ダミー × 時期ダミー」の交差項の係数を見る。 統計検定(t 検定)で効果の有意性も確認できる。
1
2
3
4
from SyntheticControlMethods import Synth
scm = Synth(df_pivot, '進学率', 'Prefecture', 'Year', 2015, 'Akita', n_optim=10).fit()
scm.plot(['original', 'pointwise', 'cumulative'])
# 「合成秋田」を構築して、 実際の秋田との差で処置効果を推定
📥 入力例: data/raw/SSDSE-B-2026.csv formula = '所得 ~ 処置 + 時期 + 処置*時期'
📤 実行例: Coefficients: 処置 +90.0 (処置群と対照群の常時差) 時期 +20.0 (時間トレンド) 処置*時期 +10.0 ★DID 推定値 p (DID) = 0.032
💬 読み方: 交差項の係数 +10 が DID 効果、 p < 0.05 で有意。 標準誤差はクラスタロバスト(県でクラスタリング)にするのが標準。 サンプルサイズが小さいと検出力が弱い。

(E) scikit-learn の DoubleML(DID)

🎯 解説: 共通トレンド仮定を視覚的に確認する。 処置前の期間で処置群と対照群が並行に動いていれば、 仮定を支持。 並行でなければ DID の前提が崩れる。
1
2
3
4
5
6
from doubleml import DoubleMLDID
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
dml_did = DoubleMLDID(data, y='y', d='treat', x_cols=['x1', 'x2'],
                      ml_g=RandomForestRegressor(), ml_m=RandomForestClassifier())
dml_did.fit()
print(dml_did.summary)  # 機械学習で nuisance を推定する高度版 DID
📥 入力例: data/raw/SSDSE-B-2026.csv 期間: 2010〜2024 年(仮) 処置: 2018 年から東京・大阪・愛知に介入
📤 実行例: 2010-2017: 両群とも年率 +0.5%(並行) 2018-2024: 処置群 +1.2%, 対照群 +0.6% → 介入後に乖離
💬 読み方: 介入前のトレンドが並行なら DID 仮定 OK。 介入後に処置群だけ加速 → 政策効果あり。 介入前から乖離していたら、 既存トレンドを誤って効果と見なす危険。 必ず Placebo Test と Pre-trend 検定をセットで実施。

⚠️ 追加の落とし穴 — DID の実務

❌ 平行トレンドの検証を省略
DID の核心的仮定は「処置前の処置群と統制群が平行なトレンド」。 これを検証せずに DID を実行するのは、 ガソリンを入れずに車を走らせるようなもの。 (i) 処置前期間の年次平均をプロット、 (ii) リード項(処置前の偽処置)が有意でないかチェック、 (iii) イベントスタディで処置前係数が 0 近傍か確認。 平行が崩れていれば、 合成統制法、 propensity score matching、 IV など別手法へ。
❌ 時差導入処置で 2WFE を使う
Goodman-Bacon (2021)・Callaway-Sant'Anna (2021) が示したように、 処置時点が群ごとに違う(staggered adoption)場合、 標準的な双方向固定効果 (TWFE) DID は有害な比較(forbidden comparison)を含むため、 真の ATT を過小または逆符号で推定する。 対策:CS法、 de Chaisemartin-d'Haultfoeuille法、 Sun-Abraham法など現代的 staggered DID 手法を使う。 2020年代後半の必須知識。
❌ 標準誤差をクラスタリングしない
パネルデータでは個体内の誤差が時系列的に相関する。 通常の SE は過小評価される。 Bertrand-Duflo-Mullainathan (2004) 以降、 クラスター頑健 SE(個体レベルでクラスタリング)が必須。 statsmodels では fit(cov_type='cluster', cov_kwds={'groups': prefecture})。 47県のように少クラスター時はワイルドブートストラップ (wild cluster bootstrap) も検討。
❌ 処置の同時発生イベントに無頓着
処置(政策)の導入と同時期に別のショック(経済危機、 自然災害、 別の政策)があると、 DID 推定値はこの混合効果を含む。 処置効果と区別できない。 対策:(i) 別ショックの空間・時間広がりを調査、 (ii) 別ショックを別変数として制御、 (iii) 影響を受けない統制群の選定、 (iv) サンプル期間を分割して頑健性チェック。 同時イベントの存在を「研究の限界」として明示する誠実さも重要。
❌ 処置効果の異質性を無視
DID は通常「平均処置効果」を推定するが、 効果は群によって違う(若年層と高齢層、 都市と地方)可能性が高い。 (i) サブグループ別 DID、 (ii) 交互作用項を入れる、 (iii) Causal Forest、 DR-Learner などの異質処置効果推定。 政策含意の観点では「誰に効くか」が「効くか」より重要なことが多い。 機械学習との融合が現代的な発展方向。
❌ スピルオーバー効果を考慮しない
SUTVA(処置の安定単位値仮定):「処置群への処置が統制群に影響しない」。 実際は隣接県、 経済交流、 情報伝播でスピルオーバーが起きる。 例:県境地域、 通勤圏、 サプライチェーン。 対策:(i) スピルオーバー対象を分析対象から除外、 (ii) 距離・隣接ダミーで効果を測定、 (iii) 空間計量経済学的手法。 SUTVA違反は推定値を歪める。
❌ 予期的効果(anticipation)を見落とす
政策発表から実施まで時間がある場合、 処置群は政策発表後に行動を変える可能性がある。 これは事前のトレンド崩壊として現れ、 平行トレンド仮定を破る。 対策:(i) 発表時点を別の処置時点として扱う、 (ii) アンチサイペーション期間を分析から除外、 (iii) イベントスタディで予期効果の有無を視覚化。 政策評価では特に注意すべき問題。

🔖 キーワード索引 — 完全強化版

「差の差分析(DID)」を理解するうえで必要なキーワードを 10 件以上提示します。 各チップから対応セクションへ移動できます。

30 秒結論 文脈 直感 数式 記号読み解き 実値計算 Python 実装 落とし穴 関連手法 関連用語 グループ教材 概念マップ

💡 30 秒で分かる結論 — 完全強化版

📍 文脈ボックス — あなたが今見ているもの(完全強化版)

このセクションは「差の差分析(DID)」を扱う 用語ページ です。 統計データ分析コンペティション(2026)の再現教材における中核用語のひとつで、政令指定都市と非政令指定都市の比較(前後差の差) という観点で SSDSE-B-2026(47 都道府県 × 複数年 × 100 超列)に紐づけられます。

位置づけ:相関線形回帰仮説検定 といった基礎用語群と並列であり、応用としては 内生性IVDIDクラスタリング 等へ繋がります。

🎨 直感で掴む — 完全強化版

差の差分析(DID) を一言でいえば「政令指定都市と非政令指定都市の比較(前後差の差)」。 47 都道府県という小さな母集団でも、 SSDSE-B-2026 の A1101 列に注目すると、 大都市圏と地方の差・人口規模に伴う相対比較など、 様々なパターンが見えてきます。

比喩でいうと、 差の差分析(DID) はデータ分析の「眼鏡」のようなもの。 同じデータでも眼鏡を変えれば、 平均(中心)・分散(ばらつき)・相関(連動)・因果(影響)と、 異なる情報が浮かび上がります。 SSDSE-B-2026 を題材に、 この眼鏡をかけてみるのが本ページの狙いです。

📐 数式または定義 — 完全強化版

差の差分析(DID) の代表的な定義式は次のとおりです。

$$ \hat{\tau}_{DID} = (\bar{Y}_{T,\text{post}} - \bar{Y}_{T,\text{pre}}) - (\bar{Y}_{C,\text{post}} - \bar{Y}_{C,\text{pre}}) $$

ここで使われる記号や演算の意味は次節で言葉に翻訳します。

🔬 数式を言葉で読み解く — 完全強化版

数式の各記号を、日本語の意味に変換します。

🧮 実値で計算してみる — SSDSE-B-2026 で 差の差分析(DID)(完全強化版)

SSDSE-B-2026(公的統計の社会・教育系データセット、 47 都道府県 × 10 年分超 × 100 以上の列)を用いて、 「差の差分析(DID)」を体感します。 ファイル名は SSDSE-B-2026.csv、 読み込みは下記の Python コードで行います。

import pandas as pd

# SSDSE-B-2026 を読み込む(cp932 / Shift_JIS)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
print(df.shape)          # (564, 112)
print(df['SSDSE-B-2026'].unique())  # 含まれる年度
latest = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()
print(latest[['Prefecture', 'A1101', 'A4101']].head())

ここで使った中心列 A1101 は SSDSE-B-2026 における 政令指定都市と非政令指定都市の比較(前後差の差) に関連する指標です。 算出例:

🐍 Python 実装 — 完全強化版

scipy / pandas / scikit-learn / statsmodels を中心とした標準的な実装例です。 まず CSV を読み込み、 次に 差の差分析(DID) の解析を行います。

import pandas as pd
import numpy as np
from scipy import stats

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
df = df[df['SSDSE-B-2026'] == df['SSDSE-B-2026'].max()].copy()

x = df['A1101'].astype(float).values
y = df['A4101'].astype(float).values

# 基本統計量
print('n            =', len(x))
print('mean(x)      =', np.mean(x))
print('std(x)       =', np.std(x, ddof=1))

# 差の差分析(DID) の代表的計算(用途に応じて scipy/statsmodels を切替える)
r, p = stats.pearsonr(x, y)
print(f'Pearson r = {r:.4f}, p = {p:.4g}')
rs, ps = stats.spearmanr(x, y)
print(f'Spearman rho = {rs:.4f}, p = {ps:.4g}')

用途別の追加実装:

# 標準化と簡易クラスタリングの例
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

X = df[['A1101', 'A4101']].astype(float).values
Xs = StandardScaler().fit_transform(X)
km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(Xs)
df['cluster'] = km.labels_
print(df[['Prefecture', 'A1101', 'A4101', 'cluster']].head(10))
# 時系列(北海道の A1101)— 例として ARIMA 系の前処理
import statsmodels.api as sm

ts = df.sort_values('SSDSE-B-2026').groupby('SSDSE-B-2026')['A1101'].mean()
print(ts.tail())
res = sm.tsa.stattools.adfuller(ts)
print('ADF stat:', res[0], 'p:', res[1])

⚠️ 落とし穴 — 完全強化版

差の差分析(DID) を実務で扱う際に踏みやすい落とし穴を 5 件挙げます。

🗺 概念マップ — 完全強化版

🎯 まとめ — 完全強化版

本ページでは「差の差分析(DID)」を 12 セクション(🔖 キーワード索引/💡 30 秒結論/📍 文脈/🎨 直感/📐 数式/🔬 記号読み解き/🧮 実値計算/🐍 Python 実装/⚠️ 落とし穴/🌐 関連手法/🔗 関連用語/📚 グループ教材)で完結に整理しました。 SSDSE-B-2026 を素材に、 概念の輪郭・式の意味・実装手順・典型的な失敗パターンの 4 点を最低限押さえれば、 統計データ分析コンペの現場で迷わず使えるはずです。