線形回帰:最小二乗法から本番環境対応の実践まで

タグ: machinelearning, datascience, python, tutorial

線形回帰はほとんどの人が最初に学ぶアルゴリズムであり、ほとんどの人が深く研究しないアルゴリズムでもあります。また、より高度なアルゴリズムが失敗した後も本番環境で見つかるモデルでもあります。なぜなら、高速で安定しており、説明可能だからです。

この記事は「.fit() を呼び出してスコアを読む」というチュートリアルではありません。数学、統計的仮定、診断、正則化、評価、本番環境の懸念事項、そして初心者とエンジニアを区別する面接質問をカバーします。

なぜ線形回帰が再検討に値するのか

線形回帰は、ほぼすべての他の教師ありモデルの理解の基盤です:

  • ロジスティック回帰は、シグモイド関数を上に乗せた線形回帰です。
  • Ridge と Lasso は、重みに制約を加えた線形回帰です。
  • ニューラルネットワークは、非線形活性化関数を持つ線形変換の積み重ねです。
  • ツリーモデルは、同じベースラインに対して判断されます:「線形モデルを上回ることができるか?」

さらに重要なのは、線形回帰が多くのビジネス問題で依然として正しい答えであることです。規制当局、クライアント、または財務チームに予測を説明する必要がある場合、解釈可能な係数を持つクリーンな線形モデルは、ブラックボックスよりも優れています。

数学:最小二乗法と正規方程式

特徴量 X とターゲット y が与えられると、線形モデルは以下を仮定します:

y = X * beta + epsilon

Enter fullscreen mode Exit fullscreen mode

目的は残差平方和を最小化することです:

L(beta) = ||y - X*beta||^2

Enter fullscreen mode Exit fullscreen mode

beta に対する導関数を取り、それをゼロに設定すると、正規方程式が得られます:

beta = (X^T * X)^(-1) * X^T * y

Enter fullscreen mode Exit fullscreen mode

実際には、逆行列の代わりに疑似逆行列(pinv)を使用します。なぜなら、特徴量が共線性を持つ場合、X^T X は特異または数値的に不安定になる可能性があるからです。

import numpy as np

def normal_equation(X, y):
    Xb = np.c_[np.ones(X.shape[0]), X]  # 切片の追加
    beta = np.linalg.pinv(Xb.T @ Xb) @ Xb.T @ y
    return beta

Enter fullscreen mode Exit fullscreen mode

最小二乗法の3つの等価な視点

1. 幾何学的視点

予測 X * beta は、yX の列空間への射影です。最小二乗法は、その部分空間の中で最も近い点を見つけます。これが、残差が適合値に対して直交する理由です。

2. 最尤推定の視点

以下を仮定します:

epsilon ~ N(0, sigma^2)

Enter fullscreen mode Exit fullscreen mode

すると、対数尤度の最大化は、二乗誤差和の最小化と等価になります。このつながりは、OLS の係数はより緩やかな仮定のもとでも一致性を持つにもかかわらず、残差の正規性が信頼区間にとって重要である理由を説明します。

3. 最適化の視点

大規模なデータセットの場合、(X^T X)^(-1) の計算は高コストになります。勾配降下法は、同じ目的関数を反復的に解きます:

def gradient_descent(X, y, lr=0.01, epochs=500):
    Xb = np.c_[np.ones(X.shape[0]), X]
    n, d = Xb.shape
    beta = np.zeros(d)
    for _ in range(epochs):
        grad = (2 / n) * Xb.T @ (Xb @ beta - y)
        beta -= lr * grad
    return beta

Enter fullscreen mode Exit fullscreen mode

正規方程式:正確で、小規模から中規模のデータセットに最適。勾配降下法:スケーラブルだが、特徴量のスケーリングと学習率の調整が必要です。

確認すべき仮定

高い R-squared を持つ適合モデルが自動的に信頼できるわけではありません。これらの仮定が、係数を解釈可能にするものです:

