Pythonでロジスティック回帰分析を実施する

# はじめに
これまでの記事で重回帰分析と分散分析を行いました。そこで、今回はロジスティック回帰分析をPythonで行っておこうと思います。

今回はKaggleで見つけた航空会社の顧客満足度のデータセット [^1] を使用したいと思います。その説明文にもある通り、航空会社は、顧客満足度を高めるために、自社が提供するサービスのどの側面に重点を置く必要があるかを把握する必要があります。そこで、このデータセット（これまでの顧客の満足度調査）を利用して（将来の）顧客がサービスに満足するかどうかを予測するモデルをロジスティック回帰分析で構築して、その結果を評価しようと思います。

# パッケージのインポートとデータの読み込み
## パッケージをインポート
まず初めにモデルを構築、視覚化、評価するにあたって必要なパッケージをインポートします。
```python
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
import sklearn.metrics as metrics
```

## データの読み込み
データを読み込んで、データの確認を行います。
```python
df_original = pd.read_csv("Invistico_Airline.csv")

print(df_original.shape)
```
```markdown:出力例
(129880, 23)
```
列数が多いので折り返し、省略がされないようにして先頭データの確認を行います。
```python
pd.set_option('display.expand_frame_repr', False)
pd.set_option('display.max_columns', 23)
print(df_original.head())
```
```markdown:出力例
  satisfaction  Gender   Customer Type  Age   Type of Travel     Class     Flight Distance  Seat comfort  Departure/Arrival time convenient    Food and drink  Gate location  Inflight wifi service    On-board service  Leg room service  Baggage handling  Checkin service    Cleanliness  Online boarding  Departure Delay in Minutes    Arrival Delay in Minutes 
0    satisfied  Female  Loyal Customer   65  Personal Travel       Eco                 265             0                                  0                 0              2                      2                   3                 0                 3                5              3                2                           0                         0.0 
1    satisfied    Male  Loyal Customer   47  Personal Travel  Business                2464             0                                  0                 0              3                      0                   4                 4                 4                2              3                2                         310                       305.0 
2    satisfied  Female  Loyal Customer   15  Personal Travel       Eco                2138             0                                  0                 0              3                      2                   3                 3                 4                4              4                2                           0                         0.0 
3    satisfied  Female  Loyal Customer   60  Personal Travel       Eco                 623             0                                  0                 0              3                      3                   1                 0                 1                4              1                3                           0                         0.0 
4    satisfied  Female  Loyal Customer   70  Personal Travel       Eco                 354             0                                  0                 0              3                      4                   2                 0                 2                4              2                5                           0                         0.0 
```

# データ探索(EDA)、データ クリーニング、およびモデルの準備
## データの探索
ロジスティック回帰モデルでは数値データが想定されることを念頭において各列のデータ型を確認します。
```python
print(df_original.dtypes)
```
```markdown:出力例
satisfaction                          object
Gender                                object
Customer Type                         object
Age                                    int64
Type of Travel                        object
Class                                 object
Flight Distance                        int64
Seat comfort                           int64
Departure/Arrival time convenient      int64
Food and drink                         int64
Gate location                          int64
Inflight wifi service                  int64
Inflight entertainment                 int64
Online support                         int64
Ease of Online booking                 int64
On-board service                       int64
Leg room service                       int64
Baggage handling                       int64
Checkin service                        int64
Cleanliness                            int64
Online boarding                        int64
Departure Delay in Minutes             int64
Arrival Delay in Minutes             float64
dtype: object
```

## データセット内の顧客満足度のカラム値を確認する
顧客満足度を予測する為に、モデルの構築前にデータセット内の顧客満足度のカラムを確認します。
```python
print(df_original['satisfaction'].value_counts(dropna = False))
```
```markdown:出力例
satisfied       71087
dissatisfied    58793
Name: satisfaction, dtype: int64
```
value_countsは引数なしのデフォルトではNaNが除外されますが、 dropna = False とするとNaNもカウントされます。NaNの件数が無いことから、顧客満足度のカラムには欠損値が無いことが確認出来ました。

