Data Every Day: 健康保険売上予測

# tldr

Kggleの[Health Insurance Cross Sell Prediction](https://www.kaggle.com/anmolkumar/health-insurance-cross-sell-prediction)を[Health Insurance Interest Prediction - Data Every Day #038](https://www.youtube.com/watch?v=4lnUUZxeGBI&list=PLs_CQl4mUvI7Z9HnwoeOS5EUu9gyvekjK&index=38&t=1s)に沿ってやっていきます。

実行環境はGoogle Colaboratorです。

# インポート


```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import plotly.express as px
import seaborn as sns

import sklearn.preprocessing as sp
from sklearn.model_selection import train_test_split
import sklearn.linear_model as slm

import tensorflow as tf
```

# データのダウンロード

Google Driveをマウントします。


```python
from google.colab import drive
drive.mount('/content/drive')
```

    Mounted at /content/drive


KaggleのAPIクライアントを初期化し、認証します。
認証情報はGoogle Drive内（`/content/drive/My Drive/Colab Notebooks/Kaggle`）に`kaggle.json`として置いてあります。


```python
import os
kaggle_path = "/content/drive/My Drive/Colab Notebooks/Kaggle"
os.environ['KAGGLE_CONFIG_DIR'] = kaggle_path

from kaggle.api.kaggle_api_extended import KaggleApi
api = KaggleApi()
api.authenticate() 
```

Kaggle APIを使ってデータをダウンロードします。


```python
dataset_id = 'anmolkumar/health-insurance-cross-sell-prediction'
dataset = api.dataset_list_files(dataset_id)
```


```python
file_name_test = dataset.files[0].name
file_name_train = dataset.files[1].name
file_path_test = os.path.join(api.get_default_download_dir(), file_name_test)
file_path_train = os.path.join(api.get_default_download_dir(), file_name_train)
```


```python
api.dataset_download_file(dataset_id, file_name_test, force=True, quiet=False)
api.dataset_download_file(dataset_id, file_name_train, force=True, quiet=False)
```

    100%|██████████| 1.54M/1.54M [00:00<00:00, 129MB/s]

    Downloading test.csv.zip to /content
    


    
    100%|██████████| 4.66M/4.66M [00:00<00:00, 33.8MB/s]

    Downloading train.csv.zip to /content
    


    





    True



# データの読み込み

Padasを使ってダウンロードしてきたCSVファイルを読み込みます。


```python
train_df = pd.read_csv(file_path_train+'.zip')
test_df = pd.read_csv(file_path_test+'.zip')
```


```python
train_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>Gender</th>
      <th>Age</th>
      <th>Driving_License</th>
      <th>Region_Code</th>
      <th>Previously_Insured</th>
      <th>Vehicle_Age</th>
      <th>Vehicle_Damage</th>
      <th>Annual_Premium</th>
      <th>Policy_Sales_Channel</th>
      <th>Vintage</th>
      <th>Response</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1</td>
      <td>Male</td>
      <td>44</td>
      <td>1</td>
      <td>28.0</td>
      <td>0</td>
      <td>&gt; 2 Years</td>
      <td>Yes</td>
      <td>40454.0</td>
      <td>26.0</td>
      <td>217</td>
      <td>1</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2</td>
      <td>Male</td>
      <td>76</td>
      <td>1</td>
      <td>3.0</td>
      <td>0</td>
      <td>1-2 Year</td>
      <td>No</td>
      <td>33536.0</td>
      <td>26.0</td>
      <td>183</td>
      <td>0</td>
    </tr>
    <tr>
      <th>2</th>
      <td>3</td>
      <td>Male</td>
      <td>47</td>
      <td>1</td>
      <td>28.0</td>
      <td>0</td>
      <td>&gt; 2 Years</td>
      <td>Yes</td>
      <td>38294.0</td>
      <td>26.0</td>
      <td>27</td>
      <td>1</td>
    </tr>
    <tr>
      <th>3</th>
      <td>4</td>
      <td>Male</td>
      <td>21</td>
      <td>1</td>
      <td>11.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>No</td>
      <td>28619.0</td>
      <td>152.0</td>
      <td>203</td>
      <td>0</td>
    </tr>
    <tr>
      <th>4</th>
      <td>5</td>
      <td>Female</td>
      <td>29</td>
      <td>1</td>
      <td>41.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>No</td>
      <td>27496.0</td>
      <td>152.0</td>
      <td>39</td>
      <td>0</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>381104</th>
      <td>381105</td>
      <td>Male</td>
      <td>74</td>
      <td>1</td>
      <td>26.0</td>
      <td>1</td>
      <td>1-2 Year</td>
      <td>No</td>
      <td>30170.0</td>
      <td>26.0</td>
      <td>88</td>
      <td>0</td>
    </tr>
    <tr>
      <th>381105</th>
      <td>381106</td>
      <td>Male</td>
      <td>30</td>
      <td>1</td>
      <td>37.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>No</td>
      <td>40016.0</td>
      <td>152.0</td>
      <td>131</td>
      <td>0</td>
    </tr>
    <tr>
      <th>381106</th>
      <td>381107</td>
      <td>Male</td>
      <td>21</td>
      <td>1</td>
      <td>30.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>No</td>
      <td>35118.0</td>
      <td>160.0</td>
      <td>161</td>
      <td>0</td>
    </tr>
    <tr>
      <th>381107</th>
      <td>381108</td>
      <td>Female</td>
      <td>68</td>
      <td>1</td>
      <td>14.0</td>
      <td>0</td>
      <td>&gt; 2 Years</td>
      <td>Yes</td>
      <td>44617.0</td>
      <td>124.0</td>
      <td>74</td>
      <td>0</td>
    </tr>
    <tr>
      <th>381108</th>
      <td>381109</td>
      <td>Male</td>
      <td>46</td>
      <td>1</td>
      <td>29.0</td>
      <td>0</td>
      <td>1-2 Year</td>
      <td>No</td>
      <td>41777.0</td>
      <td>26.0</td>
      <td>237</td>
      <td>0</td>
    </tr>
  </tbody>
</table>
<p>381109 rows × 12 columns</p>
</div>




```python
test_df
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>Gender</th>
      <th>Age</th>
      <th>Driving_License</th>
      <th>Region_Code</th>
      <th>Previously_Insured</th>
      <th>Vehicle_Age</th>
      <th>Vehicle_Damage</th>
      <th>Annual_Premium</th>
      <th>Policy_Sales_Channel</th>
      <th>Vintage</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>381110</td>
      <td>Male</td>
      <td>25</td>
      <td>1</td>
      <td>11.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>No</td>
      <td>35786.0</td>
      <td>152.0</td>
      <td>53</td>
    </tr>
    <tr>
      <th>1</th>
      <td>381111</td>
      <td>Male</td>
      <td>40</td>
      <td>1</td>
      <td>28.0</td>
      <td>0</td>
      <td>1-2 Year</td>
      <td>Yes</td>
      <td>33762.0</td>
      <td>7.0</td>
      <td>111</td>
    </tr>
    <tr>
      <th>2</th>
      <td>381112</td>
      <td>Male</td>
      <td>47</td>
      <td>1</td>
      <td>28.0</td>
      <td>0</td>
      <td>1-2 Year</td>
      <td>Yes</td>
      <td>40050.0</td>
      <td>124.0</td>
      <td>199</td>
    </tr>
    <tr>
      <th>3</th>
      <td>381113</td>
      <td>Male</td>
      <td>24</td>
      <td>1</td>
      <td>27.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>Yes</td>
      <td>37356.0</td>
      <td>152.0</td>
      <td>187</td>
    </tr>
    <tr>
      <th>4</th>
      <td>381114</td>
      <td>Male</td>
      <td>27</td>
      <td>1</td>
      <td>28.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>No</td>
      <td>59097.0</td>
      <td>152.0</td>
      <td>297</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>127032</th>
      <td>508142</td>
      <td>Female</td>
      <td>26</td>
      <td>1</td>
      <td>37.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>No</td>
      <td>30867.0</td>
      <td>152.0</td>
      <td>56</td>
    </tr>
    <tr>
      <th>127033</th>
      <td>508143</td>
      <td>Female</td>
      <td>38</td>
      <td>1</td>
      <td>28.0</td>
      <td>0</td>
      <td>1-2 Year</td>
      <td>Yes</td>
      <td>28700.0</td>
      <td>122.0</td>
      <td>165</td>
    </tr>
    <tr>
      <th>127034</th>
      <td>508144</td>
      <td>Male</td>
      <td>21</td>
      <td>1</td>
      <td>46.0</td>
      <td>1</td>
      <td>&lt; 1 Year</td>
      <td>No</td>
      <td>29802.0</td>
      <td>152.0</td>
      <td>74</td>
    </tr>
    <tr>
      <th>127035</th>
      <td>508145</td>
      <td>Male</td>
      <td>71</td>
      <td>1</td>
      <td>28.0</td>
      <td>1</td>
      <td>1-2 Year</td>
      <td>No</td>
      <td>62875.0</td>
      <td>26.0</td>
      <td>265</td>
    </tr>
    <tr>
      <th>127036</th>
      <td>508146</td>
      <td>Male</td>
      <td>41</td>
      <td>1</td>
      <td>29.0</td>
      <td>1</td>
      <td>1-2 Year</td>
      <td>No</td>
      <td>27927.0</td>
      <td>124.0</td>
      <td>231</td>
    </tr>
  </tbody>
</table>
<p>127037 rows × 11 columns</p>
</div>



# 下準備

# エンコード


```python
def get_uniques(df, columns):
    return {column: list(df[column].unique()) for column in columns}
```


```python
categorical_features = ['Gender', 'Vehicle_Age', 'Vehicle_Damage']

get_uniques(train_df, categorical_features)
```




    {'Gender': ['Male', 'Female'],
     'Vehicle_Age': ['> 2 Years', '1-2 Year', '< 1 Year'],
     'Vehicle_Damage': ['Yes', 'No']}




```python
binary_features = ['Gender', 'Vehicle_Damage']
ordinal_features = ['Vehicle_Age']
```


```python
def binary_encode(df, column, positive_label):
    df = df.copy()
    df[column] = df[column].apply(lambda x: 1 if x == positive_label else 0)
    return df
```


```python
train_df = binary_encode(train_df, 'Vehicle_Damage', 'Yes')
test_df = binary_encode(test_df, 'Vehicle_Damage', 'Yes')

train_df = binary_encode(train_df, 'Gender', 'Male')
test_df = binary_encode(test_df, 'Gender', 'Male')
```


```python
def ordinal_encode(df, column, ordering):
    df = df.copy()
    df[column] = df[column].apply(lambda x: ordering.index(x))
    return df
```


```python
age_ordering = ['< 1 Year', '1-2 Year', '> 2 Years']

train_df = ordinal_encode(train_df, 'Vehicle_Age', age_ordering)
test_df = ordinal_encode(test_df, 'Vehicle_Age', age_ordering)
```

# X, Yデータの分割


```python
test_ids = test_df['id'].tolist()
train_df = train_df.drop('id', axis=1)
test_df = test_df.drop('id', axis=1)
```


```python
y = train_df['Response']
X = train_df.drop('Response', axis=1)
```

# スケーリング


```python
scaler = sp.MinMaxScaler()
X = scaler.fit_transform(X)
test_df = scaler.fit_transform(test_df)
```

# トレーニング、テストデータの分割


```python
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7)
```

# トレーニング


```python
model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(10,)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid'),
])

model.summary()

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=[tf.keras.metrics.AUC(name='auc')],
)

batch_size=64
epochs=25

history = model.fit(
    X_train,
    y_train,
    validation_split=0.2,
    batch_size=batch_size,
    epochs=epochs,
    callbacks=[tf.keras.callbacks.ReduceLROnPlateau()],
    verbose=0,
)
```

    Model: "sequential"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    dense (Dense)                (None, 64)                704       
    _________________________________________________________________
    dense_1 (Dense)              (None, 64)                4160      
    _________________________________________________________________
    dense_2 (Dense)              (None, 1)                 65        
    =================================================================
    Total params: 4,929
    Trainable params: 4,929
    Non-trainable params: 0
    _________________________________________________________________


# 結果


```python
plt.figure(figsize=(14, 10))

epochs_range = range(1, epochs+1)
train_loss = history.history['loss']
val_loss = history.history['val_loss']

plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')

plt.title('Training and Validation Loss')
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()

plt.show()
```


![png](Health_Insurance_Cross_Sell_Prediction_files/Health_Insurance_Cross_Sell_Prediction_35_0.png)



```python
model.evaluate(X_test, y_test)
```

    3573/3573 [==============================] - 4s 1ms/step - loss: 0.2692 - auc: 0.8494





    [0.2692367732524872, 0.8494384288787842]



# 予測


```python
preds = model.predict(test_df)
```


```python
preds = list(map(lambda x: np.int(x[0]),  preds >= 0.5))
```


```python
submission = pd.concat([pd.Series(test_ids), pd.Series(preds)], axis=1)
submission.columns = ['id', 'Response']
```


```python
submission
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>Response</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>381110</td>
      <td>0</td>
    </tr>
    <tr>
      <th>1</th>
      <td>381111</td>
      <td>0</td>
    </tr>
    <tr>
      <th>2</th>
      <td>381112</td>
      <td>0</td>
    </tr>
    <tr>
      <th>3</th>
      <td>381113</td>
      <td>0</td>
    </tr>
    <tr>
      <th>4</th>
      <td>381114</td>
      <td>0</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>127032</th>
      <td>508142</td>
      <td>0</td>
    </tr>
    <tr>
      <th>127033</th>
      <td>508143</td>
      <td>0</td>
    </tr>
    <tr>
      <th>127034</th>
      <td>508144</td>
      <td>0</td>
    </tr>
    <tr>
      <th>127035</th>
      <td>508145</td>
      <td>0</td>
    </tr>
    <tr>
      <th>127036</th>
      <td>508146</td>
      <td>0</td>
    </tr>
  </tbody>
</table>
<p>127037 rows × 2 columns</p>
</div>