【ロジスティック回帰分析】機械学習特訓 ver.4（まとめ）

<b> 【特訓 ver.4】 ロジスティック回帰スタート！！</b>
※この記事ではロジスティック回帰分析についてまとめます

## ▼学習の流れ
まずはロジスティック回帰分析の基本を押さえ、具体的な問題を通して理解を深める。

■使用するデータ
握力測定に関するデータ
（実際の握力測定なしに、身長の値を用いて学生の握力分類を行う）

※データセット：後日

<font color="#FF0000">■ ロジスティック回帰分析について学習する</font>
大まかな流れ）
① データ読み込みや前処理、分割
　- 質的変数は用いることができない

② モデルの設定と訓練
　- 「ロジスティック回帰分析」で実施する

③ モデルの精度の確認
　- 精度について、以下6項目で確認していく

<font color="#FF0000">分類における「学習モデルの性能評価」について確認していく！
(1) 混同行列（confusion matrix）
(2) 正解率（accuracy）
(3) 適合率（precision）
(4) 再現率（recall）
(5) F1スコア（F1-score）
(6) AUC（曲線下面積）
</font>

<br>
<b>▼練習問題</b>

年齢、年収によってある商品を購入したかどうか でロジスティック回帰分析を行う。


## ▼復習
・<b>単回帰分析</b>の場合は、1次関数のような関係の場合に利用。すなわち、xに応じてyも比例するような際に利用をする。
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/07dc9418-49f7-819a-2387-1e620c0d38b1.png" width=50%>
<br>
・今まで学習してきた回帰分析は、
　▪ 単回帰分析 ・・・ <b>1つ</b>の入力データを使って値を予測する手法
　 例：身長のデータを使って体重を予測

　▪ 重回帰分析 ・・・ <b>2つ以上</b>の入力データを使って値を予測する手法
　 例：身長と体脂肪率を使って体重を予測

すなわち、入れる値に応じて、結果が定量的に出てくるものを求めるときに有効であった。

<br>
では、結果が2択になるケースではどうするか。
例） ◯か×か、合格か不合格か、など

以下、テストの点数（横軸）に応じて、合否（縦軸）を算出するようなものを出している。合格は1、不合格は0として表示。
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/7a1e10bf-e995-01af-a485-104d11705c88.png" width=90%>

こちらのプロットした値に対して、回帰分析をすると赤線のグラフが得られると考えられる。
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/c8942540-4f8b-d389-4ac2-102c99d9bcb6.png" width=90%>

 違和感しかない・・・。
 この赤色の直線を元に、テストの点数が「50点」「70点」で結果を出力した場合には、それぞれ「0.35」「0.63」と出力された。本来は、1 or 0（合格or不合格）で表示して欲しいのに、このような微妙な数字で出されても判断ができない。

<br>

こういった場合には、<b>ロジスティック回帰分析</b>を利用する。
## ▼ロジスティック回帰分析とは？
いくつかの要因（説明変数）から「2値の結果（目的変数）」が起こる確率を説明・予測することができる統計手法のこと。

単回帰、重回帰との違いも踏まえながらまとめると以下のようになる。
目的変数が2択（質的変数）になるものは、基本的にロジスティック回帰分析を用いるという認識でよさそう。
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/048aced8-83bd-8c0c-cdb3-04a217b7bf4f.png">

もう少し具体的に。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/7dd7a1c3-e9c0-8c22-9a8f-4df5d2839149.png)

目的変数が質的なのか量的なのかで使い分ける。
ロジスティック回帰分析では確率（ 0 or 1 ）を求めたいので、重回帰などは適さない。


## それでは実際に使ってみよう！！
### 【ロジスティック回帰分析】
<b>大まかな流れ</b>
① データ読み込みや前処理、分割
　- 質的変数は用いることができない

② モデルの設定と訓練
　- 「ロジスティック回帰分析」で実施する