仮定 意味 確認方法
線形性 特徴量とターゲットの間の線形関係 残差 vs 適合値プロット
独立性 誤差が相関していない Durbin-Watson 統計量
等分散性 誤差分散が一定 Breusch-Pagan 検定、残差プロット
正規性 誤差が正規分布している Q-Q プロット、Jarque-Bera 検定
多重共線性の不在 特徴量が高度に相関していない VIF、相関行列

完全な診断手順

import statsmodels.api as sm
from statsmodels.stats.stattools import durbin_watson
from statsmodels.stats.diagnostic import het_breuschpagan
from statsmodels.stats.outliers_influence import variance_inflation_factor
from scipy import stats
import pandas as pd

X_const = sm.add_constant(X_train)
model = sm.OLS(y_train, X_const).fit()
resid = model.resid

print("Durbin-Watson:", durbin_watson(resid))
# 2 に近い値は自己相関がないことを意味します;0 または 4 に近い場合は警告です。

lm, lm_pvalue, fvalue, f_pvalue = het_breuschpagan(resid, X_const)
print("Breusch-Pagan p値:", f_pvalue)
# p > 0.05: 異分散性の強い証拠はありません。

print("Jarque-Bera p値:", stats.jarque_bera(resid).pvalue)
# p > 0.05: 正規性に対する強い証拠はありません。

vif = pd.DataFrame({
    "feature": X_train.columns,
    "VIF": [variance_inflation_factor(X_train.values, i)
            for i in range(X_train.shape[1])],
})
print(vif)
# VIF > 10 は、多重共線性の警告として一般的に扱われます。

Enter fullscreen mode Exit fullscreen mode

正則化:バイアス-分散のトレードオフ

通常の最小二乗法は訓練誤差を最小化し、特徴量が多い場合や共線性がある場合に過学習する可能性があります。正則化はペナルティを追加します:

Ridge:       L = MSE + alpha * sum(beta_i^2)
Lasso:       L = MSE + alpha * sum(|beta_i|)
ElasticNet:  L = MSE + alpha * (r * L1 + (1 - r) * L2)

Enter fullscreen mode Exit fullscreen mode

モデル ペナルティ 効果 最適な場合
Ridge L2 重みを縮小し、すべての特徴量を保持 多くの相関する特徴量がある場合
Lasso L1 一部の重みを正確にゼロに縮小 特徴量選択が必要な場合
ElasticNet L1 + L2 相関するグループに対してスパースだが安定 両方のニーズの混合

重要な詳細: 正則化の前に常に特徴量を標準化してください。そうしないと、ペナルティが大きさの大きい特徴量を不公平に縮小します。

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet

models = {
    "OLS": LinearRegression(),
    "Ridge(alpha=1)": Ridge(alpha=1.0),
    "Lasso(alpha=0.01)": Lasso(alpha=0.01),
    "ElasticNet(alpha=0.01)": ElasticNet(alpha=0.01, l1_ratio=0.5),
}

for name, model in models.items():
    pipe = make_pipeline(StandardScaler(), model)
    pipe.fit(X_train, y_train)
    y_pred = pipe.predict(X_test)
    print(f"{name:20s} RMSE={mean_squared_error(y_test, y_pred, squared=False):.4f} "
          f"R2={r2_score(y_test, y_pred):.4f}")

Enter fullscreen mode Exit fullscreen mode

評価指標

R-squared のみを報告しないでください。各指標は異なるストーリーを語ります:

指標 式の意味 使用する場合
MAE 平均絶対誤差 誤差を二乗すべきではなく、外れ値があまり重要でない場合
RMSE 平均二乗誤差の平方根 大きな誤差が特に悪い場合
MAPE 平均絶対パーセント誤差 ビジネスがパーセントでの解釈を望む場合
説明された分散の割合 モデルの品質を比較する場合
調整済み R² 特徴量数でペナルティを受けた R² 異なる特徴量セットを持つモデルを比較する場合

常に平均ベースラインと比較してください。モデルが「平均を予測する」よりもわずかに優れているだけの場合、特徴量はあまり価値を追加していません。

baseline_pred = np.full_like(y_test, y_train.mean())
print("ベースライン RMSE:", mean_squared_error(y_test, baseline_pred, squared=False))

