ある変数からもう 1 つの変数を直線で説明する手法が、単回帰分析(simple linear regression)です。本記事では、最小二乗法の式と直感、Python での実装、結果の読み方を整理します。

目次

  1. 単回帰のモデル
  2. 最小二乗法
  3. Python で計算する
  4. 決定係数 R2R^2
  5. statsmodels で詳細を見る
  6. 残差の確認

単回帰のモデル

説明変数 xx と目的変数 yy を、次の直線で関係づけるモデルです。

yi=β0+β1xi+εiy_i = \beta_0 + \beta_1 x_i + \varepsilon_i
  • β0\beta_0 : 切片(intercept)
  • β1\beta_1 : 傾き(slope)
  • εi\varepsilon_i : 誤差(noise)

株式の文脈では「市場リターン(xx)に対する個別銘柄リターン(yy)」のような関係を、傾き(β1\beta_1、ベータ)として表す使い方が代表例です。

最小二乗法

各点のずれの 2 乗和(残差平方和、residual sum of squares)を最小にする β0,β1\beta_0, \beta_1 を選ぶ手法が、最小二乗法(OLS、Ordinary Least Squares)です。

minβ0,β1i=1n(yiβ0β1xi)2\min_{\beta_0, \beta_1} \sum_{i=1}^{n} \left( y_i - \beta_0 - \beta_1 x_i \right)^2

解は閉じた形で求まります。

β^1=Cov(x,y)Var(x),β^0=yˉβ^1xˉ\hat{\beta}_1 = \frac{\mathrm{Cov}(x, y)}{\mathrm{Var}(x)}, \quad \hat{\beta}_0 = \bar{y} - \hat{\beta}_1 \bar{x}

傾きが共分散と分散の比で書けるのが、相関係数(#5-5「相関係数と共分散」)とつながる点です。

Python で計算する

NumPy の polyfit で 1 次の直線を当てはめる例です。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
rng = np.random.default_rng(0)
n = 250
# 市場リターン(説明変数)
market = rng.normal(loc=0.0, scale=0.012, size=n)
# 個別銘柄リターン: y = 0.0002 + 1.2 * market + ノイズ
stock = 0.0002 + 1.2 * market + rng.normal(0.0, 0.008, size=n)
slope, intercept = np.polyfit(market, stock, deg=1)
print(f"傾き(β1) : {slope:.4f}")
print(f"切片(β0): {intercept:.6f}")
# 予測線
xs = np.linspace(market.min(), market.max(), 100)
ys = intercept + slope * xs
fig, ax = plt.subplots(figsize=(6, 5))
ax.scatter(market, stock, alpha=0.5, s=10)
ax.plot(xs, ys, color="red")
ax.set_xlabel("market return")
ax.set_ylabel("stock return")
ax.set_title("Simple linear regression")
plt.tight_layout()
plt.show()

傾きが 1.2 付近に推定されていれば、市場が 1% 動いたとき個別銘柄が約 1.2% 動く、という関係を捉えています。

散布図と最小二乗法による回帰直線

決定係数 R2R^2

回帰の当てはまりの良さを表すのが、決定係数 R2R^2 です。

R2=1(yiy^i)2(yiyˉ)2R^2 = 1 - \frac{\sum (y_i - \hat{y}_i)^2}{\sum (y_i - \bar{y})^2}
  • R2=1R^2 = 1 : すべての点が回帰直線上にある
  • R2=0R^2 = 0 : 平均で予測するのと同じ程度の精度

単回帰の場合、R2R^2 は相関係数の 2 乗に等しくなります。

correlation = np.corrcoef(market, stock)[0, 1]
predicted = intercept + slope * market
ss_res = np.sum((stock - predicted) ** 2)
ss_tot = np.sum((stock - stock.mean()) ** 2)
r_squared = 1 - ss_res / ss_tot
print(f"相関係数: {correlation:.4f}")
print(f"R^2 : {r_squared:.4f}")

statsmodels で詳細を見る

p 値や信頼区間まで欲しい場合は statsmodels が手軽です。

import statsmodels.api as sm
X = sm.add_constant(market) # 切片用の定数列を加える
model = sm.OLS(stock, X).fit()
print(model.summary())

主な読みどころは次のとおりです。

  • coef: 回帰係数の推定値
  • std err: 標準誤差
  • t / P>|t|: 各係数の t 値と p 値(0 と異なるかの検定)
  • R-squared: 決定係数

残差の確認

回帰モデルの妥当性は、残差(実測値と予測値の差)の散らばりで確認します。

residuals = stock - predicted
fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(predicted, residuals, alpha=0.5, s=10)
ax.axhline(0, color="gray")
ax.set_xlabel("predicted")
ax.set_ylabel("residual")
ax.set_title("Residual plot")
plt.tight_layout()
plt.show()

理想的には、残差は予測値によらず 0 を中心に均等に散らばります。残差にパターン(扇型・曲線)が見えたら、線形モデルの仮定が崩れているサインです。

注意点

  • 単回帰は「1 つの変数だけで説明する」モデル。本来は複数要因の影響を受けるなら重回帰(#5-8「重回帰分析の入門」)
  • 外れ値に弱い(最小二乗法は 2 乗で重みづけるため、外れ値の影響が大きく出る)
  • 回帰係数の有意性検定は、残差が独立で分散一定・正規という前提に立つ
  • 過去の関係が将来も続く保証はない

生成AI へのプロンプト例

ベータ計算を関数化する例です。

銘柄リターン(pandas Series)と市場リターン(pandas Series)を受け取り、
単回帰でベータと R^2 を計算する関数 estimate_beta(stock_returns, market_returns)
を書いてください。
戻り値: dict
- alpha(切片)、beta(傾き)、r_squared
- n(観測数)、residual_std
要件:
- 入力に欠損があれば inner join で揃える
- pandas 2.2 系の API を使う
- numpy の polyfit ではなく statsmodels の OLS を使う
- docstring を日本語で書く

まとめ

  • 単回帰は 1 つの説明変数で目的変数を直線で説明するモデル
  • 最小二乗法の解は共分散と分散の比で書ける
  • 決定係数 R2R^2 は当てはまりの良さの指標
  • 残差プロットで仮定の妥当性を確認