CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: データセットの標準化について

今回は機械学習とか統計で扱うデータセットの標準化について。

まずは、標準化されていない生のデータセットについて考えてみよう。 それらの多くは、次元によって数値の単位がバラバラだったり、あるいは大きさが極端に異なったりする。 これをそのまま扱ってしまうと、各次元を見比べたときにそれぞれの関係が分かりにくい。 また、機械学習においては特定の次元の影響が強く (または反対に弱く) 出てしまったりすることもあるらしい。 そこで、それぞれの次元のスケールを同じに揃えてやりたい。 これを標準化というようだ。

今回は「Zスコア」という標準化のやり方を扱う。 これは、一言で言ってしまえばデータセットの各要素から平均を引いて、標準偏差で割ったもの。 これをすると、データセットは平均が 0 で標準偏差・分散が 1 になる。

使った環境は次の通り。

$ python --version
Python 3.5.1

NumPy を使った標準化

まずは一番単純な NumPy の配列を直接使ったやり方から。

ひとまず pip を使って NumPy をインストールしておこう。

$ pip install numpy

Python の REPL を起動しよう。

$ python

NumPy をインポートしたら、次にZスコア化する対象となる配列を変数 l に代入する。 ようするに、これがデータセットを模したものということ。

>>> import numpy as np
>>> l = np.array([10, 20, 30, 40, 50])

この時点でデータセットの算術平均は 30 になっている。

>>> l.mean()
30.0

Zスコアによる標準化の第一段階では、まずデータセットの各要素から、データセットの平均値を引く。

>>> l2 = l - l.mean()

データセットの平均値は、これで 0 になった。

>>> l2.mean()
0.0

各要素から平均値を引いたので、中身はこんなことになる。

>>> l2
array([-20., -10.,   0.,  10.,  20.])

次にZスコア化の第二段階では標準偏差を扱う。 今のデータセットの標準偏差は約 14.14 だ。

>>> l2.std()
14.142135623730951

この標準偏差で、同じくデータセットの各要素を割る。

>>> l3 = l2 / l2.std()

これでデータベースの標準偏差は 1 になった。 きれいに 1 になっていないのは浮動小数点の計算誤差だろうね。

>>> l3.std()
0.99999999999999989

中身はこんなことになる。

>>> l3
array([-1.41421356, -0.70710678,  0.        ,  0.70710678,  1.41421356])

そして、これこそが標準化されたデータセットだ。 各要素の単位は、もはや元々のデータセットで扱われていたそれではなくなっている。 代わりに、単に各要素の相対的な位置関係を表したZスコアになっている。

SciPy を使った標準化

さっきは NumPy の配列を自分で標準化してみたけど、実際にはこの作業はライブラリが代わりにやってくれる。 ここでは SciPy を使った例を挙げておこう。

先ほどと同じように、今度は SciPy を pip コマンドでインストールする。

$ pip install scipy

インストールできたら Python の REPL を起動する。

$ python

さっきと同じようにデータセットを模した NumPy 配列を変数 l として用意しておく。

>>> import numpy as np
>>> l = np.array([10, 20, 30, 40, 50])

SciPy では、そのものずばり zscore() という名前の関数が用意されている。

>>> from scipy.stats import zscore

これに NumPy の配列を渡せば一発でZスコアに標準化できる。

>>> zscore(l)
array([-1.41421356, -0.70710678,  0.        ,  0.70710678,  1.41421356])

あっけない。

scikit-learn を使った標準化

同じように scikit-learn にも標準化のユーティリティが用意されている。

まずは scikit-learn を pip でインストールしておく。

$ pip install scikit-learn

Python の REPL を起動したら…

$ python

データセットを模した NumPy 配列を用意して…

>>> import numpy as np
>>> l = np.array([10, 20, 30, 40, 50])

scikit-learn では StandardScaler というクラスを使って標準化する。

>>> from sklearn.preprocessing import StandardScaler

インスタンス化したら、データセットを模した配列を渡す。 これでデータセットの情報が StandardScaler のインスタンスにセットされる。

>>> sc = StandardScaler()
>>> sc.fit(l)

そして StandardScaler#transform() メソッドを使ってデータセットを標準化する。 返り値として標準化されたデータセットが返る。

>>> sc.transform(l)
array([-1.41421356, -0.70710678,  0.        ,  0.70710678,  1.41421356])

ばっちり。 ちなみに、上記を実行すると NumPy 配列の型が int から float に変換されたよ!っていう警告が出る。 けど、意図したものなので無視しておっけー。

まとめ

  • データセットは標準化してから扱ったほうが良いらしい
  • 標準化は「Zスコア」というものを使うのがメジャーっぽい
  • 標準化のやり方には NumPy / SciPy / scikit-learn それぞれにやり方がある