K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

線形回帰

入門

02.1.1

線形回帰

最終更新 2020-01-29 読了時間 3 分
まとめ
線形回帰は、散らばった点の中に 1 本の直線 \(y = wx + b\) を引いて、未知の \(x\) に対する \(y\) を予測する手法です。直線の選び方は最小二乗法で、各点と直線のズレ(残差)を 2 乗して足した値が最小になる傾き \(w\) と切片 \(b\) を選びます。この解は平均と分散から式 1 本で求まるため、LinearRegression().fit() は反復計算なしに一瞬で終わります。読み終えると、傾きを「\(x\) が 1 増えたときの \(y\) の変化量」として説明でき、外れ値やスケール差で直線がどう歪むかを見抜けるようになります。
動画で見る:線形回帰① 最小二乗法で直線を当てはめる(K_DM チャンネル)

直感 #

気温とアイスの売上を 10 日分メモして散布図にすると、点は右上がりの帯になります。「明日は 31 ℃」と聞かれたとき、帯のまん中を通る直線を 31 ℃ まで延長して読む。これが線形回帰のやっていることです。直線は無数に引けるので、最小二乗法は「各点から直線までの縦のズレを 2 乗して全部足した値」がいちばん小さい 1 本を選びます。2 乗するのは、上のズレと下のズレが打ち消し合わないようにするためで、同時に大きく外れた点ほど強く効く性質も生みます。

何が起きているか(ステップで見る) #

「最小二乗法」が何を最小にしているのかを、図で確かめます。各点と直線のズレ(残差)を 1 辺とする正方形を描くと、その面積の合計が残差二乗和(SSE)です。直線を動かすと面積の合計 SSE が減り、最後に最小二乗解に着きます。

見るポイント:残差 4 の点が作る正方形は残差 1 の点の正方形 16 個分で、2 乗の効果で外れた 1 点が直線を強く引っぱる様子が、手順を進めるたびに正方形の面積として見えます。直線の上側と下側の正方形が打ち消し合わない(2 乗で両方プラスになる)ことも確認してください。最後の手順の直線は、下のコードで LinearRegression().fit() が式 1 本で求める解と同じです。

具体的な数式 #

一次の線形モデルは

$$ y = w x + b $$

で表されます。観測値と予測値の差(残差)\(\epsilon_i = y_i - (w x_i + b)\) の二乗和を目的関数

$$ L(w, b) = \sum_{i=1}^{n} \big(y_i - (w x_i + b)\big)^2 $$

として \(w, b\) で偏微分して 0 と置くと、反復なしに次の解が得られます。

$$ w = \frac{\sum_{i=1}^{n} (x_i - \bar{x})(y_i - \bar{y})}{\sum_{i=1}^{n} (x_i - \bar{x})^2}, \qquad b = \bar{y} - w \bar{x} $$

ここで \(\bar{x}, \bar{y}\) はそれぞれの平均です。複数の入力を使う重回帰でも、ベクトルと行列を用いて同様に最小二乗解を導くことができます。

多重共線性(重回帰で説明変数どうしが強く相関している状態)があると、係数 \(w\) が不安定になり解釈が困難になります。VIF(分散インフレ係数)が10を超える変数は除外や結合を検討してください。

Pythonを用いた実験や説明 #

次のコードは、真の関係 \(y = 2x + 1\) にノイズを足した 100 点を作り、LinearRegression で直線を推定して観測値と重ねて描きます。行番号の横の青い番号、または下の「コードの解説」から各部分の意図を確認できます。

 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
32
33
34
from __future__ import annotations

import matplotlib.pyplot as plt
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

def plot_simple_linear_regression(n_samples: int = 100) -> None:
    """Plot a fitted linear regression model for synthetic data.

    Args:
        n_samples: Number of synthetic samples to generate.
    """
    rng = np.random.default_rng(seed=0)

    X: np.ndarray = np.linspace(-5.0, 5.0, n_samples, dtype=float)[:, np.newaxis]
    noise: np.ndarray = rng.normal(scale=2.0, size=n_samples)
    y: np.ndarray = 2.0 * X.ravel() + 1.0 + noise

    model = make_pipeline(StandardScaler(with_mean=False), LinearRegression())
    model.fit(X, y)
    y_pred: np.ndarray = model.predict(X)

    fig, ax = plt.subplots(figsize=(10, 5))
    ax.scatter(X, y, marker="x", label="Observed data", c="orange")
    ax.plot(X, y_pred, label="Regression fit")
    ax.set_xlabel("$x$")
    ax.set_ylabel("$y$")
    ax.legend()
    fig.tight_layout()
    plt.show()

plot_simple_linear_regression()

コード本体は既存のものをそのまま利用していますの図

実行結果の読み方 #

図の青い直線が推定結果で、傾き \(w\) は真の値 2.0 に、切片 \(b\) は 1.0 に近づきます。傾きは「\(x\) が 1 増えたとき \(y\) が約 2 増える」と読み、切片は \(x = 0\) のときの平均的な \(y\) です。推定値そのものは model[-1].coef_ と model[-1].intercept_ で取り出せます。ノイズの標準偏差を 2.0 にしているので、×印は直線から上下におよそ 2 の幅で散らばります。

特徴量のスケール差が大きい場合は StandardScaler を適用すると、係数の大小を直接比較できるようになります。make_pipeline に組み込むと学習・推論で一貫したスケーリングが保たれます。

ノイズと回帰直線 #

ノイズの大きさが回帰直線のフィッティングにどう影響するか確認できます。

まとめ #

線形回帰の中身は「残差二乗和 \(\sum \epsilon_i^2\) を最小にする直線を 1 本選ぶ」だけです。その解は平均と分散から閉じた式で求まるので、LinearRegression は 100 万行でも反復なしに係数を返します。読むときは傾き \(w\) を「\(x\) が 1 増えたときの \(y\) の変化量」、切片 \(b\) を「\(x = 0\) のときの期待値」と解釈します。外れ値は 2 乗の分だけ強く効くので、次の一手は ロバスト回帰 です。説明変数どうしの相関(VIF が 10 超)には リッジ・ラッソ、曲がった関係には 多項式回帰 を選びます。

参考文献 #

  • Draper, N. R., & Smith, H. (1998). Applied Regression Analysis (3rd ed.). John Wiley & Sons.
  • Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning. Springer.