論文中に 「Hausman検定」として登場する用語。
Hausman検定 とは:パネルデータで「固定効果(FE)とランダム効果(RE)のどちらを使うべきか」を判定する検定。
compare や Stata の hausman コマンドが代表的。論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:
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() |
このページの上にある3つの概念マップ(関係マップ、 包含マップ、 ツリーマップ)でこの概念の位置づけが視覚的に分かります。 関連手法を辿って学習を進めましょう。
統計データ活用コンペティションの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、 効果量 |
このページの概念をマスターすることで、 以下のスキルが身につきます:
このコンペの主要データセット(SSDSE-B-2026)の構造:
| カテゴリ | 変数例 |
|---|---|
| 人口 | 総人口、 年齢別人口、 性別人口 |
| 人口動態 | 出生数、 死亡数、 合計特殊出生率、 婚姻数 |
| 気候 | 気温、 降水量、 降水日数 |
| 教育 | 幼小中高校数、 教員数、 生徒数、 大学進学率 |
| 経済 | 求職件数、 求人件数、 旅館数 |
| 医療 | 病院数、 診療所数、 歯科診療所 |
| 家計 | 消費支出、 食料費、 住居費、 教育費等の項目別 |
このガイドは「必要なときに必要な知識」を提供する設計:
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()) |
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() |
分析結果を報告する際の標準的な構成:
p値だけでなく効果量も併記するのが現代統計の標準。 主要な指標と Cohen の解釈基準:
| 統計量 | 効果量 | 小 | 中 | 大 |
|---|---|---|---|---|
| 2群平均差 | Cohen's d | 0.2 | 0.5 | 0.8 |
| 相関 | r | 0.1 | 0.3 | 0.5 |
| 線形回帰 | R² | 0.02 | 0.13 | 0.26 |
| ANOVA | η² (eta²) | 0.01 | 0.06 | 0.14 |
| χ² | Cramér's V | 0.1 | 0.3 | 0.5 |
| ロジスティック | Odds Ratio | 1.5 | 2.5 | 4.0 |
| 日本語 | 英語 |
|---|---|
| 統計的に有意 | statistically significant |
| 効果量 | effect size |
| 95%信頼区間 | 95% confidence interval (CI) |
| 標本サイズ | sample size |
| 検出力 | statistical power |
| 第1種の誤り | Type I error / false positive |
| 第2種の誤り | Type II error / false negative |
| 多重比較問題 | multiple comparisons problem |
| 過学習 | overfitting |
| 汎化性能 | generalization |
| 交差検証 | cross-validation (CV) |
「都道府県 × 年度」のパネル構造を擬似的に構築し、 一人当たり県民所得が出生率に与える影響を、 FE モデルと RE モデルの両方で推定して比較します(年度差は SSDSE-A から派生させたサンプル)。
1 2 3 4 5 6 7 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) df = df.rename(columns={'都道府県': 'pref', '一人当たり県民所得': 'income', '出生率': 'fertility', '高齢化率': 'aging'}) df['year'] = 2026 panel = df.set_index(['pref', 'year']) print(panel.head()) |
1 2 3 4 5 6 7 | from linearmodels.panel import PanelOLS, RandomEffects fe = PanelOLS.from_formula('fertility ~ income + aging + EntityEffects', data=panel).fit(cov_type='clustered', cluster_entity=True) re = RandomEffects.from_formula('fertility ~ income + aging', data=panel).fit() print(fe) print(re) |
1 2 3 4 5 6 7 8 9 10 | import numpy as np from scipy import stats b_fe = fe.params[['income', 'aging']].values b_re = re.params[['income', 'aging']].values V_fe = fe.cov.loc[['income','aging'], ['income','aging']].values V_re = re.cov.loc[['income','aging'], ['income','aging']].values diff = b_fe - b_re H = diff @ np.linalg.inv(V_fe - V_re) @ diff p = 1 - stats.chi2.cdf(H, df=len(diff)) print(f'Hausman H = {H:.3f}, p = {p:.4f}') |
| 指標 | FE 推定値 | RE 推定値 | 差 |
|---|---|---|---|
| income | 0.00021 | 0.00038 | −0.00017 |
| aging | −0.018 | −0.024 | +0.006 |
| Hausman H | 12.34 | p = 0.0021 | |
H が大きく p < 0.05 なので「個体効果と説明変数は無相関」という帰無仮説は棄却。 RE モデルは不一致推定量となるため、 FE モデルを採用するのが妥当です。
compare(最短コード)1 2 | from linearmodels.panel import compare print(compare({'FE': fe, 'RE': re})) |
1 2 3 4 5 6 7 8 9 10 11 | import statsmodels.api as sm # 個体ダミーで FE を表現 dummies = pd.get_dummies(panel.index.get_level_values('pref'), drop_first=True) X_fe = pd.concat([panel[['income','aging']].reset_index(drop=True), dummies.reset_index(drop=True)], axis=1).astype(float) y = panel['fertility'].reset_index(drop=True) fe2 = sm.OLS(y, sm.add_constant(X_fe)).fit() # 通常 OLS(pooled)と Hausman 風の差検定 X_pool = sm.add_constant(panel[['income','aging']].reset_index(drop=True).astype(float)) pool = sm.OLS(y, X_pool).fit() print(fe2.params[['income','aging']] - pool.params[['income','aging']]) |
1 2 3 | from scipy.stats import chi2 for H in [3.0, 5.99, 10.0, 12.34, 20.0]: print(f'H={H:5.2f} p={1-chi2.cdf(H, df=2):.4f}') |
plm パッケージ互換(rpy2 経由)1 2 3 4 5 6 7 8 9 10 | import rpy2.robjects as ro from rpy2.robjects import pandas2ri pandas2ri.activate() ro.r('library(plm)') ro.globalenv['df'] = panel.reset_index() ro.r(''' fe <- plm(fertility ~ income + aging, data=df, model="within", index=c("pref","year")) re <- plm(fertility ~ income + aging, data=df, model="random", index=c("pref","year")) print(phtest(fe, re)) ''') |
1. 「p < 0.05 で必ず FE」と機械的に判定してしまう。Hausman 検定はサンプルサイズが大きくなると、 ごく僅かな係数差でも p 値が小さくなります。 結果として実務的にはほぼ同等のモデルなのに FE 採用を強制されるケースがあります。 効果量(β̂FE − β̂RE の絶対値)と AIC / BIC も併用してください。
2. 不均一分散・系列相関を補正していない。古典的な Hausman 検定は球面性(i.i.d.)を仮定しています。 パネルでは個体内系列相関や不均一分散が常態なので、 cluster-robust 標準誤差で再計算しないと、 H 統計量自体が信用できません。 linearmodels の cov_type='clustered' を必ず使ってください。
3. 時間ダミーや交互作用を忘れる。FE は個体効果を吸収しますが、 時間効果(共通ショック)を含めないと、 説明変数が時間トレンドを取り込んだ偽の係数になります。 EntityEffects + TimeEffects の 2way FE を基本形にし、 必要に応じて交互作用も検討しましょう。
4. 内生変数を回帰式に放置している。Hausman は「FE と RE のどちらを使うか」を決める検定であって、 内生性そのものを解決しません。 説明変数自身が誤差項と相関しているなら、 IV や DID など別の識別戦略が必要で、 H が有意でなくても RE が不偏になる保証はありません。
5. 観測単位が「人」ではなく「集計値」になっている。都道府県単位の集計データ(SSDSE-B)は「個体=47県」しかなく、 自由度が極端に小さい状態で Hausman を行うと統計量が不安定です。 市区町村別 or 業種別の細分化、 あるいは時間方向 panel への拡張で N を増やしましょう。
6. 説明変数に時間不変の変数を含めている。FE モデルは時間不変変数(例:地形・気候)を吸収してしまうため、 RE と比較するとそれら係数の差が定義できません。 該当列は事前に外すか、 Hausman-Taylor 推定量で扱う必要があります。
7. VFE − VRE が非正定値になる。有限標本では分散差行列が負定値になり、 H が負値を出すことがあります。 これは検定の前提が壊れているサインで、 ブートストラップ版 Hausman(Wooldridge 版)への切り替え、 もしくは Mundlak アプローチ(FE と RE の中間)を検討すべきです。
Hausman検定 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 体系階層に未登録
中心の概念から放射状に、 前提・兄弟・発展形・応用先などの関係性を矢印で結びます。 横の繋がりを見るのに最適。 ノードをドラッグ、 ホイールでズーム、 クリックで遷移。
大きな円が小さな円を包含する Circle Packing 図。 「Hausman検定」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「Hausman検定」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 ジャストインタイム学習のヒント:3つの視点を行き来することで、 概念を多角的に理解できます。 包含マップやツリーマップはズーム/ドリルダウンで大分類から細部まで探索できます。