③ モデルの精度の確認
　- 精度について、以下6項目で確認していく
　　(1) 混同行列（confusion matrix）
　　(2) 正解率（accuracy）
　　(3) 適合率（precision）
　　(4) 再現率（recall）
　　(5) F1スコア（F1-score）
　　(6) AUC（曲線下面積）

### ① データ読み込みや前処理、分割
```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# データの読み込み
df = pd.read_csv("/content/akuryoku.csv")
df.head()
```
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/9e9c0dbb-4569-4040-ce9c-c35918191661.png" width=70%>

〔説明変数〕
・sex（性別）、age（年齢）、ht(身長)、wt（体重）、BMIの5つを用いる
・sexは0、1に変更する

〔目的変数〕
・grclass・・・1=握力強い、0=握力弱い


```python
#質的変数を量的変数に変換
df['sex'] = df['sex'].replace({'M': 1, 'F': 0})

#説明変数と目的変数に分ける
x = df[["sex","age","ht","wt","BMI"]].values
y = df["grclass"].values

#データを学習用と検証用に分割
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(
    x,y,train_size=0.7,random_state=0)

#標準化
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
x_train_std = sc.fit_transform(x_train)
x_test_std = sc.transform(x_test)
```
<p float="left">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/3f4908f7-4f64-0043-60e4-f39a1a5bb2dc.png" width=48%">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/5288869c-174c-c0bb-deef-14f88d861bd5.png" width="49%">
</p>
データの準備完了！


### ② モデルの設定と訓練

```python
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(x_train_std,y_train)

print(f"切片は {model.intercept_}")
print(f"傾きは {model.coef_}")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/d695c116-8bb5-8978-23bc-002444aa2ab3.png)



- ロジスティック回帰分析の式：
    - デフォルト
        - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/f1720b09-40bf-2c48-0979-c38d06ea9781.png)
　
    - 今回の場合は、
        - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/6cb3f59c-4770-3de3-f3e1-431264804221.png)


以下の条件を持つ(x)に対する、握力分類(y)を予測してみる。

性別：男性（1）
年齢：30歳
身長：175 cm
体重：70 kg
BMI：22.9

```python
# 予測用データを作成して標準化
x_new = pd.DataFrame([[1, 30, 175, 70, 22.9]], columns=["sex", "age", "ht", "wt", "BMI"])
x_new_std = sc.transform(x_new)

