特徴量を標準化しないとどうなるか分かりやすくしてみた

よく機械学習を使う前に特徴量を標準化ないし正規化をして単位を統一しろと言われると思います。
それについて実際に単位を統一しないとどうなるか、今回は機械学習ではなくユークリッド距離(多次元の三平方の定理だと思っていただければ)を用いた1近傍法を使って説明してみようと思います。
# 標準化をしない場合
```Python3
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import pandas as pd
import numpy as np

df = pd.read_csv("wine.csv")
y = df["Wine"].values
x = df.drop("Wine", axis=1).values

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)

y_pred = []
for i in range(len(x_test)):
    tmp = []
    for j in range(len(x_train)):
        tmp.append(np.linalg.norm(x_train[j]-x_test[i]))
    y_pred.append(y_train[np.argmin(tmp)])
print(classification_report(y_test, y_pred))
```
```
              precision    recall  f1-score   support

           1       0.95      0.91      0.93        22
           2       0.80      0.80      0.80        20
           3       0.54      0.58      0.56        12

    accuracy                           0.80        54
   macro avg       0.76      0.76      0.76        54
weighted avg       0.80      0.80      0.80        54
```
となります。Wineデータにしては非常に精度が悪い事が分かります。

# 標準化した場合
```Python3
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import pandas as pd
import numpy as np

df = pd.read_csv("wine.csv")
y = df["Wine"].values
x = df.drop("Wine", axis=1)

# 標準化
for col in x.columns:
    x[col] = (x[col] - x[col].mean()) / x[col].std()
x = x.values

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)

y_pred = []
for i in range(len(x_test)):
    tmp = []
    for j in range(len(x_train)):
        tmp.append(np.linalg.norm(x_train[j]-x_test[i]))
    y_pred.append(y_train[np.argmin(tmp)])
print(classification_report(y_test, y_pred))
```
```
              precision    recall  f1-score   support

           1       0.96      1.00      0.98        22
           2       1.00      0.80      0.89        20
           3       0.80      1.00      0.89        12

    accuracy                           0.93        54
   macro avg       0.92      0.93      0.92        54
weighted avg       0.94      0.93      0.93        54
```
精度が13%上がりました。
コードを見れば分かりますが最初に言いました通り機械学習ではなくユークリッド距離によるルールベースの予測です。

# なぜこうなったか
ちょっとデータを実際に見てみましょう
## 標準化していない
そのままのデータを出します。
```Python3
df = pd.read_csv("wine.csv")
df.head()
x = df.drop("Wine", axis=1)
x.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/e15f1c84-453c-ad4f-32b3-f7580a5e7f97.png)
```Python3
x.describe()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/c2b02483-bfde-5316-e222-37dc90def68a.png)

変数によって数値がバラバラです

## 標準化をする
標準化は平均値を0として標準偏差を1にします。
```Python3
for col in x.columns:
    x[col] = (x[col] - x[col].mean()) / x[col].std()
x.head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/62ed52c3-febd-a32c-985e-ae05a261839b.png)

```Python3
x.describe()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/a6fc60d6-46c5-bbad-1850-cffc46382517.png)

多少四分位と最大最小値に違いはありますがそれでも数値が似ています。

## 結論
単位が違うと当然変数の取り得る値も異なる訳で、そうなると大きな値に影響されやすくなります。なので、今回だと単位を揃えなかったらProlineに大きく影響を受けてしまう事が考えられます。
しかし単位を標準化して揃える事でどの変数も平等に扱うことができます。

# まとめ
単位はちゃんと揃えましょう。
でないと大きな数値に影響されやすくなります。
<b>ただし決定木系アルゴリズムでは揃えなくても大丈夫です。</B>
## 標準化
```math
Norm(x_i) = \frac{x_i - mean(x_i)}{std(x_i)}
```

## 正規化
```math
Scale(x_i) = \frac{x_i - min(x_i)}{max(x_i) - min(x_i)}
```