論文中に 「多重共線性」として登場する用語。
多重共線性 とは:説明変数同士が強く相関している状態。回帰係数の推定が不安定になり、p値が大きくなる。
多重共線性(multicollinearity)は、 重回帰で説明変数同士が強く相関している状態。 これがあると、 「個々の係数は信用できないが、 予測自体はそこそこ正しい」という厄介な状況になります。
症状(あるある):
原因:説明変数同士が強く相関していると、 OLS の解 $(X^\top X)^{-1}$ で逆行列が不安定になります。 「x1 と x2 が一緒に動くので、 どっちが効いているか分けられない」状態。
検出:
対処法:
覚えておくべき真実:多重共線性は「モデルが悪い」ではなく「係数の解釈ができない」状態。 予測精度には影響しない。 「個別の変数の効果」を主張したいときだけ深刻になる。
2つの説明変数 X1・X2 の相関 r をスライダーで変え、 目的変数 Y への重回帰
Y = β₁X1 + β₂X2 + 誤差 を 閉形式の2変数OLSで正確に推定します。
真の値は β₁ = β₂ = 1.0。 相関を高めると、 推定される係数の
標準誤差が膨張し、 データを僅かに揺らすだけで係数が大きく振れる様子(=多重共線性)を体感できます。
👉 グラフの上を ドラッグ(スマホは指でスワイプ)すると、 同じ真の関係のまま「別の標本を引き直し」ます。 相関が高いほど、 少し揺らすだけで推定点(●)が対角線上を大きく行き来します。
-
X1 と X2 が「似た動き」をすると、 OLS は「Y の増加分を X1 のおかげにするか X2 のおかげにするか」を決められません。 右パネルの推定点(●)の散らばりが 対角線(右下↘)方向に伸びた楕円になるのはこのためで、 「β̂₁ を大きくすれば β̂₂ を小さくしても当てはまりはほぼ同じ」=両者を足した効果 (β₁+β₂) はよく決まるのに、 個別には決まらないことを表します。 相関を r → 0 に下げると楕円は丸くなり、 推定は安定します。
関連ページ: —
多重共線性(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 13 14 15 16 | from statsmodels.stats.outliers_influence import variance_inflation_factor
import pandas as pd
# SSDSE-B-2026(2023年、47都道府県)の実在列で VIF を計算
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
X = df[['A1101', 'A4101', 'A5101', 'A9101']].rename(columns={
'A1101': '総人口', 'A4101': '出生数', 'A5101': '転入', 'A9101': '婚姻'
}).astype(float)
X = (X - X.mean()) / X.std() # 標準化
vif_df = pd.DataFrame({
'feature': X.columns,
'VIF': [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
})
print(vif_df.sort_values('VIF', ascending=False).round(2))
|
VIF の式 $\text{VIF}_j = 1 / (1 - R_j^2)$ を言葉に直すと: R²_j は「説明変数 x_j を、 残りの説明変数すべてで回帰したときの当てはまり」。 つまり「x_j は他の x で何 % 説明できるか」。 これが 0 なら VIF=1(独立、 問題なし)、 0.9 なら VIF=10(x_j の 90% は他の変数で説明可能、 多重共線性が深刻)、 1 に近づくと VIF は無限大に発散。 「分散がどれだけ膨らむか」の倍率なので、 VIF=10 は「係数の分散が独立時の 10 倍に膨張」と読める。
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 プロセスより)
💡 この 6 工程はデータ分析全般の流れで、 この用語だけの話ではない。 多重共線性は「データ理解」で気づき、 「モデリング」で対処する。 VIF はデータ理解の段階で計算できる。
| 分野 | 主要技術 | 代表ツール |
|---|---|---|
| 記述統計 | 要約量、 可視化 | 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 |
これらは互いに深く関連します:
SSDSE-B-2026 の実在列では、 「総人口」「出生数」「転入」「婚姻」のような規模系列が強く相関しており、 一緒に重回帰に入れると VIF が大きくなる典型例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
X = df[['A1101', 'A4101', 'A5101', 'A9101']].rename(columns={
'A1101': '総人口', 'A4101': '出生数', 'A5101': '転入', 'A9101': '婚姻'
}).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 | 判定 |
|---|---|---|
| 総人口 | 113.20 | 深刻 |
| 出生数 | 163.72 | 深刻 |
| 転入 | 30.03 | 深刻 |
| 婚姻 | 143.44 | 深刻 |
「総人口」「出生数」「転入」「婚姻」を同時に入れると、 全変数で VIF が 10 を超えました。 代表変数を 1 つに絞るか、 これら 4 変数から主成分を 1 つ作って代用する解決法が定石です。
statsmodels.stats.outliers_influence.variance_inflation_factor(標準)1 2 3 4 5 | import pandas as pd from statsmodels.stats.outliers_influence import variance_inflation_factor as vif_fn vifs = pd.Series([vif_fn(X.values, i) for i in range(X.shape[1])], index=X.columns) print(vifs.round(2)) |
numpy.linalg による条件数1 2 | cond_num = np.linalg.cond(X.values) print(f'条件数 = {cond_num:.1f}') # > 30 で多重共線性疑い |
sklearn.linear_model.Ridge(多重共線性に強い回帰)1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
features = ['A1101', 'A4101', 'A5101', 'A9101']
labels = ['総人口', '出生数', '転入', '婚姻']
X = StandardScaler().fit_transform(df[features].astype(float))
y = df['I5102'].astype(float).values
ridge = Ridge(alpha=10.0).fit(X, y)
coef = {label: float(value) for label, value in zip(labels, ridge.coef_.round(2))}
print('coef =', coef)
print(f'R² = {ridge.score(X, y):.4f}')
|
sklearn.decomposition.PCA → 主成分回帰1 2 3 4 5 6 7 8 9 10 | import pandas as pd
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
X = StandardScaler().fit_transform(df[['A1101', 'A4101', 'A5101', 'A9101']].astype(float))
pca = PCA(n_components=4).fit(X)
print('PC 寄与率', pca.explained_variance_ratio_.round(4))
print('累積寄与率', pca.explained_variance_ratio_.cumsum().round(4))
|
1 2 3 4 5 6 7 8 9 10 11 | import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
X = df[['A1101', 'A4101', 'A5101', 'A9101']].rename(columns={
'A1101': '総人口', 'A4101': '出生数', 'A5101': '転入', 'A9101': '婚姻'
}).astype(float)
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つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 前処理 › 変換 › 多重共線性
中心に 多重共線性 を置き、 そこから Ridge回帰・LASSO・相関係数・重回帰・PCA・Elastic Net など 計 12 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。
大きな円が小さな円を包含する Circle Packing 図。 「多重共線性」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「多重共線性」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 ジャストインタイム学習のヒント:3つの視点を行き来することで、 概念を多角的に理解できます。 包含マップやツリーマップはズーム/ドリルダウンで大分類から細部まで探索できます。
多重共線性の本質は、 説明変数が「束」で動くため、 束全体の効きは分かるが、 個々への配分が決まらないことにあります。 ここから 予測(当てる) と 推論(各変数の効果を語る) で毒性が非対称になります。
つまり「モデルが悪い」のではなく「問いが分不相応」なのです。 データが答えられる問い(束の効き)と答えられない問い(各変数の分離)を混同すると事故になります。
drop_first=True で基準カテゴリを1つ落とすのが定石。 「合計=各内訳の和」を同時投入するのも同じ罠。総人口・出生数・転入者数・婚姻件数を同時に説明変数にした例(いずれも人口規模で一斉に動く「束」)。 実データでの数値です。
💡 この節の要点:多重共線性は「予測には概ね無害・推論には有害」という非対称性が核心。 VIF 閾値は目安に過ぎず、 標準化では解決せず、 変数削除もバイアスと引き換え。 目的(予測か推論か)を先に決めてから対処法を選ぶ。
本セクションは「多重共線性」を 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 で再現します。 まず一行で読み込めるよう、 引数を直書きしたシンプル版を示します:
1 2 3 | # 最小コード(直書き) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] |
続いて、 列名はリポジトリ準拠(A1101 総人口、 A4101 出生数、 A5101 転入、 A9101 婚姻、 I5102 一般診療所)の本番コードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) # 2023 年の 47都道府県スナップショット sub = df[df['SSDSE-B-2026'] == 2023].copy() x = sub['A1101'].astype(float) # 総人口 y = sub['I5102'].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:,.6f}') # 0.000909 print(f'beta0 = {beta0:,.4f}') # -174.4478 print(f'相関係数 = {x.corr(y):.4f}') # 0.9717 # 残差・決定係数も計算 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 が手元にない場合は、 統計データ活用コンペティション公式ページからダウンロードしてください。
ここでは、 数式や表だけでは伝わりにくい多重共線性のイメージを 3 枚の図で確認します。 左の図は説明変数同士がどれくらい揃って動いているかを散布で示し、 中央の図は VIF・相関ヒートマップで「どこに共線性の塊があるか」を一目で把握できる構図、 右の図は対処策(リッジ・ラッソ)が共線性下で係数をどのように安定させるかを比較したものです。
2 つの説明変数 X1・X2 がほぼ同じ方向に動くと、 回帰の解は「X1 の係数を増やして X2 を減らす」あるいは「逆」のどちらでも当てはまりが同じになり、 一意に決まらなくなります。 図のように散布が直線上に乗っているほど、 係数の標準誤差が膨張し、 p 値が大きくなり、 結果として「重要な変数なのに有意でない」という誤った結論が出やすくなります。
SSDSE-B-2026 から「総人口・出生数・転入・婚姻」のような関連指標を取り出して相関行列を可視化すると、 ほとんどの組で |r| > 0.95 が並びます。 セルが深い赤になっている箇所が共線性のホットスポットで、 そのまま回帰に投入すると VIF が 10 を大幅に超えます。 まずヒートマップで全体像を眺め、 次に VIF・条件数で定量化、 という順序が実務で扱いやすい流れです。
OLS(左)は共線性の影響で係数が大きく振れる一方、 リッジ回帰(中央)は係数を 0 近くに縮め、 ラッソ回帰(右)は寄与の小さい変数を完全に 0 にして変数選択まで行います。 「予測だけが目的」ならリッジ、 「解釈と変数選択を両立したい」ならラッソ、 という使い分けが基本です。 ただし係数が縮むぶん解釈の意味も変わるため、 学術論文の主分析で使う際は補足分析として OLS も併記するのが安全です。
多重共線性は「症状(係数の符号反転、 巨大な SE)」と「診断指標(VIF、 条件数)」を併用しないと見抜けない。 ここでは SSDSE-B-2026 を使い、 4 段階で確認する。
このコードでやること: 「総人口」「出生数」「転入」「婚姻」など実在する人口規模系列の相関行列を計算し、 |r|>0.9 のペアをリストする。
📥 入力: SSDSE-B-2026.csv(47都道府県)。 数値カラムを 4-6 個選択。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
cols = ['A1101', 'A4101', 'A5101', 'A9101'] # 総人口/出生数/転入/婚姻
df_sub = df[cols + ['I5102']].rename(columns={
'A1101': '総人口', 'A4101': '出生数', 'A5101': '転入',
'A9101': '婚姻', 'I5102': '一般診療所'
}).astype(float)
features = ['総人口', '出生数', '転入', '婚姻']
corr = df_sub[features].corr()
print(corr.round(3))
print()
print('|r|>0.9 のペア:')
for i in range(len(corr)):
for j in range(i+1, len(corr)):
if abs(corr.iloc[i,j]) > 0.9:
print(f' {corr.columns[i]} - {corr.columns[j]}: r={corr.iloc[i,j]:.3f}')
|
📤 実行例:
💬 結果の読み方: 6 ペアすべてで |r|>0.95 近辺。 これらを重回帰に同時投入すると、 ほぼ確実に多重共線性が深刻になる。 同じ人口規模を反映する変数は互いの代理指標になりやすいため、 代表変数を選ぶ必要がある。
このコードでやること: statsmodels の variance_inflation_factor で各変数の VIF を計算する。 VIF > 10 なら除外候補。
📥 入力: 上記 df_sub の 4 列をすべて使う。
1 2 3 4 5 6 7 8 9 10 | import pandas as pd
from statsmodels.stats.outliers_influence import variance_inflation_factor
features = ['総人口', '出生数', '転入', '婚姻']
X = df_sub[features]
Z = (X - X.mean()) / X.std()
vif_rows = []
for i, name in enumerate(Z.columns):
vif_rows.append({'変数': name, 'VIF': variance_inflation_factor(Z.values, i)})
print(pd.DataFrame(vif_rows).round(2).to_string(index=False))
|
📤 実行例:
💬 結果の読み方: 全変数が VIF > 10、 特に「総人口」「出生数」「婚姻」は 100 を超える。 ドメイン知識で代表変数を 1 つ残し、 再計算して VIF が十分下がるかを確認する。
このコードでやること: 一般診療所を目的変数として、 「総人口だけ」と「総人口 + 出生数」の 2 モデルで係数を比較する。 多重共線性下では係数の符号や大きさが大きく変わる。
📥 入力: 同じ df_sub。
1 2 3 4 5 6 7 8 | from sklearn.linear_model import LinearRegression
for cols in [['総人口'], ['総人口','出生数'], ['総人口','出生数','転入'], ['総人口','出生数','転入','婚姻']]:
X = df_sub[cols].values
y = df_sub['一般診療所'].values
m = LinearRegression().fit(X, y)
coef_str = ', '.join(f'{c}={v:.6f}' for c, v in zip(cols, m.coef_))
print(f'{cols}: {coef_str}')
|
📤 実行例:
💬 結果の読み方: 「総人口」の符号が、 出生数を加えた瞬間に正から負へ反転する。 これは多重共線性の典型的な症状で、 経済的直感に反する係数が出る。 個別係数を解釈するのは危険。
このコードでやること: 同じデータに Ridge 回帰を適用し、 alpha を変えたときの係数の挙動と R² を観察する。
📥 入力: 同じ df_sub の 4 変数(総人口、 出生数、 転入、 婚姻)。
1 2 3 4 5 6 7 8 9 10 11 | from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
features = ['総人口', '出生数', '転入', '婚姻']
X = StandardScaler().fit_transform(df_sub[features])
y = df_sub['一般診療所'].values
for alpha in [0.0, 1.0, 10.0, 100.0]:
m = Ridge(alpha=alpha).fit(X, y)
r2 = m.score(X, y)
print(f'alpha={alpha:6.1f}: 係数={m.coef_.round(2)} R²={r2:.4f}')
|
📤 実行例:
💬 結果の読み方: alpha=0(OLS)では婚姻だけが極端に大きく、 他の係数が負になるが、 alpha を上げると 4 変数の係数が穏当な正の値に近づく。 R² の低下は比較的小さい(0.9802 → 0.9646)。 解釈と予測のバランスを取るなら alpha=10 が良い妥協点。
合成 3 変数で他変数による R² から VIF を計算する。
| 変数 | R² | VIF |
|---|---|---|
| x1 | 0.10 | 1.11 |
| x2 | 0.50 | 2.00 |
| x3 | 0.95 | 20.0 |
1 2 3 4 5 | import numpy as np r2 = np.array([0.10, 0.50, 0.95]) vif = 1/(1-r2) print(f"VIF: {vif}") print(f"問題変数 index: {np.where(vif >= 10)[0]}") |
💬 手計算 (Step 2) x3 (VIF=20) と Python 出力が完全一致。
「多重共線性」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。
多重共線性は回帰係数の符号反転・標準誤差膨張という形で現れる。 SSDSE-B-2026 で「総人口」と「出生数」を両方説明変数に入れると、 2023年データでは VIF が 100 を超えるため、 一方を除く、 もしくはリッジで縮小するのが定石。
「multicollinearity」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「multicollinearity」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「multicollinearity の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
似すぎたデータが混ざる現象です。
正しい分析結果を出すために使います。
テストの点数と勉強時間を両方使う例です。
この現象の正体と解決策を読みます。
🍰 まずはやさしく
分析の準備をするためのチェック項目です。
計算ミスのような間違いを防ぐために使います。
部活のデータ分析で役立つ知識です。
診断の方法から対策までを順番に読みます。
このページは 重回帰分析の「前提条件チェック」における中核トピック「多重共線性 (multicollinearity)」の解説。 全 SSDSE-B-2026 ベース教材の中で、 重回帰 → 残差診断 → 多重共線性診断 → 正則化回帰 という学習パスの 3 番目に位置する。 前提として 重回帰分析 と 相関係数 の理解が必要。 本ページ後は リッジ回帰・主成分分析・VIF への接続が自然。
🍰 まずはやさしく
役割が重なるメンバーが多すぎる状態です。
どのデータが本当に重要かを知るために使います。
スマホの利用時間とSNSの時間が似ている例です。
数値で問題を見つける流れを読みます。
多重共線性は「重回帰の説明変数同士がほぼ線形従属になり、 X'X 行列が反転に不安定になる」現象。 SSDSE-B-2026 で「総人口」と「出生数」を同時に説明変数にすると、 両者の相関は 0.9954 となり、 係数の標準誤差が爆発して係数の符号さえ実行ごとに反転しうる。 これが「個別では強い効果に見えるのに、 統合すると効果が消える」典型的な共線性パターン。
本ページでは (1) 入力: 「総人口」「出生数」「転入」「婚姻」を含む説明変数行列 → (2) 処理: VIF (Variance Inflation Factor) と条件数の算出 → (3) 出力: VIF > 10 の変数特定 → (4) 解釈: 「per capita 化 / Ridge / Lasso のどれを選ぶか」の 4 段階で診断と対処を追う。
次節以降では、 47 都道府県のサブセット 5 件で X'X の固有値を手計算し、 条件数の悪化を確認した上で、 statsmodels と sklearn の VIF / Ridge で同じ結論が出ることを示す。
🍰 まずはやさしく
データの重なり具合を数式で表したものです。
客観的に問題を判断するために使います。
買い物で似た商品を比べる感覚に近いです。
定義と計算のルールについて読みます。
multicollinearity の定義や代表的な数式を以下に示す。 数式の各記号の意味は次節で言葉に翻訳する。
multicollinearity は文脈に応じて複数の定式化があるが、 教育目的では最も基本的な形を抑えることが重要。 具体的な値での計算例は後続セクションを参照。
$$\text{multicollinearity}: f(\mathbf{X}, \boldsymbol{\theta}) \to y$$
記号の対応はこうです。 $\text{VIF}_j$ は説明変数 $j$ の分散拡大係数。 $R_j^2$ は「変数 $j$ を、残りの説明変数すべてで回帰したときの決定係数」で、 $j$ が他の変数でどれだけ説明できてしまうかを表します。 $R_j^2 = 0$(他と無関係)なら $\text{VIF} = 1$、 $R_j^2 = 0.9$ なら $\text{VIF} = 10$、 $R_j^2 = 0.99$ なら $100$。 VIF の値は「係数の標準誤差が何倍に膨らむか」の2 乗を意味するので、 $\text{VIF} = 10$ なら標準誤差は $\sqrt{10} \approx 3.2$ 倍です。 目安の「VIF > 10 で要注意」は、 $R_j^2 > 0.9$ に相当します。
前節の数式に含まれる記号を、 日本語の意味に翻訳する。
multicollinearity の数式は、 これらの記号を組み合わせて「データから未知量を推定する」あるいは「データの構造を要約する」プロセスを記述している。
multicollinearity を SSDSE-B-2026 の実データで具体的に計算する手順を示す。 数式 → 値代入 → 手計算 → Python 実装 の流れで、 結果が一致することを確認する。
使用データ: SSDSE-B-2026 の 47 都道府県 × 主要列。 まず 5-10 都道府県の小さな部分集合で手計算し、 全件は Python で実行する。
| Step | 操作 | 実際の値 |
|---|---|---|
| 1 | 説明変数を 3 つ選ぶ | 総人口・65 歳以上人口・出生数(2023 年度・47 県) |
| 2 | 相関行列を見る | 総人口×出生数 = 0.9954、 総人口×65 歳以上 = 0.9910 — すべて 0.98 超 |
| 3 | 総人口を他 2 列で回帰 | $R^2 = 0.9968$ |
| 4 | VIF を計算 | $\mathrm{VIF} = 1/(1-0.9968) = 309.07$ |
| 5 | 他の列も同様に | 65 歳以上人口 72.33 / 出生数 142.30 — いずれも目安の 10 を大きく超える |
📥 入力:data/raw/SSDSE-B-2026.csv の 2023 年度 47 都道府県。 このコードでやること:Step 3〜5 の VIF を定義どおり「他の列で回帰した $R^2$」から計算し、 手計算と一致するか確かめる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import pandas as pd import numpy as np d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) d = d[d['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)] d = d[pd.to_numeric(d['年度'], errors='coerce') == 2023].reset_index(drop=True) num = lambda c: pd.to_numeric(d[c], errors='coerce') X = pd.DataFrame({ '総人口': num('総人口'), '65歳以上人口': num('65歳以上人口'), '出生数': num('出生数'), }) # VIF_j = 1 / (1 - R^2_j)。R^2_j は「列 j を他の列で回帰した決定係数」 def vif(X, j): y = X.iloc[:, j].values Z = X.drop(X.columns[j], axis=1).values Z = np.column_stack([np.ones(len(Z)), Z]) # 切片を足す beta, *_ = np.linalg.lstsq(Z, y, rcond=None) resid = y - Z @ beta r2 = 1 - (resid ** 2).sum() / ((y - y.mean()) ** 2).sum() return r2, 1 / (1 - r2) for j, col in enumerate(X.columns): r2, v = vif(X, j) print(f'{col:12s} R^2 = {r2:.4f} VIF = {v:8.2f}') print() print('相関行列:') print(X.corr().round(4).to_string()) |
📤 実行すると次の出力が得られる:
💬 VIF が 309 ということは、 総人口の係数の分散が、 他の列と無相関だった場合の 309 倍に膨らんでいるという意味。 標準誤差はその平方根で約 17.6 倍。 これでは個別の係数を解釈できない。 3 列とも「県の規模」を測っているので、 1 つに絞るか、 人口当たりの比率に直して規模の影響を抜く。
multicollinearity を Python で実装する代表的なコードを示す。 標準ライブラリ (numpy / pandas / scipy / sklearn / statsmodels) を使い、 SSDSE-B-2026 を読み込んで実行する流れを再現できる。
🎯 このコードでやること: multicollinearity を計算するための最小限のコード。 入力データ・処理・出力・結果の読み方を明示する。
📥 入力データ: SSDSE-B-2026 (47 都道府県 × 100 超列) の CSV。
1 2 3 4 5 | import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
print(df[['Prefecture', 'A1101', 'A4101', 'A5101', 'A9101']].head())
|
📤 実行結果: 出力された数値を読み、 他手法との比較や有意性検証を行う。
💬 結果の読み方: multicollinearity の出力は単なる数値ではなく、 データの構造や規則性を要約したもの。 適切な解釈と他指標との併用が重要。
multicollinearity を実務で使う際に頻発する誤用・落とし穴を列挙する。 多くは「前提の確認不足」「結果の過信」「他手法との比較不足」が原因で、 事前にチェックリスト化することで回避できる。
multicollinearity を中心に、 関連する概念・上位カテゴリ・応用領域を放射状に配置した。
「multicollinearity」を中心に、 隣接する手法・概念との関係を以下に整理する。 単独の手法理解にとどまらず、 分析パイプライン全体での位置付けを把握することで、 適切な前段・後段・代替手法を選べる。
| 隣接手法 | 関係 | 接続のポイント |
|---|---|---|
| 重回帰分析 | 上位 / 一般化 | 多重共線性は重回帰の係数推定が不安定化する現象 |
| VIF / 条件数 | 下位 / 特殊化 | 共線性を定量化する 2 大診断指標 (VIF>10、 条件数>30 で深刻) |
| Ridge / Lasso 回帰 | 並列 / 対比 | 正則化で X'X 行列を安定化させる代替案 |
| 標準化 / per capita 化 | 前段 (前処理) | スケール統一と本質的共線性の解消 |
| 主成分回帰 (PCR) | 後段 (後処理) | 直交化された主成分を説明変数として再構成 |
| 係数の符号・標準誤差 | 評価 / 比較 | 共線性の影響を係数の不安定性で目視判定 |
「multicollinearity」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。
| シナリオ | 重視する観点 | 候補手法 |
|---|---|---|
| VIF > 10 の変数が複数 | 個別係数の解釈が重要 | 一方の変数を削除 (ドメイン知識で選択) |
| VIF > 10 だが全変数が重要 | 予測精度重視 | Ridge 回帰 (係数を安定化) |
| 変数選択も自動化したい | 解釈性 + 疎性 | Lasso 回帰 (不要変数をゼロに) |
| 予測のみが目的 | 係数解釈不要 | そのまま重回帰 (共線性は予測には響かない) |
| 時系列・パネルデータ | 個別効果の分離 | 固定効果モデル / 階差変数の利用 |
| 47 都道府県のような小標本 | 解釈性 + 過学習回避 | per capita 化 + Ridge |
多重共線性の診断は VIF だけではありません。 用途に応じて 4 つの指標を組み合わせると、 「どの変数群が」「どれくらい」「どんな方向で」共線になっているかが立体的に分かります。 SSDSE-B-2026 を素材に、 4 指標の使い分けを整理します。
| 指標 | 計算式・基準 | 分かること | 限界 |
|---|---|---|---|
| 相関係数 | |r| > 0.7 | 2 変数間の共線性 | 3 変数以上の同時共線性を見逃す |
| VIF | 1/(1-R²ⱼ) > 10 | 個別変数の共線寄与 | 「どの方向で」までは特定できない |
| 条件数 | √(λmax/λmin) > 30 | 設計行列全体の悪さ | 標準化前の値に依存 |
| 固有値分解 | λmin → 0 で危険 | 共線変数群の方向 | 計算量・解釈の難しさ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
cols = ['A1101', 'A4101', 'A5101', 'A9101']
labels = {'A1101': '総人口', 'A4101': '出生数', 'A5101': '転入', 'A9101': '婚姻'}
X = df[cols].rename(columns=labels).astype(float)
Z = (X - X.mean()) / X.std()
# 1. 相関係数
print('相関行列:')
print(X.corr().round(3))
# 2. VIF
print()
print('VIF:')
for i, c in enumerate(Z.columns):
print(f' {c}: {variance_inflation_factor(Z.values, i):.2f}')
# 3. 条件数
eig = np.linalg.eigvalsh(Z.T @ Z / len(Z))
print()
print(f'条件数: {np.sqrt(eig.max()/eig.min()):.1f}')
# 4. 固有値(小さいもの = 共線方向)
print(f'最小固有値: {eig.min():.6f}')
|
| 戦略 | 使う場面 | 注意点 |
|---|---|---|
| 変数削減 | 解釈最優先 | ドメイン知識で選別、 機械的削除はバイアス源 |
| 主成分回帰 (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 で「年少人口 + 高齢人口を総人口と同時に扱う」をすべて投入するような状況がこれに該当します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd, numpy as np
import statsmodels.api as sm
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].dropna(subset=['A4101', 'I5102'])
# 完全共線な変数を作る(出生数 × 2)
df['出生数x2'] = df['A4101'].astype(float) * 2
X = sm.add_constant(pd.DataFrame({
'出生数': df['A4101'].astype(float),
'出生数x2': df['出生数x2']
}))
try:
model = sm.OLS(df['I5102'].astype(float), X).fit()
print(model.summary())
except Exception as e:
print('完全共線で推定不可:', e)
print('rank:', np.linalg.matrix_rank(X.values), 'cols:', X.shape[1])
|
多重共線性は「珍しい問題」ではなく、 実データを扱えば ほぼ必ず 出会う問題です。 SSDSE-B-2026 や類似データセットでよく遭遇する 6 つの典型シナリオを整理し、 それぞれの対処を示します。
| # | シナリオ | SSDSE-B での例 | 推奨対処 |
|---|---|---|---|
| 1 | 和が一定(恒等式) | 年少人口 + 高齢人口を総人口と同時に扱う | どれか 1 つを削除(恒等式の基底変換) |
| 2 | スケール変換のみ | 人口(人) と 人口(千人) | 片方削除 |
| 3 | 高相関(同一概念の代理) | 総人口 と 出生数(r = 0.9954) | PCA、 ドメイン優先で 1 つ選択 |
| 4 | 多項式項の共線 | x と x²、 x と x³ | 中心化、 直交多項式 |
| 5 | 交互作用項 | x、 z、 x×z | 中心化、 標準化 |
| 6 | ダミー変数の罠 | 東京/その他のダミー 2 個 | 基準カテゴリを 1 つ抜く |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd
from statsmodels.stats.outliers_influence import variance_inflation_factor
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
X = df[['A1101', 'A4101', 'A9101']].rename(columns={
'A1101': '総人口', 'A4101': '出生数', 'A9101': '婚姻'
}).astype(float)
# シナリオ 3:同一概念の代理変数を 3 つ同時投入
print('相関行列:')
print(X.corr().round(4))
Z = (X - X.mean()) / X.std()
print()
print('VIF:')
for i, c in enumerate(Z.columns):
print(f' {c}: VIF = {variance_inflation_factor(Z.values, i):.1f}')
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd
import statsmodels.api as sm
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]).copy()
df = df[df['SSDSE-B-2026'] == 2023].dropna(subset=['A1101'])
# 2 区分ダミーを基準カテゴリなしで全部入れる(罠)
df['地域区分'] = df['Prefecture'].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['A1101'].astype(float), 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())
|
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
from statsmodels.stats.outliers_influence import variance_inflation_factor
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].dropna(subset=['A1101', 'A1303'])
x = df['A1101'].astype(float) # 総人口
z = df['A1303'].astype(float) # 高齢人口
# 中心化なし
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β‖² + λ₁‖β‖₁ + λ₂‖β‖² | あり | グループでまとめて残す |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
cols = ['A1101', 'A4101', 'A5101', 'A9101']
labels = {'A1101': '総人口', 'A4101': '出生数', 'A5101': '転入', 'A9101': '婚姻'}
df = df.dropna(subset=cols + ['I5102'])
scaler = StandardScaler()
X = scaler.fit_transform(df[cols].astype(float))
y = df['I5102'].astype(float).values
names = [labels[c] for c in cols]
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 names))
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 では均等縮約。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 を使う💡 まとめ:多重共線性は「気づかなければスルー、 気づけば対処可能」な問題。 チェックリストを習慣化すれば、 査読でも実務でも怖くなくなります。