# 予測実行
y_pred = model.predict(x_new_std)
print("予測されたgrclass:", y_pred[0])
```
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/f8573e64-77b7-a1f0-5229-8c59ba628876.png" width=50%>


### ③ モデルの精度を確認

##### (1) 混同行列（confusion matrix）

```python
from sklearn.metrics import confusion_matrix
print("confusion_matrix =")
print(confusion_matrix(y_true=y_test,y_pred=model.predict(x_test_std)))
```
※y_true　=　y_test
※y_pred　=　model.predict(x_test_std))
　↑ 正解データ ＝ `y_test` 、
 　　予測データ ＝ `model.predict( )`で定義付け
<br>

【結果】
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/12b643ac-7951-fda1-d289-843ba69597a0.png" width=50%>

※ 参照
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/9a6bd323-90ec-5705-8714-8ddd16eae9b0.png)

青丸が正しく判定できた数になる。
総合的に「偽」が少ない方が、精度は高い。


##### (2) 正解率（accuracy）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/039b8917-fe8f-843a-b038-91ba01d40c7d.png)


```python
print("正解率(train) =", model.score(x_train_std, y_train))
print("正解率(test) =", model.score(x_test_std, y_test))
```

【結果】
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/c65a4ef7-3fc9-9dfb-b847-28e38359218a.png" width=50%>




 ##### (3) 適合率（precision）
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/604da926-bebe-f0a0-5b67-44932b97244e.png)


```python
from sklearn.metrics import precision_score
print("precision =",precision_score(y_true=y_test,y_pred=model.predict(x_test_std)))
```

【結果】
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/dcf60796-c494-abe6-991a-6c14e2fc34a2.png" width=50%>


 ##### (4) 再現率（recall）
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/7a3d3a93-5c21-bf93-6515-7d88c58bb399.png)

```python
from sklearn.metrics import recall_score
print("recall =",recall_score(y_true=y_test,y_pred=model.predict(x_test_std)))
```

【結果】
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/abfb604e-5d5c-c00b-ce28-168b16b7df50.png" width=50%>

 ##### (5) F1スコア（F1-score）
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/a187be47-c6ee-23b9-18c6-fe693b4e3443.png)


```python
from sklearn.metrics import f1_score
print("f1 score =",f1_score(y_true=y_test,y_pred=model.predict(x_test_std)))
```

【結果】
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/b8dc1efd-d12d-be54-66e5-48ba8ea2761e.png" width=50%>

<br>

 ここまでの内容を簡単にまとめると・・・
| 項目                      | 説明                               | 値                                  |
|---------------------------|------------------------------------|-------------------------------------|
| (1)混同行列（confusion matrix） | 予測の正誤を表す表。                   | [[129, 11], [24, 109]]              |
| (2)-1 正解率（train）             | 訓練データにおける正解率。             | 0.8711                              |
| (2)-2 正解率（test）              | テストデータにおける正解率。           | 0.8718                              |
| (3) 適合率（precision）        | 正と予測したものの正確さ。             | 0.9083                              |
| (4) 再現率（recall）            | 実際の正をどれだけ捉えたか。           | 0.8195                              |
| (5) F1スコア（F1-score）        | 適合率と再現率の調和平均。             | 0.8617                              |


 ##### (6) AUC（曲線下面積）
AUCスコア（Area Under the Curve）は、ROC曲線（Receiver Operating Characteristic Curve）の下の面積を指す。このスコアは0から1までの値を取り、1に近いほどモデルの性能が良いことを示す。
```python
from sklearn.metrics import roc_auc_score
print("auc =",roc_auc_score(y_true=y_test,
                            y_score=model.predict_proba(x_test_std)[:,1]))
```
※y_true　=　y_test
※y_score　=　model.predict_proba(x_test_std)[:,1]
　↑ 正解データ ＝ `y_test` 、
 　スコアデータ ＝ `model.predict_proba(x_test_std)[:,1]`で定義付け
<br>
<b>何をしている？</b> 
テストデータから各データが特定のクラス（握力が強いか）に属する確率を計算。

<b>どうやっているのか？</b> 
`model.predict_proba(x_test_std)` はテストデータの各サンプルのクラス確率を計算。 `[:,1]`は「1」クラス（握力が強い）の確率を抽出。これにより、サンプルが「握力が強い」とされる確信度を示す。

<b>簡単な例で考えてみる</b> 
例えば、テストデータに10人の実験者がいる。モデルは各人の「握力が強い」確率を計算し、`model.predict_proba(x_test_std)[:,1]` でそれをリスト化。数値0.8が出れば、その人の握力が強い確率は80％と予測される。

<br>

【結果】
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/89d58d5a-5933-3771-4eeb-14f2b0c503b7.png" width=50%>

94%と高い精度が出ている。つまり、このモデルが「この人の握力は強い」と判断した場合、その予測は信頼できると言える。

<br>

※参照：ROC曲線も可視化してみる
```python
from sklearn.metrics import roc_curve, auc

# モデルが予測した「握力が強い」確率を取得
y_score = model.predict_proba(x_test_std)[:, 1]

# ROC曲線のデータを計算（実際のラベルと予測確率を使って）
fpr, tpr, thresholds = roc_curve(y_true=y_test, y_score=y_score)

# ROC曲線をプロット
plt.plot(fpr, tpr, label="ROC curve (area = %0.2f)" % auc(fpr, tpr))

