複数の説明変数を組み合わせて目的変数を予測するのが、重回帰分析(multiple linear regression)です。本記事では、行列形式での定式化、Python での実装、よく踏む落とし穴(多重共線性など)を整理します。

目次

  1. 重回帰のモデル
  2. 株式分析でのよくある使い方
  3. Python で計算する
  4. 決定係数と自由度調整
  5. 多重共線性
  6. カテゴリ変数(ダミー変数)
  7. 残差診断

重回帰のモデル

説明変数を pp 個用意して、目的変数を直線(超平面)で表します。

yi=β0+β1xi1+β2xi2++βpxip+εiy_i = \beta_0 + \beta_1 x_{i1} + \beta_2 x_{i2} + \cdots + \beta_p x_{ip} + \varepsilon_i

行列で書くと、

y=Xβ+ε\mathbf{y} = X \boldsymbol{\beta} + \boldsymbol{\varepsilon}

最小二乗法の解は次のとおりです(XXX^\top X が可逆なとき)。

β^=(XX)1Xy\hat{\boldsymbol{\beta}} = (X^\top X)^{-1} X^\top \mathbf{y}

行列演算で求まることが、単回帰との大きな違いです。

株式分析でのよくある使い方

目的変数説明変数の例
個別銘柄の月次リターン市場リターン、業種ダミー、サイズ要因
翌期 EPS売上成長率、営業利益率、過去 EPS
ボラティリティ出来高、前期ボラ、業種

学術的には Fama-French 3 ファクターモデルなどが知られています(本記事ではモデル詳細は扱いません)。

Python で計算する

statsmodels で重回帰を組む例です。

import numpy as np
import pandas as pd
import statsmodels.api as sm
rng = np.random.default_rng(2)
n = 300
# 説明変数 3 つ
x1 = rng.normal(0.0, 1.0, size=n)
x2 = rng.normal(0.0, 1.0, size=n)
x3 = rng.normal(0.0, 1.0, size=n)
# 目的変数: y = 0.5 + 0.8*x1 - 0.3*x2 + 0.0*x3 + noise
y = 0.5 + 0.8 * x1 - 0.3 * x2 + 0.0 * x3 + rng.normal(0.0, 0.5, size=n)
df = pd.DataFrame({"x1": x1, "x2": x2, "x3": x3, "y": y})
X = sm.add_constant(df[["x1", "x2", "x3"]])
model = sm.OLS(df["y"], X).fit()
print(model.summary())

coef 列で係数の推定値、P>|t| 列で各係数の有意性を確認します。

決定係数と自由度調整

説明変数を増やすと、R2R^2 は機械的に上がります。本当に説明力が増えたかを見るには、自由度を考慮した 自由度調整済み決定係数 を使います。

Radj2=1(1R2)×n1np1R^2_{\text{adj}} = 1 - (1 - R^2) \times \frac{n - 1}{n - p - 1}

statsmodels の出力では Adj. R-squared の行に表示されます。説明変数を 1 つ追加して R^2 だけが上がり Adj. R-squared が下がる場合、その変数は実質的な情報を持っていない可能性があります。

多重共線性

重回帰で最も注意すべき落とし穴が 多重共線性(multicollinearity) です。説明変数同士の相関が強いと、各係数の推定値が不安定になります。

判定の目安として、VIF(Variance Inflation Factor、分散拡大係数) が使われます。

VIFj=11Rj2\text{VIF}_j = \frac{1}{1 - R_j^2}

ここで Rj2R_j^2 は、変数 jj を他の説明変数で回帰したときの決定係数です。慣例的には次のラインを使います。

VIF の値解釈
1〜5大きな問題なし
5〜10注意
10 以上多重共線性が疑わしい
from statsmodels.stats.outliers_influence import variance_inflation_factor
X_no_const = df[["x1", "x2", "x3"]]
vif = pd.DataFrame({
"feature": X_no_const.columns,
"VIF": [variance_inflation_factor(X_no_const.values, i)
for i in range(X_no_const.shape[1])],
})
print(vif)

VIF が高い変数があれば、変数を削るか、主成分分析(PCA)などで合成変数に置き換える対処が一般的です。

カテゴリ変数(ダミー変数)

業種・市場区分のようなカテゴリ変数は、ダミー変数(0/1 の列)に展開してから回帰に入れます。pandas の get_dummies が手軽です。

sample = pd.DataFrame({
"sector": ["IT", "金融", "製造", "IT", "金融"],
"x": [1.0, 2.0, 3.0, 4.0, 5.0],
"y": [1.1, 1.9, 3.2, 4.0, 5.1],
})
dummies = pd.get_dummies(sample["sector"], drop_first=True)
features = pd.concat([sample[["x"]], dummies], axis=1)
X = sm.add_constant(features.astype(float))
model = sm.OLS(sample["y"], X).fit()
print(model.params)

drop_first=True で 1 つのカテゴリを基準にして、係数を「基準カテゴリとの差分」として読みます。

残差診断

単回帰と同様、残差プロットで仮定を確認します。

  • 残差と予測値の散布図 → 0 を中心に均等な散らばりが理想
  • QQ プロット → 残差の正規性を確認
  • 残差の自己相関(時系列データの場合) → Durbin-Watson 統計量

statsmodels の summary には Durbin-Watson 値が表示されます。2 付近なら自己相関は小さい、0 や 4 に近いと正・負の自己相関があるサインです。

注意点

  • 説明変数の単位が桁違いだと、係数の大きさを直感で比べられません(必要に応じて標準化する)
  • 過去の関係が将来も続く保証はないため、サンプル外検証 が必須
  • 説明変数の選び方によっては、データに過剰に適合する オーバーフィット に陥ります(分割検証や正則化が対策)
  • 株式リターンでは、リーク(将来情報の混入)に特に注意します

生成AI へのプロンプト例

要因モデルを汎用的に組む例です。

目的変数 y(pandas Series)と、説明変数の DataFrame X(列が要因)を受け取り、
重回帰の結果を整理して返す関数 fit_factor_model(y, X) を書いてください。
戻り値: dict
- params(係数の Series)、p_values(Series)
- r_squared、adj_r_squared
- vif(各説明変数の VIF を入れた DataFrame)
- residuals(残差の Series)
要件:
- statsmodels の OLS を使う
- 切片を自動で追加
- pandas 2.2 系の API を使う
- docstring を日本語で書く

まとめ

  • 重回帰は複数の説明変数を線形に組み合わせるモデル
  • 自由度調整済み R2R^2 で「変数を増やした効果」を評価する
  • 多重共線性は VIF で確認、5〜10 以上は要注意
  • カテゴリ変数はダミー変数に展開、係数は「基準カテゴリとの差」として読む
  • オーバーフィットを避けるため、サンプル外検証を組み合わせる