import numpy as np
# 元データ(p.483)
data = np.array([
# ディナーダミー、トラブルダミー、リピートダミー、人数
[0, 0, 0, 207],
[0, 0, 1, 23],
[0, 1, 0, 18],
[0, 1, 1, 2],
[1, 0, 0, 435],
[1, 0, 1, 290],
[1, 1, 0, 15],
[1, 1, 1, 10]])
# 各行を人数分に展開したもの
data_flat = np.repeat(data[:, :3], data[:, 3], axis=0)
X = data_flat[:, :2] # ディナーダミー、トラブルダミー
X = np.hstack((np.ones_like(X[:,:1]), X)) # 1列目に全て1の列を追加
y = data_flat[:, 2] # リピートダミー
# コスト関数 C(β) = -log L(β) = - \sum { (y - 1) x^T β - log(1 + exp(-x^T β)) }
# L(β) = \Pi p^y (1-p)^(1-y), p = 1 / (1 + exp(-x^T β))
def cost_function(X, y, beta):
return -np.sum((y - 1) * (X @ beta) - np.log(1 + np.exp(-X @ beta)))
# 勾配 ∂C/∂β のテスト(p.490)
beta = np.array([1.0, 1.0, 1.0])
delta = 0.0001
gradient = [
(cost_function(X, y, beta + [delta, 0, 0]) - cost_function(X, y, beta)) / delta,
(cost_function(X, y, beta + [0, delta, 0]) - cost_function(X, y, beta)) / delta,
(cost_function(X, y, beta + [0, 0, delta]) - cost_function(X, y, beta)) / delta,
]
print("first gradient =", gradient)
# 勾配が最小になるβを求める
# βから勾配に学習率を掛けたものを引くのを繰り返す
learning_rate = 0.005
for i in range(120):
gradient = np.array([
(cost_function(X, y, beta + [delta, 0, 0]) - cost_function(X, y, beta)) / delta,
(cost_function(X, y, beta + [0, delta, 0]) - cost_function(X, y, beta)) / delta,
(cost_function(X, y, beta + [0, 0, delta]) - cost_function(X, y, beta)) / delta,
])
beta -= learning_rate * gradient
print("beta =", beta)
# オッズ比(p.492)
print("odds of beta1, beta2 =", np.exp(beta[1:]))
# scikit-learnのLogisticRegressionで検算する
from sklearn.linear_model import LogisticRegression
X = data_flat[:, :2] # ディナーダミー、トラブルダミー
y = data_flat[:, 2] # リピートダミー
lr = LogisticRegression().fit(X, y)
print("sklearn beta0 =", lr.intercept_, ", (beta1, beta2) =", lr.coef_[0])
print("sklearn odds of beta1, beta2 =", np.exp(lr.coef_[0]))