【NumPy / SciPy】Pythonでデータの標準化

データ分析の前処理などで行う標準化と正規化の違いや, Pythonで標準化する際のいくつかの方法について調べたのでメモります。

標準化と正規化

正規化 (normalization) または最大最小スケーリング (min-max scaling) は [0,1] となるように下記のような変換をする。min/maxに強く影響される。

     \begin{eqnarray*} x_{new}^i = \frac{x^i - x_{min}} {x_{max} - x_{min}} \end{eqnarray*}

一方で, 標準化 (standardization)は N(0, 1) となるように下記のような変換する。外れ値に対して正規化よりロバスト。

     \begin{eqnarray*} x_{new}^i = \frac{x^i - \mu} {\sigma} \end{eqnarray*}

数式は Standardization vs. normalization [1] から引用。

機械学習の様々なアルゴリズムは良いパフォーマンスを実現するためにスケーリングが必要となるが, 正規化も標準化もスケーリングの一種として考えて良さそう。

注意点として訓練データのみならず, 評価データや予測時のデータに対しても同じスケーリングパラメータを適用して変換する必要がある。
(過去に訓練データと評価データで別々に標準化し失敗してしまったことがあった…)

Pythonでデータの標準化

標準化自体が簡単に実装できるとは思うが, ライブラリを使う方法も幾つかある。

  • NumPy
  • SciPy
  • scikit-learn

環境はOSX 10.11.5, Python 2.7.9。

NumPy

NumPyの mean と std を使う方法。

In [1]: import numpy as np

In [2]: x = [1,2,3,4,5,6,7,8,9]

In [3]: x_copy = np.copy(x)

In [4]: x_std = (x_copy - x_copy.mean()) / x_copy.std()

In [5]: x_std
Out[5]:
array([-1.54919334, -1.161895  , -0.77459667, -0.38729833,  0.        ,
        0.38729833,  0.77459667,  1.161895  ,  1.54919334])

In [6]: np.mean(x_std)
Out[6]: 0.0

In [7]: np.std(x_std)
Out[7]: 1.0

mean, std を使った方法は Pandas でもできる。[2]

SciPy

scipy.stats.zscore を使う方法。axisに None, 0, 1 を指定でき下記のような違いがある。

  • axis=None: 行列全体で標準化
  • axis=0: 列方向で標準化
  • axis=1: 行方向で標準化

また, ddof で std 計算時の自由度 (df) を調整できる。 例えば, ddof=1 の時に n-1 で計算。Defaultは0。

In [8]: import scipy.stats as sp

In [9]: x_std = sp.stats.zscore(x, axis=0)

In [10]: x_std
Out[10]:
array([-1.54919334, -1.161895  , -0.77459667, -0.38729833,  0.        ,
        0.38729833,  0.77459667,  1.161895  ,  1.54919334])

In [11]: np.mean(x_std)
Out[11]: 0.0

In [12]: np.std(x_std)
Out[12]: 1.0

In [13]: x_matrix = np.array([[1,2,3],[4,5,6],[7,8,9]])

In [14]: x_matrix
Out[14]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [15]: x_std = sp.stats.zscore(x_matrix, axis=0)

In [16]: x_std
Out[16]:
array([[-1.22474487, -1.22474487, -1.22474487],
       [ 0.        ,  0.        ,  0.        ],
       [ 1.22474487,  1.22474487,  1.22474487]])

In [17]: x_std = sp.stats.zscore(x_matrix, axis=None)

In [18]: x_std
Out[18]:
array([[-1.54919334, -1.161895  , -0.77459667],
       [-0.38729833,  0.        ,  0.38729833],
       [ 0.77459667,  1.161895  ,  1.54919334]])

In [19]: x_std = sp.stats.zscore(x_matrix, axis=1)

In [20]: x_std
Out[20]:
array([[-1.22474487,  0.        ,  1.22474487],
       [-1.22474487,  0.        ,  1.22474487],
       [-1.22474487,  0.        ,  1.22474487]])

In [21]: x_std = sp.stats.zscore(x_matrix, axis=1, ddof=1)

In [22]: x_std
Out[22]:
array([[-1.,  0.,  1.],
       [-1.,  0.,  1.],
       [-1.,  0.,  1.]])

scikit-learn

sklearn.preprocessing を使う方法。StandardScaler は標準化, MinMaxScaler は正規化。
fit でスケーリングパラメータを保持しておき, transform で標準化された値を返すのでアプリケーションへの実装に適している。

In [27]: from sklearn.preprocessing import StandardScaler
In [28]: x = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

In [29]: ss = StandardScaler()

In [30]: ss.fit(x)
Out[30]: StandardScaler(copy=True, with_mean=True, with_std=True)

In [31]: x_std = ss.transform(x)

In [32]: x_std
Out[32]:
array([-1.54919334, -1.161895  , -0.77459667, -0.38729833,  0.        ,
        0.38729833,  0.77459667,  1.161895  ,  1.54919334])

In [33]: x_std = ss.transform([4.5])

In [34]: x_std
Out[34]: array([-0.19364917])

In [35]: from sklearn.preprocessing import MinMaxScaler

In [36]: mms = MinMaxScaler()

In [37]: x_norm = mms.fit_transform(x)

In [38]: x_norm
Out[38]: array([ 0.   ,  0.125,  0.25 ,  0.375,  0.5  ,  0.625,  0.75 ,  0.875,  1.   ])

今回, 参考にさせて頂いた本は『Python機械学習プログラミング 達人データサイエンティストによる理論と実践』です。

[1] Standardization vs. normalization
[2] Essential Basic Functionality