# ランダムな予測の場合の線をプロット（対角線）
plt.plot([0, 1], [0, 1], linestyle="--", label="Random")

# 理想的な予測の場合の線をプロット（階段形）
plt.plot([0, 0, 1], [0, 1, 1], linestyle="--", label="Ideal")

plt.legend()
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/86dffe86-f458-6af4-5246-1bc81083bee8.png)

青　：ROC曲線（これの下の面積がAUC）、面積が大きいほど正確
緑　：理想値　黄色：適当な値
※緑、黄色の線は、指標として書いておくことが多い。
※横軸：偽陽性率（FP率）、縦軸：真陽性率（TP率）

<br>

<b>それでは、練習問題に行ってみよー！！</b>


## 【練習問題】年齢、年収によってある商品を購入したかどうか
以下、3ステップを意識して実施。
① データ読み込みや前処理、分割
　- 質的変数は用いることができない

② モデルの設定と訓練
　- 「ロジスティック回帰分析」で実施する

③ モデルの精度の確認
　- 精度について、以下6項目で確認していく
　　(1) 混同行列（confusion matrix）
　　(2) 正解率（accuracy）
　　(3) 適合率（precision）
　　(4) 再現率（recall）
　　(5) F1スコア（F1-score）
　　(6) AUC（曲線下面積）

```python
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score, roc_auc_score

# データの読み込み
df = pd.read_csv("/content/Social_Network_Ads.csv")
print(df.head())

# 必要なデータの抽出
x = df[["Age", "EstimatedSalary"]].values
y = df["Purchased"].values

# データを学習用と検証用に分割
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.7, random_state=0)

# データの標準化
sc = StandardScaler()
x_train_std = sc.fit_transform(x_train)
x_test_std = sc.transform(x_test)

# ロジスティック回帰モデルの訓練
model = LogisticRegression()
model.fit(x_train_std, y_train)

# モデルのパラメータ表示
print(f"切片は {model.intercept_}")
print(f"傾きは {model.coef_}")

# 混同行列の出力
print("Confusion Matrix:")
print(confusion_matrix(y_true=y_test, y_pred=model.predict(x_test_std)))

# 性能指標の計算と表示
print("正解率(train) =", model.score(x_train_std, y_train))
print("正解率(test) =", model.score(x_test_std, y_test))
print("適合率 =", precision_score(y_true=y_test, y_pred=model.predict(x_test_std)))
print("再現率 =", recall_score(y_true=y_test, y_pred=model.predict(x_test_std)))
print("F1スコア =", f1_score(y_true=y_test, y_pred=model.predict(x_test_std)))
print("AUC =", roc_auc_score(y_true=y_test, y_score=model.predict_proba(x_test_std)[:, 1]))
```
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/afd041ba-f395-9fdf-f0b7-66901f206317.png" width=40%>


▼ 傾きと切片（ロジスティック回帰式）
切片は [-0.998508]
傾きは [[2.08013198 1.06134466]]

　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/2453f5f2-ff0d-9efd-8d04-ddc7ff77208b.png" width=40%>


▼ 回帰式の精度を確認
　(1) 混同行列（confusion matrix）
　(2) 正解率（accuracy）
　(3) 適合率（precision）
　(4) 再現率（recall）
　(5) F1スコア（F1-score）
　(6) AUC（曲線下面積）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853135/4e207076-7f8d-0bb3-71b2-1341ff3e6ba0.png" width=40%>

テストデータにおける正解率は約87%で、AUCスコアは約0.95と非常に高い性能を示した。モデルの適合率も高い一方で、再現率は約73%と伸び代がある。実際の現場で活用する際には、追加のデータ収集、特徴量エンジニアリング、異なるアルゴリズムの試行、ハイパーパラメータの最適化などで精度を上げていく必要がありそう。

<br>
<b>以上。</b>


<br>
続いては、 <b>SVM分析</b>へGO！！！