今回は機械学習とか統計で扱うデータセットの標準化について。
まずは、標準化されていない生のデータセットについて考えてみよう。 それらの多くは、次元によって数値の単位がバラバラだったり、あるいは大きさが極端に異なったりする。 これをそのまま扱ってしまうと、各次元を見比べたときにそれぞれの関係が分かりにくい。 また、機械学習においては特定の次元の影響が強く (または反対に弱く) 出てしまったりすることもあるらしい。 そこで、それぞれの次元のスケールを同じに揃えてやりたい。 これを標準化というようだ。
今回は「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 それぞれにやり方がある
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログを見る