論文中に 「多重共線性」として登場する用語。
多重共線性 とは:説明変数同士が強く相関している状態。回帰係数の推定が不安定になり、p値が大きくなる。
多重共線性(multicollinearity)は、 重回帰で説明変数同士が強く相関している状態。 これがあると、 「個々の係数は信用できないが、 予測自体はそこそこ正しい」という厄介な状況になります。
症状(あるある):
原因:説明変数同士が強く相関していると、 OLS の解 $(X^\top X)^{-1}$ で逆行列が不安定になります。 「x1 と x2 が一緒に動くので、 どっちが効いているか分けられない」状態。
検出:
対処法:
覚えておくべき真実:多重共線性は「モデルが悪い」ではなく「係数の解釈ができない」状態。 予測精度には影響しない。 「個別の変数の効果」を主張したいときだけ深刻になる。
多重共線性(multicollinearity)は、 重回帰モデルで説明変数同士が強く相関する状態。 係数の推定が不安定になり、 解釈が困難に。
|r| > 0.7 のペアは要注意。
$$ \text{VIF}_j = \frac{1}{1 - R_j^2} $$
X^T X の最大固有値/最小固有値。 30 を超えると多重共線性の疑い。
1 2 3 4 5 6 7 8 9 10 11 12 | from statsmodels.stats.outliers_influence import variance_inflation_factor import pandas as pd # VIF を全変数で計算 vif_df = pd.DataFrame() vif_df['feature'] = X.columns vif_df['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])] print(vif_df.sort_values('VIF', ascending=False)) # VIF > 10 の変数を除く high_vif = vif_df[vif_df['VIF'] > 10]['feature'].tolist() X_reduced = X.drop(columns=high_vif) |
Ragnar Frisch(1934)が経済学で問題提起。 「経済データの多くは互いに相関しており、 回帰係数を一意に推定できない」。 1969年にノーベル経済学賞受賞時の主要業績。
| 目的 | 1変数 | 2変数 | 多変量 |
|---|---|---|---|
| 記述 | 平均, 中央値, 分散 | 相関, 共分散 | PCA, 因子分析 |
| 可視化 | ヒストグラム, 箱ひげ | 散布図, ヒートマップ | 散布図行列, バイプロット |
| 予測 | 時系列モデル | 単回帰 | 重回帰, Ridge, LASSO |
| 分類 | ロジスティック回帰 | 判別分析 | SVM, RF, NN |
| グループ化 | 階級分け | 2次元クラスタリング | k-means, 階層クラスタリング |
| 検定 | 1標本t検定 | 2標本t検定, χ² | ANOVA, MANOVA |
| n | 推奨手法 |
|---|---|
| n < 10 | 記述統計のみ、 ノンパラ検定、 ベイズ統計 |
| 10 ≤ n < 30 | t検定, ブートストラップ, 単回帰 |
| 30 ≤ n < 200 | 重回帰, ANOVA, 階層クラスタリング |
| 200 ≤ n < 10000 | 複雑な回帰, RF, GBM, k-means |
| n ≥ 10000 | 深層学習, 大規模分散学習 |
| ライブラリ | 用途 |
|---|---|
| numpy | 数値計算の基礎、 行列演算 |
| pandas | データフレーム、 表操作 |
| scipy | 統計関数、 最適化、 線形代数 |
| statsmodels | 古典統計、 検定、 回帰分析の詳細 |
| scikit-learn | 機械学習、 前処理、 評価 |
| matplotlib | 基本可視化 |
| seaborn | 統計的可視化(高級) |
| plotly | インタラクティブ可視化 |
| xgboost / lightgbm | 勾配ブースティング |
| PyTorch / TensorFlow | 深層学習 |
このページで扱った概念を、 学習効率のためにまとめます。 これを毎日見ることで、 統計の基礎が体に染み込みます。
| 記号 | 意味 | 読み方 |
|---|---|---|
| μ | 母平均 | ミュー |
| σ | 母標準偏差 | シグマ |
| σ² | 母分散 | シグマ二乗 |
| x̄ | 標本平均 | エックスバー |
| s | 標本標準偏差 | エス |
| n | 標本サイズ | エヌ |
| p | p値、 比率 | ピー |
| α | 有意水準 | アルファ |
| β | 回帰係数、 第二種誤り率 | ベータ |
| r | 相関係数 | アール |
| R² | 決定係数 | アール二乗 |
| Σ | 総和記号、 共分散行列 | シグマ大文字 |
| N(μ, σ²) | 正規分布 | ノーマル ミュー シグマ二乗 |
| t(df) | t分布 | ティー |
| χ²(df) | カイ二乗分布 | カイ二乗 |
| F(d1, d2) | F分布 | エフ |
| H₀, H₁ | 帰無仮説、 対立仮説 | エイチゼロ、 エイチワン |
| E[X] | 期待値 | エクスペクタンス |
| Var(X) | 分散 | バリアンス |
| Cov(X, Y) | 共分散 | カバリアンス |
💡 統計学・データサイエンスは「記号の意味を理解する」ことが最初の壁。 各記号が何を表すか、 公式の中での役割を覚えてしまえば、 後はパターンの組合せで様々な手法が理解できます。
(CRISP-DM プロセスより)
| 分野 | 主要技術 | 代表ツール |
|---|---|---|
| 記述統計 | 要約量、 可視化 | pandas, matplotlib |
| 推測統計 | 検定、 信頼区間 | scipy.stats, statsmodels |
| 機械学習 | 予測、 分類、 クラスタリング | scikit-learn, XGBoost |
| 深層学習 | NN、 画像、 自然言語 | PyTorch, TensorFlow |
| 時系列 | ARIMA、 状態空間、 LSTM | statsmodels, prophet |
| 因果推論 | RCT、 IV、 DiD、 PSM | DoWhy, EconML |
| ベイズ統計 | MCMC、 変分推論 | PyMC, Stan |
| 最適化 | 線形/凸/離散最適化 | scipy.optimize, cvxpy |
これらは互いに深く関連します:
「世帯人員」「持ち家比率」「住宅延床面積」は構造的に強く相関しているため、 一緒に重回帰に入れると VIF が爆発する典型例です。
1 2 3 4 5 6 7 8 9 10 | import pandas as pd import numpy as np from statsmodels.stats.outliers_influence import variance_inflation_factor df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) X = df[['一人当たり県民所得','世帯人員','持ち家比率','住宅延床面積','高齢化率']].astype(float) X = (X - X.mean()) / X.std() # 標準化 vif = pd.Series( [variance_inflation_factor(X.values, i) for i in range(X.shape[1])], index=X.columns) print(vif.round(2)) |
| 変数 | VIF | 判定 |
|---|---|---|
| 一人当たり県民所得 | 1.8 | 問題なし |
| 世帯人員 | 8.4 | 注意 |
| 持ち家比率 | 11.2 | 深刻 |
| 住宅延床面積 | 13.6 | 深刻 |
| 高齢化率 | 2.3 | 問題なし |
「持ち家比率」と「住宅延床面積」を同時に入れると VIF が 10 を超えました。 一方を落とすか、 これら 2 つから主成分を 1 つ作って代用する解決法が定石です。
statsmodels.stats.outliers_influence.variance_inflation_factor(標準)1 2 | from statsmodels.stats.outliers_influence import variance_inflation_factor as vif_fn vifs = [vif_fn(X.values, i) for i in range(X.shape[1])] |
numpy.linalg による条件数1 2 | cond_num = np.linalg.cond(X.values) print(f'条件数 = {cond_num:.1f}') # > 30 で多重共線性疑い |
sklearn.linear_model.Ridge(多重共線性に強い回帰)1 2 3 | from sklearn.linear_model import Ridge, RidgeCV ridge = RidgeCV(alphas=[0.01, 0.1, 1, 10, 100]).fit(X, y) print('best alpha =', ridge.alpha_, 'coef =', ridge.coef_) |
sklearn.decomposition.PCA → 主成分回帰1 2 3 4 5 6 | from sklearn.decomposition import PCA from sklearn.linear_model import LinearRegression pca = PCA(n_components=3).fit(X) Z = pca.transform(X) lr = LinearRegression().fit(Z, y) print('PC 寄与率', pca.explained_variance_ratio_.cumsum()) |
1 2 3 4 | import seaborn as sns import matplotlib.pyplot as plt sns.heatmap(X.corr(), annot=True, cmap='RdBu_r', vmin=-1, vmax=1) plt.show() |
1. VIF だけで判断する。VIF は他の説明変数で当該変数を回帰したときの R²j から作られる単一指標です。 サンプルサイズが小さいと不安定になりがちで、 ペア相関ヒートマップ・条件数(cond(X))・固有値分解(最小固有値が 0 近い)と併用するのが正攻法です。
2. 「予測精度が落ちる」と誤解する。多重共線性は個別係数の標準誤差を膨らませますが、 X 全体の予測力(R², MSE)はほぼ影響を受けません。 予測が目的なら気にせず投入してよく、 むしろ「変数を捨てて bias を増やす」方が損です。
3. ダミー変数の罠(perfect multicollinearity)。カテゴリ変数を全水準でダミー化(drop_first しない)すると、 合計が 1 になり完全共線。 多くのライブラリでは特異行列でエラー、 もしくは警告も出さず怪しい結果を返します。 必ず参照カテゴリを 1 つ落としましょう。
4. 「Ridge を使えば安心」と過信する。Ridge は係数を 0 に縮める正則化で、 多重共線性下でも安定した解を返しますが、 縮められた係数の解釈は「介入効果」ではなくバイアスを含んだ予測重みです。 因果推論の文脈では別の戦略(DAG・IV)が必要です。
5. 標準化を忘れる。VIF と Ridge は、 説明変数の単位スケールに敏感です。 「所得は千円」「人口は万人」など桁が異なるまま入力すると、 結果が解釈不能になります。 必ず StandardScaler で z スコア化してから計算しましょう。
6. 「相関 0.7 未満なら安心」という基準を信じる。ペア相関では検出できない「線形結合の共線性」(x3 ≒ 0.5 x1 + 0.5 x2)が存在します。 必ず VIF や条件数の追加診断も組み合わせてください。
7. 多重共線性を理由に説明変数を機械的に削除する。「VIF 10 以上を全部消す」と理論的に重要な変数まで落としてしまいます。 ドメイン知識と「これは仮説検証に必要か / 予測のための補助か」の区別を行ったうえで削除や合成を決めましょう。
多重共線性 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 前処理 › 変換 › 多重共線性
中心の概念から放射状に、 前提・兄弟・発展形・応用先などの関係性を矢印で結びます。 横の繋がりを見るのに最適。 ノードをドラッグ、 ホイールでズーム、 クリックで遷移。
大きな円が小さな円を包含する Circle Packing 図。 「多重共線性」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「多重共線性」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 ジャストインタイム学習のヒント:3つの視点を行き来することで、 概念を多角的に理解できます。 包含マップやツリーマップはズーム/ドリルダウンで大分類から細部まで探索できます。
本セクションは「多重共線性」を 47都道府県データ(SSDSE-B-2026)で具体的に確認するための追加教材です。 例として総人口と就業者数を同時に説明変数に入れる場合を扱います。
多重共線性を 47都道府県データで直感的に捉えるには、 まず「総人口と就業者数を同時に説明変数に入れる場合」を思い浮かべます。 東京都・大阪府・神奈川県のように総人口が大きい都道府県ほど、 課税対象所得や就業者数も大きくなる傾向があり、 こうしたデータの「形」を 多重共線性 は要約します。
たとえば 47都道府県を散布図にすると、 右肩上がりの帯状にデータが並びます。 この「帯の傾き」「帯のばらつき」「帯から外れる外れ値」を表現する道具が、 ここで扱う 多重共線性 だとイメージしてください。
多重共線性の中心的な数式は次のとおりです( SSDSE-B-2026 の 47 都道府県 \(n=47\) を想定):
$$ \hat{y}_i = \hat{\beta}_0 + \hat{\beta}_1 x_i, \quad i = 1, 2, \dots, 47 $$ $$ \hat{\beta}_1 = \frac{\sum_{i=1}^{47} (x_i - \bar{x})(y_i - \bar{y})}{\sum_{i=1}^{47} (x_i - \bar{x})^2}, \quad \hat{\beta}_0 = \bar{y} - \hat{\beta}_1 \bar{x} $$ここで \(x_i\) は総人口、 \(y_i\) は課税対象所得、 \(\bar{x}, \bar{y}\) はそれぞれの標本平均を表します。 多重共線性の解釈は、 上式で得られる係数や残差から導かれます。
SSDSE-B-2026 の 47都道府県データから、 「総人口と就業者数を同時に説明変数に入れる場合」を Python で再現します。 まず一行で読み込めるよう、 引数を直書きしたシンプル版を示します:
# 最小コード(直書き)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv')
続いて、 列名はリポジトリ準拠(A1101 総人口、 A1102 男性人口、 D3201 課税対象所得、 等)の本番コードです。
import pandas as pd
import numpy as np
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=[0,1,2])
# 列名を 3 段ヘッダの最下段だけ採用(コード列: A1101, D3201 等)
df.columns = [c[-1] for c in df.columns]
# 2022 年の 47都道府県スナップショット
sub = df[df['年度コード'] == 2022].copy()
x = sub['A1101'].astype(float) # 総人口
y = sub['D3201'].astype(float) # 課税対象所得
# 多重共線性の基礎統計
x_mean, y_mean = x.mean(), y.mean()
beta1 = ((x - x_mean) * (y - y_mean)).sum() / ((x - x_mean) ** 2).sum()
beta0 = y_mean - beta1 * x_mean
print(f'n = {len(x)}') # 47
print(f'beta1 = {beta1:,.4f}') # 傾き
print(f'beta0 = {beta0:,.4f}') # 切片
print(f'相関係数 = {x.corr(y):.4f}') # 0.95+ になる
# 残差・決定係数も計算
y_hat = beta0 + beta1 * x
resid = y - y_hat
ss_res = (resid ** 2).sum()
ss_tot = ((y - y_mean) ** 2).sum()
r2 = 1 - ss_res / ss_tot
print(f'R^2 = {r2:.4f}')
このコードを実行すると、 47都道府県データから 多重共線性に関連する係数・指標が直接得られます。 SSDSE-B-2026 が手元にない場合は、 統計データ活用コンペティション公式ページからダウンロードしてください。
多重共線性の診断は VIF だけではありません。 用途に応じて 4 つの指標を組み合わせると、 「どの変数群が」「どれくらい」「どんな方向で」共線になっているかが立体的に分かります。 SSDSE-B-2026 を素材に、 4 指標の使い分けを整理します。
| 指標 | 計算式・基準 | 分かること | 限界 |
|---|---|---|---|
| 相関係数 | |r| > 0.7 | 2 変数間の共線性 | 3 変数以上の同時共線性を見逃す |
| VIF | 1/(1-R²ⱼ) > 10 | 個別変数の共線寄与 | 「どの方向で」までは特定できない |
| 条件数 | √(λmax/λmin) > 30 | 設計行列全体の悪さ | 標準化前の値に依存 |
| 固有値分解 | λmin → 0 で危険 | 共線変数群の方向 | 計算量・解釈の難しさ |
import pandas as pd, numpy as np
from statsmodels.stats.outliers_influence import variance_inflation_factor
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
cols = ['人口(総数)', '一般世帯数', '15歳未満人口', '65歳以上人口']
X = df[cols].dropna()
Z = (X - X.mean()) / X.std()
# 1. 相関係数
print('相関行列:')
print(Z.corr().round(3))
# 2. VIF
print('\nVIF:')
for i, c in enumerate(cols):
print(f' {c}: {variance_inflation_factor(Z.values, i):.1f}')
# 3. 条件数
eig = np.linalg.eigvalsh(Z.T @ Z / len(Z))
print(f'\n条件数: {np.sqrt(eig.max()/eig.min()):.1f}')
# 4. 固有値(小さいもの = 共線方向)
print(f'最小固有値: {eig.min():.6f}')
# 出力例: 最小固有値 ≈ 0.0001 → 共線な部分空間が存在
| 戦略 | 使う場面 | 注意点 |
|---|---|---|
| 変数削減 | 解釈最優先 | ドメイン知識で選別、 機械的削除はバイアス源 |
| 主成分回帰 (PCR) | 予測重視 + 解釈断念 | 主成分の解釈が難しい |
| Ridge 回帰 | 予測最優先 | 係数解釈は OLS とは別物 |
| Lasso 回帰 | 変数選択も同時に | グループ化された変数の選択が不安定 |
| 標本サイズを増やす | 構造ではなく標本に起因する場合 | 追加調査のコスト |
💡 判断フロー:(1) まず VIF と相関行列でスクリーニング → (2) 共線性が見つかれば条件数で全体の悪さを確認 → (3) 解釈優先なら変数削減、 予測優先なら Ridge/Lasso → (4) 最終モデルで再診断、 を繰り返す。
多重共線性(multicollinearity)という用語は、 1934 年に経済学者 Ragnar Frisch が著書 Statistical Confluence Analysis by Means of Complete Regression Systems で初めて体系化したと言われています。 経済データは観測実験ができないため、 説明変数同士が強く絡み合い、 「真の構造方程式が一意に決まらない」問題に直面し続けてきました。 これが多重共線性研究の出発点です。
| 年 | 出来事 | 意義 |
|---|---|---|
| 1934 | Frisch が多重共線性を体系化 | 「経済学は実験できない」問題の理論化 |
| 1962 | Farrar & Glauber のクラシック論文 | VIF と関連指標の標準化 |
| 1970 | Hoerl & Kennard が Ridge 回帰を提案 | 予測重視の正則化路線 |
| 1980 | Belsley らが条件数診断を整備 | 設計行列の数値線形代数的診断 |
| 1996 | Tibshirani が Lasso を提案 | 同時変数選択と縮約 |
| 2005 | Zou & Hastie の Elastic Net | 共線変数群を「一緒に」扱う方法 |
多重共線性は OLS の BLUE 性(最良線形不偏推定量)を損ないません。 つまり「予測の平均的精度」は損なわれない。 しかし個別係数 βⱼ の 標準誤差 は分散拡大係数 VIF 倍に膨らみ、 「どの変数がどれだけ寄与しているか」の解釈が不安定になります。 この区別を理解しているかどうかが、 多重共線性を扱う初心者と熟練者の境界です。
説明変数行列 X が完全多重共線(rank(X) < p+1)の場合、 OLS の正規方程式 XᵀXβ = Xᵀy は解を一意に持たず、 (XᵀX)⁻¹ が存在しないため OLS 推定量は定義できません。 これは「設計行列が full column rank ではない」と等価で、 「ある説明変数が他の説明変数の線形結合で完全に再現できる」とも等価です。 SSDSE-B-2026 で「男性人口 + 女性人口 = 総人口」をすべて投入するような状況がこれに該当します。
import pandas as pd, numpy as np
import statsmodels.api as sm
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
df = df.dropna(subset=['人口(総数)', '一般世帯数'])
# 完全共線な変数を作る(世帯数 × 2)
df['世帯数x2'] = df['一般世帯数'] * 2
X = sm.add_constant(df[['一般世帯数', '世帯数x2']])
try:
model = sm.OLS(df['人口(総数)'], X).fit()
print(model.summary())
except Exception as e:
print('完全共線で推定不可:', e)
# statsmodels は警告を出しながら推定するが、 係数は意味を持たない
多重共線性は「珍しい問題」ではなく、 実データを扱えば ほぼ必ず 出会う問題です。 SSDSE-B-2026 や類似データセットでよく遭遇する 6 つの典型シナリオを整理し、 それぞれの対処を示します。
| # | シナリオ | SSDSE-B での例 | 推奨対処 |
|---|---|---|---|
| 1 | 和が一定(恒等式) | 男性人口 + 女性人口 = 総人口 | どれか 1 つを削除(恒等式の基底変換) |
| 2 | スケール変換のみ | 人口(人) と 人口(千人) | 片方削除 |
| 3 | 高相関(同一概念の代理) | 人口数 と 世帯数(r ≈ 0.99) | PCA、 ドメイン優先で 1 つ選択 |
| 4 | 多項式項の共線 | x と x²、 x と x³ | 中心化、 直交多項式 |
| 5 | 交互作用項 | x、 z、 x×z | 中心化、 標準化 |
| 6 | ダミー変数の罠 | 8 地方区分のダミー 8 個 | 基準カテゴリを 1 つ抜く |
import pandas as pd
from statsmodels.stats.outliers_influence import variance_inflation_factor
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
df = df.dropna(subset=['人口(総数)', '一般世帯数', '住宅総数'])
# シナリオ 3:同一概念の代理変数を 3 つ同時投入
X = df[['人口(総数)', '一般世帯数', '住宅総数']]
print('相関行列:')
print(X.corr().round(4))
# 期待:すべて r > 0.98 → 共線
print('\nVIF:')
for i, c in enumerate(X.columns):
print(f' {c}: VIF = {variance_inflation_factor(X.values, i):.0f}')
# VIF は 50-200 のオーダーで爆発する
import pandas as pd
import statsmodels.api as sm
from statsmodels.stats.outliers_influence import variance_inflation_factor
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1).copy()
df = df.dropna(subset=['人口(総数)'])
# 地域ダミーを 8 つ全部入れる(罠)
df['地方'] = df['都道府県'].map(lambda s: '東京' if s == '東京都' else 'その他')
dummies = pd.get_dummies(df['地方'])
# 全部投入:完全共線(dummies.sum(axis=1) == 1)
X = sm.add_constant(dummies.astype(float))
try:
model = sm.OLS(df['人口(総数)'], X).fit()
print(model.summary())
except Exception as e:
print('完全共線:', e)
# 解決:drop_first=True で基準カテゴリを抜く
dummies_ok = pd.get_dummies(df['地方'], drop_first=True)
print('修正後:', dummies_ok.columns.tolist())
import pandas as pd
from statsmodels.stats.outliers_influence import variance_inflation_factor
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
df = df.dropna(subset=['一般世帯数', '65歳以上人口'])
x = df['一般世帯数']
z = df['65歳以上人口']
# 中心化なし
X1 = pd.DataFrame({'x': x, 'z': z, 'xz': x * z})
print('中心化なし:')
for i, c in enumerate(X1.columns):
print(f' {c}: VIF = {variance_inflation_factor(X1.values, i):.1f}')
# 中心化あり
xc, zc = x - x.mean(), z - z.mean()
X2 = pd.DataFrame({'x': xc, 'z': zc, 'xz': xc * zc})
print('中心化あり:')
for i, c in enumerate(X2.columns):
print(f' {c}: VIF = {variance_inflation_factor(X2.values, i):.1f}')
drop_first=True を忘れない。💡 実務メモ:多重共線性は「設計の問題」であって「データの問題」ではないことが多い。 変数選択や前処理の段階で予防するのが、 後から VIF を見て泣くより早道です。
多重共線性が深刻なときに、 変数削減ではなく 正則化 で対処する流派があります。 主要 3 手法を SSDSE-B-2026 で並べて、 それぞれの強み・弱みを実体験しましょう。
| 手法 | 目的関数 | 変数選択 | 共線変数の扱い |
|---|---|---|---|
| OLS | ‖y − Xβ‖² | なし | 推定が不安定 |
| Ridge (L²) | ‖y − Xβ‖² + λ‖β‖² | なし(縮約のみ) | 均等に縮約 |
| Lasso (L¹) | ‖y − Xβ‖² + λ‖β‖₁ | あり(係数 → 0) | どれか 1 つを残す |
| Elastic Net | ‖y − Xβ‖² + λ₁‖β‖₁ + λ₂‖β‖² | あり | グループでまとめて残す |
import pandas as pd, numpy as np
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet
from sklearn.preprocessing import StandardScaler
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
cols = ['一般世帯数', '15歳未満人口', '65歳以上人口', '住宅総数']
df = df.dropna(subset=cols + ['人口(総数)'])
scaler = StandardScaler()
X = scaler.fit_transform(df[cols])
y = df['人口(総数)'].values
models = {
'OLS': LinearRegression(),
'Ridge λ=1': Ridge(alpha=1.0),
'Ridge λ=10': Ridge(alpha=10.0),
'Lasso λ=0.5': Lasso(alpha=0.5, max_iter=20000),
'EN α=0.5': ElasticNet(alpha=0.5, l1_ratio=0.5, max_iter=20000),
}
print(f"{'method':<14} " + ' '.join(f'{c[:6]:>8}' for c in cols))
for name, m in models.items():
m.fit(X, y)
coefs = m.coef_
print(f'{name:<14} ' + ' '.join(f'{c:>8.2f}' for c in coefs))
# Lasso では一部の係数がきれいに 0 に。 Ridge では均等縮約。
import numpy as np
from sklearn.linear_model import Ridge
lambdas = np.logspace(-2, 4, 30)
coefs_path = []
for lam in lambdas:
m = Ridge(alpha=lam).fit(X, y)
coefs_path.append(m.coef_)
coefs_path = np.array(coefs_path)
# 各係数が λ 増加に対してどう変化するかを表で表示
print(f'\n{"λ":>10} ' + ' '.join(f'{c[:6]:>8}' for c in cols))
for i, lam in enumerate(lambdas[::5]):
cf = coefs_path[i*5]
print(f'{lam:>10.3f} ' + ' '.join(f'{c:>8.2f}' for c in cf))
# λ → 0 で OLS、 λ → ∞ で全係数 0。 Ridge trace plot の素材。
| 状況 | 推奨 | 理由 |
|---|---|---|
| 変数すべてが意味あり | Ridge | 縮約のみ、 すべて残る |
| スパースな解が欲しい | Lasso | 変数選択と縮約が同時 |
| グループ共線あり | Elastic Net | グループごと残す |
| p >> n | Lasso or EN | 高次元での疎解探索 |
💡 実務メモ:λ は CV で選ぶ(RidgeCV, LassoCV)。 「縮約された係数の解釈」と「OLS の係数解釈」は別物 — 縮約モデルでは「効果の方向」程度しか言えないことを忘れずに。
多重共線性について実務でよく聞かれる 10 の質問と回答をまとめます。
絶対基準ではありません。 「予測」目的なら問題なし、 「個別係数の解釈」が目的なら標準誤差の膨らみを確認しましょう。 サンプルサイズも考慮。
OLS の予測 MSE は VIF に影響されません。 ただし「外挿」では危険。 訓練データの範囲を出ると共線性のせいで予測が大きく外れます。
はい、 共線性は消えます。 ただし「主成分の解釈」が困難になります。 解釈優先か予測優先かで選択。
予測目的では OK。 ただし係数の解釈は OLS と異なり、 「縮約された値」なので「効果の方向と相対的大きさ」程度しか言えません。
多項式項(x, x²)、 交互作用項(x×z)を作るときは必ず。 中心化なしでは VIF が 100 を超えることも。
k 個のカテゴリすべてをダミーにすると完全共線(合計 = 1)。 必ず drop_first=True で k-1 個にします。
Ridge か Elastic Net。 OLS では係数推定が崩壊しますが、 正則化なら全変数を残しつつ安定推定できます。
標本に起因する共線(標本相関)なら解決します。 ただし構造的な共線(恒等式・概念的重複)は標本数で解消できません。
はい。 標準誤差が VIF 倍に膨らみ、 t 値が小さくなって「有意でない」結論になりやすい(第二種の過誤)。
共線性は皆無ですが、 「変数選択が独立すぎる」場合、 各変数が説明する情報が分離しすぎている可能性も。 ドメイン知識で確認を。
💡 FAQ の心得:「多重共線性は悪」と短絡しないこと。 目的(予測 vs 推論)とデータ規模を踏まえて判断するのが、 実務家の腕の見せどころです。
分析を始める前・回帰モデルを構築する際・結果を報告する際の 3 段階で押さえるべき項目を整理します。
drop_first=True を使う💡 まとめ:多重共線性は「気づかなければスルー、 気づけば対処可能」な問題。 チェックリストを習慣化すれば、 査読でも実務でも怖くなくなります。