## 欠損値の確認
ロジスティック回帰モデルでは、欠損値が存在しないことが前提となります。そこで、データの行に欠損値がないかを確認します。
```python
print(df_original.isnull().sum())
```
```markdown:出力例
satisfaction                           0
Gender                                 0
Customer Type                          0
Age                                    0
Type of Travel                         0
Class                                  0
Flight Distance                        0
Seat comfort                           0
Departure/Arrival time convenient      0
Food and drink                         0
Gate location                          0
Inflight wifi service                  0
Inflight entertainment                 0
Online support                         0
Ease of Online booking                 0
On-board service                       0
Leg room service                       0
Baggage handling                       0
Checkin service                        0
Cleanliness                            0
Online boarding                        0
Departure Delay in Minutes             0
Arrival Delay in Minutes             393
dtype: int64
```
欠損値は全体のレコード数、129,880に対しての393レコードだけとその割合は僅かであることから、今回は欠損値のある行を削除することにします。
```python
df_subset = df_original.dropna(axis=0).reset_index(drop = True)
```

## データの準備
ロジスティック回帰分析を行うにあたって、説明変数と目的変数を設定したいと思います。ここでは説明変数を機内エンターテイメント体験(Inflight entertainment)、目的変数を顧客満足度(satisfaction)として、機内エンターテイメント体験の向上が顧客満足度の向上につながるかどうかを予測しようと思います。

## 顧客満足度のカテゴリ値を数値に変換しておく
顧客満足度のデータ型が「object 型」になっているので、扱いやすくするためにOne-Hotエンコーディングを使用して、カテゴリ値を数値に変換しておきます。
```python
df_subset['satisfaction'] = OneHotEncoder(drop='first').fit_transform(df_subset[['satisfaction']]).toarray()
```

## トレーニングデータとテストデータの作成
回帰モデルの結果をより適切にテストおよび評価する為に、ホールドアウト法（Hold-out）を用いて、データの 70% をトレーニングデータ、残りの 30% をテストデータに分割します。トレーニングデータはモデルを構築するために使用し、テストデータは構築後のモデルのパフォーマンスを評価するために使用します。そうすることで過剰適合（オーバーフィッティング）や不足適合（アンダーフィッティング）に対処します。
```python
X = df_subset[["Inflight entertainment"]]
y = df_subset["satisfaction"]

X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=42)
```

# 二項ロジスティック回帰モデルの構築
## ロジスティック回帰モデルをデータに適合さる
ロジスティック回帰モデルを構築し、そのモデルをトレーニングデータに適合させます。つまり、X_trainに対してY_trainが導かれるようにパラメータを推定させます。
```python
clf = LogisticRegression().fit(X_train,y_train)
```

## パラメータ推定値の取得
モデルから偏回帰係数と切片の2つのパラメータを取得します。

### 偏回帰係数
```python
print(clf.coef_)
```
```markdown:出力例
[[0.99752883]]
```
### 切片
```python
print(clf.intercept_)
```
```markdown:出力例
[-3.19359054]
```
## モデルのプロットの作成
モデルのプロットを作成し、結果を視覚化します。
```python
sns.regplot(x="Inflight entertainment", y="satisfaction", data=df_subset, logistic=True, ci=None)
plt.show()
```
出力例：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953203/45c087ba-aac6-8f78-8200-b486e460607c.png)

#### 考察
グラフは、機内エンターテイメントの価値が高いほど顧客満足度も高くなることを示しているようです。ですが、これだけで結論を導くのはいささか早急なのでもう少し詳細な分析を行います。

# 混同行列を使用した二項ロジスティック回帰モデルの生成とその評価
## テストデータセットの結果の予測
回帰分析が完了したので、結果を確認して分析します。まず、ホールドアウト法で分離したテストデータを predict 関数に入力して、モデルから値を取得します。そして、その値をテストデータの顧客満足度の値と比較することで予測の精度を確認、評価します。

## 各種評価指標の定義の確認
### 正解率(Accuracy)
精度ともいい、正しく分類されたデータの比率。
正解率（Accuracy）の計算式は以下の通り：
```math
Accuracy = \frac{True Positives + False Negatives}{True Positives + False Positives + True Negatives + False Negatives}
```

