2026年10月8日にstatsmodels 0.15のVIF関数とscikit-learnの前処理・交差検証本文を再確認した。VIFはある説明変数を他の説明変数で補助回帰したR²から、係数分散の膨張を点検する指標であり、万能の閾値や変数削除の自動規則ではない。相関表が見逃す線形関係、スケール、欠測、予測と係数解釈、モデル目的、交差検証、因果仮定を分け、VIFの数値だけで広告や施策の原因を判断しない。
広告費・営業人数・店舗数を使って売上を回帰したら、広告費の係数がマイナスになった。「広告を増やすと売上が下がる」と報告してよいでしょうか。
その係数は、他の入力を条件とした統計的な関連です。説明変数が一緒に動くと、それぞれの関連を切り分けにくくなります。ただし、符号が逆になる理由は多重共線性だけではありません。入力の単位、集計、モデルの形、交絡も確認します。
ここではVIFが表す分散の増幅と、係数そのもの・予測・因果を分けるため、架空4行の計算を使います。実在する会社の広告効果を推定した例ではありません。
30秒で要点
- VIFは、ある説明変数を他の説明変数で回帰した補助回帰のR²から計算します。売上などの目的変数のR²とは別です。
- VIFが5なら分散の増幅は5倍、標準誤差の相対増幅は√5倍です。同じノイズと変数の広がりを比較する、という条件があります。
- 大きいVIFだけでは、標準誤差が何円なのか、予測が悪いのか、変数を消すべきかは決まりません。
- 2変数ずつの相関が極端でなくても、複数を組み合わせた線形従属があり得ます。
- 分割を変えた感度確認は役立ちますが、2回一致しただけで安定性や因果効果を保証しません。
係数・標準誤差・VIFは違う数字
表が収まらない場合は、横にスクロールできます
| 用語 | 何を表すか | 取り違えやすい点 |
|---|---|---|
| 説明変数 | モデルに渡す入力。広告費、店舗数など | 単位・集計対象・欠測処理をそろえる |
| 係数 | 他の入力を固定したときの、モデル上の平均応答の変化 | その変数への介入効果とは限らない |
| 標準誤差 | 仮定の下での係数推定量の標準偏差の推定 | 残差の標準偏差や、個々の予測誤差とは別 |
| 多重共線性 | 入力の間に強い線形関係がある状態 | 2列の相関だけでは見つからない場合がある |
| VIF | 入力の線形関係による係数分散の増幅要因 | 係数の絶対値・因果・モデル全体の予測精度ではない |
| 交差検証 | データを分け、学習と評価や推定の変動を見る手順 | 独立性・時系列・同一対象の重複に合う分け方が必要 |
補助回帰のR²を使う
説明変数x1のVIFを知りたいなら、x1を目的変数として、残りの説明変数で回帰します。その決定係数を R1² として、VIF1 = 1/(1 - R1²) です。x1をほぼ再現できるほどR1²は1に近づき、独自に動く情報は少なくなります。
切片を含む完全ランクの通常の最小二乗法(OLS)で、誤差の条件付き平均が0、分散が一定σ²、誤差間の共分散が0という条件を置くと、係数の条件付き分散は次の形になります。
Var(β̂1 | X) = σ² / Sxx1 × VIF1、ただし Sxx1 = Σ(x1 - x1の平均)²。
σ²を残差平方和/残差自由度で推定した値s²に置き換えると、通常の標準誤差は SE(β̂1) = √(s² × VIF1 / Sxx1)。相関のない仮想設計との比較で、s²とSxx1を固定したときの相対増幅が√VIFです。
したがって、VIFだけを見て標準誤差の絶対的な大きさは決められません。ノイズ、入力の単位・広がり、標本構成も関係します。異分散に頑健な標準誤差などを使う場合も、この単純な式をそのまま代入しないでください。
架空4行で、増幅の条件を固定する
平均0のベクトル u=(-1,-1,1,1) と v=(-1,1,-1,1) を使います。内積は0、各平方和は4です。x1=u、x2=u+εv とすると、x2がx1に近づくほど切り分けが難しくなります。
この構成では R1²=1/(1+ε²)、VIF1=(1+ε²)/ε²。s²を0.01、Sxx1を4に固定した値を計算します。
表が収まらない場合は、横にスクロールできます
| ε | 補助回帰R1² | VIF1 | SE(β̂1) |
|---|---|---|---|
| 1.00 | 0.500000 | 2 | 0.070711 |
| 0.50 | 0.800000 | 5 | 0.111803 |
| 0.25 | 0.941176 | 17 | 0.206155 |
| 0.10 | 0.990099 | 101 | 0.502494 |
これは母集団から精度を測った実験ではなく、式の分母を確かめる教材です。下の応答を使う例は4行に切片と2係数を推定するので、残差自由度は1しかありません。実務に十分な標本数を示すものではありません。
小さい応答の変更で、係数の符号が変わる例
ε=0.1に固定し、さらに w=(1,-1,-1,1) を用意します。wは切片、u、vに直交します。応答は y=10+2u+kv+0.05w とし、kだけを0.15から0.25に変えます。
表が収まらない場合は、横にスクロールできます
| 行 | x1 | x2 | yA(k=0.15) | yB(k=0.25) |
|---|---|---|---|---|
| 1 | -1 | -1.1 | 7.90 | 7.80 |
| 2 | -1 | -0.9 | 8.10 | 8.20 |
| 3 | 1 | 0.9 | 11.80 | 11.70 |
| 4 | 1 | 1.1 | 12.20 | 12.30 |
x2=u+0.1vなので、モデル y≈β0+β1x1+β2x2 の最小二乗解は β0=10、β2=k/0.1、β1=2-k/0.1 になります。w成分は残差として残ります。
表が収まらない場合は、横にスクロールできます
| 応答 | 切片 | x1の係数 | x2の係数 | 残差平方和 | 残差自由度 |
|---|---|---|---|---|---|
| yA | 10 | 0.5 | 1.5 | 0.01 | 1 |
| yB | 10 | -0.5 | 2.5 | 0.01 | 1 |
各応答の差の絶対値は0.1なのに、x1の係数は正から負へ変わります。一方、観測した4点での当てはめの差も各0.1です。係数をそれぞれ識別する難しさと、観測点への当てはまりを分けて読む例です。「予測精度は変わらない」と一般化するための外部評価はしていません。
相関表だけでは見つからない線形従属
別の設計として、入力をu、v、u+vの3列にすると、相関はuとvで0、残りの2組で約0.707です。それでも第3列は第1列と第2列の和なので、完全な線形従属です。どの相関も0.8未満だから安全、とは言えません。
数学上、完全に説明される列のVIFは無限大に向かい、係数の一意な分解ができません。ソフトウェアではR²の丸めやクリップにより、無限大でなく大きな有限値が返ることもあります。確認したstatsmodels 0.15.0の掲載ソースはR²を上限でクリップしています。関数の数値だけでなく、行列のランクも確認します。
Pythonで係数・VIF・ランクを別々に計算する
次はNumPyで補助回帰と最小二乗解を直接計算する教材です。切片を明示的に追加します。statsmodelsのOLS仕様でも、配列入力には通常切片を自分で追加する必要があります。以下はstatsmodelsの関数を実行した結果ではありません。
import numpy as np
u = np.array([-1., -1., 1., 1.])
v = np.array([-1., 1., -1., 1.])
w = np.array([1., -1., -1., 1.])
ones = np.ones(4)
for eps in [1., 0.5, 0.25, 0.1]:
x2 = u + eps * v
aux = np.column_stack([ones, x2])
residual = u - aux @ np.linalg.lstsq(aux, u, rcond=None)[0]
r2 = 1 - residual @ residual / (u @ u)
vif = 1 / (1 - r2)
se = np.sqrt(0.01 * vif / (u @ u))
print("eps, R2, VIF, SE", eps, r2, vif, se)
np.testing.assert_allclose(vif, (1 + eps**2) / eps**2)
x = np.column_stack([ones, u, u + 0.1 * v])
for k in [0.15, 0.25]:
y = 10 + 2*u + k*v + 0.05*w
beta = np.linalg.lstsq(x, y, rcond=None)[0]
residual = y - x @ beta
df = len(y) - np.linalg.matrix_rank(x)
s2 = (residual @ residual) / df
se = np.sqrt(np.diag(s2 * np.linalg.inv(x.T @ x)))
print("k, coefficients, s2, df, SE", k, beta, s2, df, se)
np.testing.assert_allclose(beta, [10, 2-k/0.1, k/0.1])
np.testing.assert_allclose(s2, 0.01)
np.testing.assert_allclose(se[1], np.sqrt(0.01*101/4))
dependent = np.column_stack([ones, u, v, u+v])
print("dependent rank / columns", np.linalg.matrix_rank(dependent), 4)
assert np.linalg.matrix_rank(dependent) == 3
完全従属の設計では係数を解釈する処理へ進めません。欠測行の除去で診断対象が変わっていないか、定数列、同じ列の重複、切片と全カテゴリのダミー変数の重複も確認します。単位をそろえるだけでは、元の線形関係は消えません。
AGEとEXPERIENCEの例を、一般則にしない
scikit-learnの公式教材は、賃金データのAGEとEXPERIENCEを使い、交差検証の分割間で係数が動く例を示しています。片方の係数が正、他方が負になる領域が現れ、AGEを除いた例ではEXPERIENCEの変動が小さくなります。これは、そのデータ・前処理・モデルでの観測です。年齢と経験年数を扱えば必ず同じ符号になる、片方を消せばすべて解決する、という結論ではありません。
変数を消すと、「他の何を一定とした関連か」という問いも変わります。交絡調整に必要な変数を、VIFを下げる目的だけで除くと別の問題を作ります。正則化で係数が安定しても、推定対象やバイアスは変わります。予測目的なら未使用データで評価し、説明・因果目的なら識別の条件に戻る必要があります。
符号に驚いたときの、小さい確認手順
最初に、報告しようとしている係数と、その単位・他の調整変数を1つの文で書きます。「広告費を動かす効果」と言い換えず、「この入力を条件とした関連」と書けるかを確かめます。
- 設計行列を確認する:重複・定数・ダミー変数・欠測行を確認し、ランクと相関表を見ます。
- 補助回帰と不確実性を見る:VIF、通常または設計に合う標準誤差、区間、残差の構造を並べます。VIFだけで絶対SEは判断しません。
- 分け方を理由付きで変える:時系列なら未来を学習へ混ぜず、同一対象の反復なら対象単位を守るなど、利用場面に合う分割にします。係数の感度と予測の評価は別欄に残します。
- 問いに戻る:入力を削除する、設計・収集を改善する、予測に正則化を使う、今のデータでは個別の関連を切り分けられないと報告する、という選択肢を比べます。
旧来の「期間を前半・後半に分けて2回一致すれば使える」「大きさが2倍違えば不可」という単独基準は置きません。2分割の一致は一つの観測で、母集団の安定性や施策の妥当性の証明にはならないからです。
最後に、VIFが低く、符号が安定し、標準誤差が小さくても因果は別です。計測していない交絡があり得ます。冒頭のマイナス係数から広告削減額を直接決めず、何を検証すれば判断が変わるかを整理してください。状況を整理する(15分)も、その問いを言語化する入口として使えます。