ロジスティック回帰分析とは?
はじめに
今回はロジスティック回帰(logistic regression)について、をわかりやすく解説します。
今回扱うのは、yの値が2値の場合です。
そもそも2値ってなんだよ!って、思われた方もいらっしゃると思います。
2値とは、たとえば、'Yes or No'とか、'赤 or 白'みたいな2つの値のことです。
ロジスティック回帰では2つに分類する問題を考えるんです。
医学の領域で使われることが多い分析方法です。回帰と名前についていますが、分類 なので注意です。
分類は基本的にはどちらかに分けるのですが、このロジスティック回帰は分類される確率を出すのでややこしいかもしれませんがこの記事で理解できるはずです!
わからないことがあればぜひ質問してください!
わかりやすいように例を元に説明させていただきます。
例
ある学校の生徒10人(Aさん~Jさん)のテストの結果のデータがある。そこから、その10人以外の子(例えばKさん)が、合格か不合格かを分類したいとする。
テストの結果には、1人につき数学の点数、国語の点数、英語の点数の3つと、合格か不合格かの情報がある。
名前 | 数学の点数 | 国語の点数 | 英語の点数 | 合格か不合格か |
---|---|---|---|---|
Aさん | 85 | 78 | 92 | 合格 |
Bさん | 68 | 74 | 80 | 不合格 |
Cさん | 90 | 85 | 88 | 合格 |
Dさん | 73 | 79 | 84 | 合格 |
Eさん | 60 | 55 | 65 | 不合格 |
Fさん | 82 | 87 | 89 | 合格 |
Gさん | 77 | 70 | 75 | 不合格 |
Hさん | 91 | 88 | 93 | 合格 |
Iさん | 65 | 67 | 69 | 不合格 |
Jさん | 80 | 83 | 86 | 合格 |
これを一般的に数式に直すと、
観測データ
y=1となる確率をpとする。逆にy=0となる確率は1-pになります。
つまり次のようなモデルを考える。
Q. なぜこのような変換をしたか?
A. オッズ
を対数取ると尺度が合うから。 \displaystyle\frac{p}{1-p}
具体例
-
確率
、オッズはp=\frac{1}{10} 、\frac{1}{9}=0.11 \displaystyle\log\left(\frac{p}{1-p}\right)=-2.2 -
このとき確率
、オッズはp=\frac{9}{10} 、\frac{9}{1}=9 \displaystyle\log\left(\frac{p}{1-p}\right)=2.2
となりこの2つをみると、
オッズを比較すると0.11と9でオッズには対称性がないが、対数を取ると-2.2と2.2となり対称性があるので比較しやすくなる。
ロジスティック回帰曲線
このモデルからpの式に直す。
となる。
ここで注意なのですが、この
最尤推定で
が求められる。
この最尤推定は普通には解けないのですが、ニュートンラフソン法を用いることで解析的に解くことができます。(証明は長いので次の記事で書いてます)
最終的に、新しい子のデータ
まとめ
今回は、ロジスティック回帰の設定から回帰曲線の導出までやりました。
なぜオッズの対数を取って比較しやすくするテクニックはなるほどなと思いました。
最尤推定の証明はこちらです。
おまけのPythonコード
import pandas as pd
import numpy as np
import statsmodels.api as sm
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
#データの準備
data = {
"名前": ["Aさん", "Bさん", "Cさん", "Dさん", "Eさん", "Fさん", "Gさん", "Hさん", "Iさん", "Jさん"],
"数学の点数": [85, 68, 90, 73, 60, 82, 77, 91, 65, 80],
"国語の点数": [78, 74, 85, 79, 55, 87, 70, 88, 67, 83],
"英語の点数": [92, 80, 88, 84, 65, 89, 75, 93, 69, 86],
"合格か不合格か": ["合格", "不合格", "合格", "合格", "不合格", "合格", "不合格", "合格", "不合格", "合格"]
}
df = pd.DataFrame(data)
df['合格か不合格か'] = df['合格か不合格か'].map({"合格": 1, "不合格": 0})
#特徴量とターゲットの設定
X = df[["数学の点数", "国語の点数", "英語の点数"]]
y = df["合格か不合格か"]
#ロジスティック回帰モデルの学習
model = LogisticRegression()
model.fit(X, y)
#係数の取得
coefficients = model.coef_
intercept = model.intercept_
#テストデータ
import pandas as pd
test_data = {
"名前": ["Kさん", "Lさん", "Mさん", "Nさん", "Oさん"],
"数学の点数": [ 88, 69, 92, 75, 78],
"国語の点数": [ 80, 76, 86, 72, 75],
"英語の点数": [ 85, 78, 90, 73, 77],
"合格か不合格か": ["合格", "不合格", "合格", "不合格", "合格"]
}
df_test = pd.DataFrame(test_data)
df_test['合格か不合格か'] = df_test['合格か不合格か'].map({"合格": 1, "不合格": 0})
#KさんからOさんの合格確率を表示
pre = model.predict_proba(df_test[["数学の点数", "国語の点数", "英語の点数"]])[:,1]
test_predictions = (pre >= 0.5).astype(int)
test_labels = df_test["合格か不合格か"]
#Calculate accuracy
accuracy = accuracy_score(test_labels, test_predictions)
#各生徒の合格率をパーセンテージで表示
for i in range(len(pre)):
print(df_test["名前"][i], "の合格率:", f"{pre[i]*100:.2f}%", " 予測結果:", test_predictions[i] , " 実際の結果:" , test_labels[i])
print("分類の正解率:", accuracy*100,'%')
結果
Kさん の合格率: 99.93% 予測結果: 1 実際の結果: 1
Lさん の合格率: 8.99% 予測結果: 0 実際の結果: 0
Mさん の合格率: 100.00% 予測結果: 1 実際の結果: 1
Nさん の合格率: 1.05% 予測結果: 0 実際の結果: 0
Oさん の合格率: 30.87% 予測結果: 0 実際の結果: 1
分類の正解率: 80.0 %
参考文献
- 鈴木 譲 「統計的機械学習の数理100問 with Python」 p.47
Discussion