### 適合率（Precision）
陽性的中率（positive predictive value）ともいい、陽性であると予測されたデータが実際に陽性である比率。
適合率（Precision）の計算式は以下の通り：
```math
Precision = \frac{True Positives}{True Positives + False Positives}
```

### 再現率（Recall）
実際に陽性であるすべてのデータのうち、陽性として予測されたデータの比率。
再現率（Recall）の計算式は以下の通り：
```math
Recall = \frac{True Positives}{True Positives + False Negatives}
```

### F1スコア（F1 Score）
F-値とも言い、適合率と再現率の調和平均。
F1スコア（F1 Score）の計算式は以下の通り：
```math
F = 2 \div (\frac{1}{precision} + \frac{1}{recall}) = 2 \times \frac{precision \times recall}{precision + recall}
```

Pythonでこれを実装します。
### 各種評価指標の出力
```python
# XのテストデータよりYの予測値を取得する
y_pred = clf.predict(X_test)

# 各種指標の出力
print("正解率(Accuracy):", "%.6f" % metrics.accuracy_score(y_test, y_pred))
print("適合率(Precision):", "%.6f" % metrics.precision_score(y_test, y_pred))
print("再現率(Recall):", "%.6f" % metrics.recall_score(y_test, y_pred))
print("F1スコア(F1 Score):", "%.6f" % metrics.f1_score(y_test, y_pred))
```
```markdown:出力例
正解率(Accuracy): 0.801529
適合率(Precision): 0.816142
再現率(Recall): 0.821530
F1スコア(F1 Score): 0.818827
```

#### 考察
モデルの正解率は 80.2%であり、これはデータセットの顧客満足度54.7% (71,087/129,880) よりも向上しています。また、適合率も81.6%と高い数値を示しており、偽陽性が少ないことを示しています。（偽陽性が全く存在しなければ適合率は100%になります)。同じく再現率も82.2%となっており、偽陰性が少ないことを示しています。（こちらも偽陰性が全く存在しなければ再現率は100%になります)。F1スコアも81.9%と適合率と再現率の両方が適度にバランスが取れていることを示し、モデルの予測精度が高いと考えられます。﻿（どちらも完璧であった場合、最大値の100%になります）。

## 混同行列(Confusion Matrix) の数字の理解と解釈
### 混同行列(Confusion Matrix) の各象限の定義の確認
混同行列は、分類器の性能を要約するのに役立ちます。混同行列の構成要素は、ロジスティック回帰分類器を評価するためのメトリクスを計算するために使用されます。
混同行列の4つの象限は、二項ロジスティック回帰分析では、以下のとおりです：

- 右上の第一象限には、偽陽性の数が示されます
- 左上の第二象限には、真陰性の数が示されます
- 左下の第三象限には、偽陰性の数が示されます
- 右下の第四象限には、真陽性の数が示されます

つまり、今回の例でいけば

- 偽陽性: モデルが誤って予測した顧客満足度の数
- 真陰性: モデルが正しく予測した顧客満足度の数
- 偽陰性: モデルが誤ってに予測した顧客満足度の数
- 真陽性: モデルが正しくに予測した顧客満足度の数

です。
モデルの当てはまりがよければ真陰性と真陽性のみを出力し、偽陰性や偽陽性は出力しません。

### 混同行列の生成
```python
cm = metrics.confusion_matrix(y_test, y_pred, labels = clf.classes_)
disp = metrics.ConfusionMatrixDisplay(confusion_matrix = cm,display_labels = clf.classes_)
disp.plot()
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953203/5c767287-15e1-cfcf-60db-ed2b8d00c28a.png)

#### 考察
第一象限（偽陽性）と第三象限（偽陰性）の値が4,000未満と第二象限（真陰性) 、第四象限(真陽性）が共に13,000を超えていることに比べると少ない値です。また偽陽性と偽陰性の数値に大きな差はありません。

## 結論
よって、「機内エンターテイメントを高く評価した顧客は、満足度が高い傾向にありました。機内エンターテイメントを改善すれば、顧客満足度が向上するはずです」、となります。

[^1]: Airlines Customer satisfaction https://www.kaggle.com/datasets/sjleshrac/airlines-customer-satisfaction/data