特徴量のスケーリング

機械学習モデルは、多くの場合、異なるスケールの数値データを扱います。これにより、特定の特徴量が他の特徴量に比べて過度に影響を与える可能性があります。例えば、身長がセンチメートル単位で、体重がキログラム単位である場合、モデルは体重の影響を過小評価し、身長の影響を過大評価する可能性があります。このようなバイアスを防ぐために、特徴量のスケーリングが必要です。

主要な手法

標準化(Standardization)
この変換により、データは平均が0、標準偏差が1の正規分布に近づきます。これにより、異なる特徴量が同じスケールで扱われるようになり、特定の特徴量が他の特徴量よりも大きな影響を持つことを防ぐことができます。

標準化はScikit-learnライブラリのStandardScalerを利用します。

import numpy as np
from sklearn.preprocessing import StandardScaler

data = np.array([[1.0, 2.0, 3.0],
                 [4.0, 5.0, 6.0],
                 [7.0, 8.0, 9.0]])

scaler = StandardScaler()
standardized_data = scaler.fit_transform(data)

standardized_data

StandardScalerは各特徴量(列)の平均と標準偏差を計算し、その値を使用してデータを変換します。

先に変換後のデータを示します。

array([[-1.22474487, -1.22474487, -1.22474487],
       [ 0.        ,  0.        ,  0.        ],
       [ 1.22474487,  1.22474487,  1.22474487]])

このサンプルの、1列目を見ていきます。
まず1列目の平均を計算します。

$$
\mu_1 = \frac{1.0 + 4.0 + 7.0}{3} = 4.0
$$

したがって、4の値が0に変換されています。
また標準偏差については下記のようになります。

$$
\sigma_1 = \sqrt{\frac{(1.0-4.0)^2 + (4.0-4.0)^2 + (7.0-4.0)^2}{3}} = \sqrt{\frac{9 + 0 + 9}{3}} = \sqrt{6} \approx 2.449
$$

1の値では、下記のように計算され、1の値が-1.224に変換されています。

$$
z = \frac{1.0 - 4.0}{2.449} \approx -1.224
$$

このような形で、各列に対してデータの標準化が行われます。

MinMaxScaler

MinMaxScalerは、データを特定の範囲(通常は0から1)にスケーリングする手法です。このスケーリング方法は、データの最小値を0、最大値を1に変換し、それに基づいて他の値をリスケールします。

こちらもScikit-learnライブラリに実装があります。

import numpy as np
from sklearn.preprocessing import MinMaxScaler

data = np.array([[1.0, 2.0, 3.0],
                 [4.0, 5.0, 6.0],
                 [7.0, 8.0, 9.0]])

scaler = MinMaxScaler()
normalized_data = scaler.fit_transform(data)

normalized_data

先ほどと同じサンプルデータに対して、今度はMinMaxScalerを適用してみます。

array([[0. , 0. , 0. ],
       [0.5, 0.5, 0.5],
       [1. , 1. , 1. ]])

1列目の平均(4の値)は0.5に変換され、最小値は0、最大値は1に変換されている事が確認出来ます。

Robust Scaling

Robust Scalingは、外れ値の影響を受けにくい手法です。データを中央値と四分位範囲(IQR)を用いてスケールします。

こちらもScikit-learnライブラリに実装があります。

import numpy as np
from sklearn.preprocessing import RobustScaler

data = np.array([[1.0, 2.0, 3.0],
                 [4.0, 5.0, 6.0],
                 [7.0, 8.0, 9.0],
                 [10.0, 20.0, 30.0]]) 

scaler = RobustScaler()
scaled_data = scaler.fit_transform(data)

scaled_data

今回は意図的にサンプルデータに外れ値を追加してあります。
結果は下記のようになります。

array([[-1.        , -0.66666667, -0.5       ],
       [-0.33333333, -0.22222222, -0.16666667],
       [ 0.33333333,  0.22222222,  0.16666667],
       [ 1.        ,  2.        ,  2.5       ]])

1列目の中央値は5.5になります。
四分位範囲(IQR)は、下記のように計算します。

import numpy as np

sample = [1.0, 4.0, 7.0, 10.0]

q1 = np.percentile(sample, 25)
q2 = np.percentile(sample, 50) 
q3 = np.percentile(sample, 75) 

q3 - q1

これによって、4.5という値が算出されます。
よって1列目のデータポイント1.0については下記のように計算されます。

$$
x' = \frac{1.0 - 5.5}{4.5} = -1.0
$$

Max Absolute Scaler

Max Absolute Scalerは、データを絶対値の最大値で除算してスケーリングする手法です。このスケーラーはデータの符号を維持しながら、各データポイントを-1から1の範囲に収めます。特にスパースデータセット(データの多くがゼロであるデータセット)に対して有効です。

こちらもScikit-learnライブラリに実装があります。

import numpy as np
from sklearn.preprocessing import MaxAbsScaler

data = np.array([[ 1.0,  2.0,  3.0],
                 [ 4.0,  5.0,  6.0],
                 [ 7.0,  8.0,  9.0],
                 [-1.0, -2.0, -3.0]])

scaler = MaxAbsScaler()
scaled_data = scaler.fit_transform(data)

scaled_data

結果は下記のようになります。

array([[ 0.14285714,  0.25      ,  0.33333333],
       [ 0.57142857,  0.625     ,  0.66666667],
       [ 1.        ,  1.        ,  1.        ],
       [-0.14285714, -0.25      , -0.33333333]])

1列目の1.0について計算してみます。
1列目の最大絶対値は 7.0です。

最大値で除算を行うと下記のようになり、約0.143になります。
また最大値である7.0について1となります。

$$
x' = \frac{1.0}{7.0} \approx 0.143
$$