【機械学習】データ前処理 -文字列・欠損値の変換などについて

<br>
機械学習におけるデータの前処理についてのメモです。


# データ前処理の必要性
機械学習でモデルにデータを渡す際には、データの全てが数値であることが求められる。しかし現実のデータが全て綺麗な数字のみで構成されていることは稀であり、文字列が混入していたりデータに欠損があったりすることが多い。

>機械学習で扱えるデータ

|生年月日|年齢|経験年数|
|----|----|----|
|2000/1/1|20|1|
|2001/1/1|21|2|
|2002/2/1|22|0|

>このままでは機械学習で扱えないデータ

|生年月日|年齢|経験年数|
|----|----|----|
|2000/1/1|20才|一年|
|2001/1/1|21才|半年|
|2002/2/1|22才|(空白)|


<br>
そこで、機械学習モデルにデータを渡す前に、データを綺麗することを目的として行われるのがデータの前処理である。上記のような例以外にも、データを標準化したりすることも本作業の範囲となる。



# データ前処理
## 文字列をダミー変数に変換
データの特徴量が文字列であるとき、個々のデータ（カテゴリ変数）をダミー変数に置き換える方法が用いられる。これを One-hot-Encoding という。

pandas の get_dummies メソッドを使用することで、文字列など数値ではないデータを列の項目として置き換え、1 or 0 の値で表示することができる。

```python:One-Hot-Encodingによる文字列のダミー変数化
import pandas as pd

# 元データ。要素として文字列が含まれている
data1 = pd.DataFrame({'職業':['教師', 'プログラマー', '公務員']})
print(data1)

# 文字列（カテゴリ変数）をダミー変数に変換
new_data1 = pd.get_dummies(data1)
print(new_data1)
```

>データの初期状態

|| 職業 |
|---|---|
| 0 | 教師 |
| 1 | プログラマー |
| 2 | 公務員 |

>One-Hot-Encoding後

| | 職業_プログラマー | 職業_公務員 | 職業_教師 |
|---|---|---|---|
| 0 | 0 | 0 | 1 |
| 1 | 1 | 0 | 0 |
| 2 | 0 | 1 | 0 |


## 欠損値をダミー変数に変換
欠損値の場合でも、上記で用いたOne-Hot-Encodingを用いることができる。
欠損値を扱うことを明示するため、上で使用した get_dummies 関数に、 dummy_na=True というオプションを付ける。

```python:python:One-Hot-Encodingによる欠損値のダミー変数化
import numpy as np

# 2番目と4番目のデータが欠損しているデータ
data2 = pd.DataFrame({'職業':['教師', np.nan, 'プログラマー', np.nan]})
print(data2)

# 欠損値をダミー変数に置き換える
new_data2 = pd.get_dummies(data2, dummy_na=True)
print(new_data2)
```

>データの初期状態

|   | 職業 |
|:--|:--|
| 0 | 教師 |
| 1 | NaN |
| 2 | プログラマー |
| 3 | NaN |

>One-Hot-Encoding後

|   | 職業_プログラマー | 職業_教師 | 職業_nan |
|:--|:--|:--|:--|
| 0 | 0 | 1 | 0 |
| 1 | 0 | 0 | 1 |
| 2 | 1 | 0 | 0 |
| 3 | 0 | 0 | 1 |


## 平均値による欠損値の補完
上の例では文字列の欠損であったためOnehotEncodingが使用出来たが、数値データ中の欠損値などに対してはこの方法は望ましくない。
そのような場合には、欠損値を他のデータの平均値で置き換えるという手法をとる。

欠損値の平均値への変換には、 Imputer モデルを使用する。
Imputer では、オプションで変換元データの種別、変換先データの種別を指定して使用する。

```python:欠損値を平均値に変換する
from sklearn.preprocessing import Imputer

# 欠損値を含む数値データ群
data3 = pd.DataFrame({'年収':[3000000, 4000000, 5000000, np.nan]})
print(data3)


## 欠損値を平均値に置き換えるための処理
# 変換モデルImputerに対し、欠損値NaN を 平均値(mean) に変換することを明示
imp = Imputer(missing_values='NaN', strategy='mean')
# モデルImputerに欠損値を含むデータを学習させる
imp.fit(data3)

# 欠損値を平均値に置き換える
new_data3 = pd.DataFrame(imp.transform(data3), columns=data3.columns)
print(new_data3)
```

>データの初期状態


|| 年収 |
|:--|:--|
| 0 | 3000000.0 |
| 1 | 4000000.0 |
| 2 | 5000000.0 |
| 3 | NaN |

>平均値による変換後


|| 年収 |
|---|---|
| 0 | 3000000.0 |
| 1 | 4000000.0 |
| 2 | 5000000.0 |
| 3 | 4000000.0 |


## データの標準化
扱う数値データが大きすぎるとき、その後の扱いが煩雑になる。
そのような場合には、前処理段階でデータを標準化してしまうのが望ましい。
データの標準化には、 StandardScaler モデルを使用する。

```python:データの標準化
from sklearn.preprocessing import StandardScaler

# 規模の大きな数値データ群
data4 = pd.DataFrame({'大きな数値群':[100000000,120000000,140000000]})
print(data4)


## データの標準化を行う準備
# 標準化を行うモデル
std = StandardScaler()
# モデルにデータを学習させる
std.fit(data4)

# データを標準化する
new_data4 = pd.DataFrame(std.transform(data4), columns=data4.columns)
print(new_data4)
```

>データの初期状態


|   | 大きな数値群 |
|---|---|
| 0 | 100000000 |
| 1 | 120000000 |
| 2 | 140000000 |


>標準化処理後


|   | 大きな数値群 |
|---|---|
| 0 | -1.224745 |
| 1 | 0.000000 |
| 2 | 1.224745 |


以上。