18  ロジスティック回帰

18.1 二値分類

50人の学生がある試験を受けた.各学生の勉強時間を X,試験の合格・不合格を Y とする.ここで,Y は次のように定義される二値変数である.

Y = \begin{cases} 1 & \text{合格} \\ 0 & \text{不合格} \end{cases}

下の散布図では,横軸が勉強時間 X,縦軸が合格・不合格 Y を表している.

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression

np.random.seed(0)
X = np.random.uniform(0, 100, 50)
y = (X + np.random.normal(0, 15, 50) > 50).astype(int)

X = X.reshape(-1, 1)  # sklearn 用に変形する
model = LogisticRegression()
model.fit(X, y)

plt.scatter(X, y)
x_values = np.linspace(0, 100, 200).reshape(-1, 1)
y_values = model.predict_proba(x_values)[:, 1]
plt.plot(x_values, y_values, color="red", label="$p(X)$")
plt.xlabel("Study Time (X)")
plt.ylabel("Result (Y)")
plt.legend()
plt.show()

ロジスティック回帰は,説明変数 X を使って,目的変数 Y の確率を予測するための手法である.例えば,ある学生が X=70 時間勉強したときに,その学生が合格する確率は P(Y=1|X=70) と表される.これ以降,この確率を p(X) と略記する.

18.2 ロジスティック関数

ロジスティック関数(logistic function)は次のように表される.

p(X) = \frac{1}{1 + e^{-(\beta_0 + \beta_1 X)}}

ここで,X は説明変数,\beta_0\beta_1 はパラメータである.ロジスティック関数は -\infty から \infty の範囲の X を入力として,0 から 1 の範囲の確率 p(X) を出力する.

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-100, 100, 400)
beta_0 = 0
beta_1 = 0.1
p_X = 1 / (1 + np.exp(-(beta_0 + beta_1 * X)))
plt.plot(X, p_X)
plt.title("Logistic Function")
plt.xlabel("X")
plt.ylabel("p(X)")
plt.grid()
plt.show()

18.3 オッズとロジット

オッズ(odds)は,ある事象が起こる確率と起こらない確率の比率を表す.

\text{odds} = \frac{p(X)}{1 - p(X)}

例えば,5回に1回成功する場合,成功の確率は 0.2 であるが,オッズは

\frac{0.2}{0.8} = \frac{1}{4} = 0.25

となる.

オッズは 0 から \infty の範囲を取り,確率 p(X)0.5 のときオッズは 1 になる.

ロジット(logit)はオッズの対数を取ったもので,次のように表される.

\text{logit}(p(X)) = \log\left(\frac{p(X)}{1 - p(X)}\right) = \beta_0 + \beta_1 X

ロジットは -\infty から \infty の範囲を取り,確率 p(X)0.5 のときロジットは 0 になる.

18.4 尤度関数

ロジスティック回帰モデルのパラメータ \beta_0\beta_1 を推定するために,尤度関数を最大化する.

L(\beta_0, \beta_1) = \prod_{i:y_i=1} p(x_i) \prod_{i:y_i=0} (1 - p(x_i))

この式は,

L(\beta_0, \beta_1) = \prod_{i=1}^{n} p(x_i)^{y_i} (1 - p(x_i))^{1 - y_i}

で表すこともできる.

この関数の対数を取ったものを対数尤度関数と呼び,次のように表される.

\begin{align*} \ell(\beta_0, \beta_1) &= \log L(\beta_0, \beta_1) \\ &= \sum_{i=1}^{n} \left[ y_i \log p(x_i) + (1 - y_i) \log (1 - p(x_i)) \right] \end{align*}

\ell(\beta_0, \beta_1) を最大化する \beta_0\beta_1 を求めることは,-\ell(\beta_0, \beta_1) を最小化することと同じである.ここでは,最小化問題を考えるために,損失関数 J を次のように定義する.尤度関数 L とは別の記号を用いることに注意する.

J(\beta_0, \beta_1) = - \ell(\beta_0, \beta_1) = \sum_{i=1}^{n} \left[ - y_i \log p(x_i) - (1 - y_i) \log (1 - p(x_i)) \right]

18.5 勾配降下法

損失関数 J(\beta_0, \beta_1) を最小化するために,勾配降下法を用いる.損失関数の各パラメータに関する偏微分は次のようになる.

\begin{align*} \frac{\partial J}{\partial \beta_0} &= \sum_{i=1}^{n} (p(x_i) - y_i) \\ \frac{\partial J}{\partial \beta_1} &= \sum_{i=1}^{n} (p(x_i) - y_i) x_i \end{align*}

これらの偏微分を用いて,パラメータを更新する.学習率を \alpha とすると,更新式は次のようになる.

\begin{align*} \beta_0 &\leftarrow \beta_0 - \alpha \frac{\partial J}{\partial \beta_0} \\ \beta_1 &\leftarrow \beta_1 - \alpha \frac{\partial J}{\partial \beta_1} \end{align*}

18.6 scikit-learn による実装

上記のロジスティック回帰モデルは,scikit-learn の LogisticRegression クラスを用いて簡単に実装できる.以下にその例を示す.

import numpy as np
from sklearn.linear_model import LogisticRegression

# データの生成
np.random.seed(0)
X = np.random.uniform(0, 100, 50).reshape(-1, 1)
y = (X.flatten() + np.random.normal(0, 15, 50) > 50).astype(int)

# ロジスティック回帰モデルの学習
model = LogisticRegression()
model.fit(X, y)

# パラメータの表示
print("Intercept (β0):", model.intercept_[0])
print("Coefficient (β1):", model.coef_[0][0])
Intercept (β0): -9.093527571121504
Coefficient (β1): 0.17535051335865087

\beta_0 \approx -9.0935\beta_1 \approx 0.1754 が得られる.これにより,ロジスティック関数は次のようになる.

p(X) = \frac{1}{1 + e^{-(-9.0935 + 0.1754 X)}}

ある学生が X=80 時間勉強したときに,その学生が合格する確率は次のように計算される.

p(80) = \frac{1}{1 + e^{-(-9.0935 + 0.1754 \times 80)}} \approx 0.9929

X_new = np.array([[80]])
prob = model.predict_proba(X_new)[0][1]
print("Probability of passing for X=80:", prob)
Probability of passing for X=80: 0.9928574234362196