Data Every Day: たべものの嗜好

# tldr

Kggleの[Food Preferences](https://www.kaggle.com/vijayashreer/food-preferences)を[Predicting Age From Food Preference](https://www.youtube.com/watch?v=r0eaUpurifA&list=PLs_CQl4mUvI7Z9HnwoeOS5EUu9gyvekjK&index=34)に沿ってやっていきます。

実行環境はGoogle Colaboratorです。

# インポート


```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
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')
```

    Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).


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 = 'vijayashreer/food-preferences'
dataset = api.dataset_list_files(dataset_id)
file_name = dataset.files[0].name
file_path = os.path.join(api.get_default_download_dir(), file_name)
file_path
```

    Warning: Looks like you're using an outdated API Version, please consider updating (server 1.5.10 / client 1.5.9)





    '/content/Food_Preference.csv'




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

    100%|██████████| 24.3k/24.3k [00:00<00:00, 15.1MB/s]

    Downloading Food_Preference.csv to /content
    


    





    True



# データの読み込み

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


```python
data = pd.read_csv(file_path)
```


```python
data
```




<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>Timestamp</th>
      <th>Participant_ID</th>
      <th>Gender</th>
      <th>Nationality</th>
      <th>Age</th>
      <th>Food</th>
      <th>Juice</th>
      <th>Dessert</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>2019/05/07 2:59:13 PM GMT+8</td>
      <td>FPS001</td>
      <td>Male</td>
      <td>Indian</td>
      <td>24</td>
      <td>Traditional food</td>
      <td>Fresh Juice</td>
      <td>Maybe</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2019/05/07 2:59:45 PM GMT+8</td>
      <td>FPS002</td>
      <td>Female</td>
      <td>Indian</td>
      <td>22</td>
      <td>Western Food</td>
      <td>Carbonated drinks</td>
      <td>Yes</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2019/05/07 3:00:05 PM GMT+8</td>
      <td>FPS003</td>
      <td>Male</td>
      <td>Indian</td>
      <td>31</td>
      <td>Western Food</td>
      <td>Fresh Juice</td>
      <td>Maybe</td>
    </tr>
    <tr>
      <th>3</th>
      <td>2019/05/07 3:00:11 PM GMT+8</td>
      <td>FPS004</td>
      <td>Female</td>
      <td>Indian</td>
      <td>25</td>
      <td>Traditional food</td>
      <td>Fresh Juice</td>
      <td>Maybe</td>
    </tr>
    <tr>
      <th>4</th>
      <td>2019/05/07 3:02:50 PM GMT+8</td>
      <td>FPS005</td>
      <td>Male</td>
      <td>Indian</td>
      <td>27</td>
      <td>Traditional food</td>
      <td>Fresh Juice</td>
      <td>Maybe</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>283</th>
      <td>2019/05/10 9:24:00 AM GMT+8</td>
      <td>FPS284</td>
      <td>Male</td>
      <td>Indian</td>
      <td>27</td>
      <td>Western Food</td>
      <td>Fresh Juice</td>
      <td>Yes</td>
    </tr>
    <tr>
      <th>284</th>
      <td>2019/05/10 9:32:54 AM GMT+8</td>
      <td>FPS285</td>
      <td>Male</td>
      <td>Indian</td>
      <td>24</td>
      <td>Traditional food</td>
      <td>Fresh Juice</td>
      <td>Yes</td>
    </tr>
    <tr>
      <th>285</th>
      <td>2019/05/10 12:09:17 PM GMT+8</td>
      <td>FPS286</td>
      <td>Male</td>
      <td>Indian</td>
      <td>25</td>
      <td>Traditional food</td>
      <td>Fresh Juice</td>
      <td>Yes</td>
    </tr>
    <tr>
      <th>286</th>
      <td>2019/05/10 12:52:17 PM GMT+8</td>
      <td>FPS287</td>
      <td>Male</td>
      <td>Indian</td>
      <td>27</td>
      <td>Traditional food</td>
      <td>Fresh Juice</td>
      <td>Yes</td>
    </tr>
    <tr>
      <th>287</th>
      <td>2019/05/10 12:55:42 PM GMT+8</td>
      <td>FPS288</td>
      <td>Male</td>
      <td>Indian</td>
      <td>27</td>
      <td>Traditional food</td>
      <td>Fresh Juice</td>
      <td>No</td>
    </tr>
  </tbody>
</table>
<p>288 rows × 8 columns</p>
</div>



# 下準備


```python
data.info()
```

    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 288 entries, 0 to 287
    Data columns (total 8 columns):
     #   Column          Non-Null Count  Dtype 
    ---  ------          --------------  ----- 
     0   Timestamp       288 non-null    object
     1   Participant_ID  288 non-null    object
     2   Gender          284 non-null    object
     3   Nationality     288 non-null    object
     4   Age             288 non-null    int64 
     5   Food            288 non-null    object
     6   Juice           288 non-null    object
     7   Dessert         288 non-null    object
    dtypes: int64(1), object(7)
    memory usage: 18.1+ KB


不要な列の削除


```python
data = data.drop(['Timestamp', 'Participant_ID'], axis=1)
```

欠損値の処理


```python
data = data.dropna(axis=0)
data = data.reset_index(drop=True)
```

Ageを若者と年配者のバイナリに変換します


```python
age_bins = pd.qcut(data['Age'], q=2, labels=[0,1])
```


```python
pd.concat([data['Age'], age_bins], axis=1)
```




<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>Age</th>
      <th>Age</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>24</td>
      <td>0</td>
    </tr>
    <tr>
      <th>1</th>
      <td>22</td>
      <td>0</td>
    </tr>
    <tr>
      <th>2</th>
      <td>31</td>
      <td>1</td>
    </tr>
    <tr>
      <th>3</th>
      <td>25</td>
      <td>0</td>
    </tr>
    <tr>
      <th>4</th>
      <td>27</td>
      <td>0</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>279</th>
      <td>27</td>
      <td>0</td>
    </tr>
    <tr>
      <th>280</th>
      <td>24</td>
      <td>0</td>
    </tr>
    <tr>
      <th>281</th>
      <td>25</td>
      <td>0</td>
    </tr>
    <tr>
      <th>282</th>
      <td>27</td>
      <td>0</td>
    </tr>
    <tr>
      <th>283</th>
      <td>27</td>
      <td>0</td>
    </tr>
  </tbody>
</table>
<p>284 rows × 2 columns</p>
</div>




```python
data['Age'] = age_bins
```

# エンコード


```python
categorical_features = ['Gender', 'Nationality', 'Food', 'Juice', 'Dessert']
```


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


```python
get_uniques(data, categorical_features)
```




    {'Dessert': ['Maybe', 'Yes', 'No'],
     'Food': ['Traditional food', 'Western Food'],
     'Gender': ['Male', 'Female'],
     'Juice': ['Fresh Juice', 'Carbonated drinks'],
     'Nationality': ['Indian',
      'Pakistani ',
      'Tanzanian',
      'Indonesia',
      'Pakistan',
      'Maldivian ',
      'MY',
      'Malaysian',
      'Malaysian ',
      'Indonesian ',
      'Maldivian',
      'MALAYSIAN',
      'Malaysia ',
      'Pakistani',
      'Canadian',
      'Nigerian ',
      'Algerian ',
      'Korean ',
      'Seychellois',
      'Indonesain',
      'Indonesian',
      'Malaysia',
      'Japan',
      'China',
      'Mauritian',
      'Yemen']}



フィーチャーを特徴に従い以下の3つのタイプに分けます。


```python
binary_features = ['Gender', 'Food', 'Juice']
ordinal_features = ['Desert']
nominal_features = ['Nationality']
```


```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
def ordinal_encode(df, column, ordering):
    df = df.copy()
    df[column] = df[column].apply(lambda x: ordering.index(x))
    return df
```


```python
def onehot_encode(df, column):
    df = df.copy()
    dummies = pd.get_dummies(df[column])
    df = pd.concat([df, dummies], axis=1)
    df = df.drop(column, axis=1)
    return df
```


```python
data = binary_encode(data, 'Gender', 'Male')
data = binary_encode(data, 'Food', 'Traditional food')
data = binary_encode(data, 'Juice', 'Fresh Juice')

desert_ordering = ['No', 'Maybe', 'Yes']
data = ordinal_encode(data, 'Dessert', desert_ordering)

data = onehot_encode(data, 'Nationality')

```

# スケーリングとデータの分割


```python
y = data['Age']
X = data.drop('Age', axis=1)
```


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


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

# トレーニング


```python
model = slm.LogisticRegression()
model.fit(X_train, y_train)
model.score(X_test, y_test)
```




    0.7209302325581395



少ないデータとしてはまずまずの精度がでました。