Enter fullscreen mode Exit fullscreen mode

完全なエンドツーエンドの例

import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

data = fetch_california_housing(as_frame=True)
X = data.frame.drop(columns=["MedHouseVal"])
y = data.frame["MedHouseVal"]

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 1. 手作りの正規方程式
beta = normal_equation(X_train.values, y_train.values)
X_test_b = np.c_[np.ones(X_test.shape[0]), X_test.values]
y_pred_manual = X_test_b @ beta

# 2. sklearn ベースライン
from sklearn.linear_model import LinearRegression
lr = LinearRegression().fit(X_train, y_train)
y_pred_sklearn = lr.predict(X_test)

for name, y_pred in [("manual", y_pred_manual), ("sklearn", y_pred_sklearn)]:
    print(f"{name}: RMSE={mean_squared_error(y_test, y_pred, squared=False):.4f} "
          f"MAE={mean_absolute_error(y_test, y_pred):.4f} "
          f"R2={r2_score(y_test, y_pred):.4f}")

Enter fullscreen mode Exit fullscreen mode

手動の解と sklearn の解は、ほぼ同一の数値を生成するはずです。そうでない場合、勾配降下法が収束していないか、特徴量がスケーリングされていない可能性があります。

本番環境チェックリスト

  1. 特徴量のスケーリング: 勾配降下法と正則化モデルに必要。
  2. 交差検証: テストセットで alpha を調整しない。
  3. データ漏洩: スケーリング、エンコーディング、または補完の前に分割する。
  4. 監視: デプロイ後に特徴量の分布と予測のドリフトを追跡。
  5. 説明可能性: 監査のために係数、特徴量重要度、SHAP 値を記録。
  6. シンプルさを優先: XGBoost に手を伸ばす前に、線形回帰から始める。

よくある間違い

1. 相関は因果関係ではない

高い係数は、特徴量の変更がターゲットを変更することを意味しません。省略変数と逆因果関係は常に可能性があります。

2. 外挿

線形モデルは訓練範囲外では危険です。300㎡までの住宅で訓練されたモデルは、3000㎡の住宅の価格を教えてくれません。

3. 高い R-squared は良い予測を意味しない

R-squared はサンプル内適合度を測定します。モデルは訓練データで高い R-squared を持ち、未知のデータでひどい RMSE を持つ可能性があります。

4. 残差の無視

残差にパターンがある場合、モデルは構造を欠いています。非線形パターンを修正するために、盲目的に線形特徴量を追加しないでください。

5. 生の特徴量を正則化に使用する

標準化なしでは、Ridge と Lasso は異なる単位で測定された特徴量に不均等なペナルティを適用します。

準備すべき面接質問

  1. 正規方程式と勾配降下法の違いは何ですか?
  2. 正規誤差仮定の下で、OLS が最尤推定と等価である理由は何ですか?
  3. X^T X が特異の場合、何が起こり、Ridge はどのように役立ちますか?
  4. 多重共線性をどのように検出し、修正しますか?
  5. R-squared の代わりに調整済み R-squared を使用する理由は何ですか?
  6. 残差 vs 適合値プロットは何を教えてくれますか?
  7. Ridge よりも Lasso を好むのはどのような場合ですか?
  8. L1 または L2 正則化の前に標準化しなければならない理由は何ですか?
  9. 異分散性の結果は何ですか?
  10. 回帰パイプラインでデータ漏洩をどのように検出しますか?

結論

線形回帰はシンプルに見えますが、機械学習の核心的なアイデアを含んでいます:目的関数、最適化、統計的仮定、正則化、評価、そしてデプロイメント。この1つのモデルを深く理解すれば、その後のすべてのアルゴリズムが学びやすくなります。

数学から始め、仮定を検証し、本番環境の懸念事項を念頭に置いてください。「シンプルすぎる」モデルは、しばしば本番環境で最も長く生き残るモデルです。


役に立ちましたか?より実践的な AI とデータエンジニアリングの投稿のために、私をフォローしてください。
没 ;。l