LoginSignup
44

More than 3 years have passed since last update.

StandardScalerを試してみる

Last updated at Posted at 2019-10-31

sklearn.preprocessing.StandardScalerについて簡単に調べたのでメモとして残します。

StandardScalerはデータセットの標準化機能を提供してくれています。
標準化を行うことによって、特徴量の比率を揃えることが出来ます。

例えば偏差値を例にすると、100点満点のテストと50点満点のテストがあったとして
点数の比率、単位が違う場合でも標準化を利用することでそれらの影響を受けずに点数を評価できます。

標準化は集合の各データから平均を引き、標準偏差で割ることで求めることが出来ます。

z_i = \large{\frac{x_i- \mu}{\sigma}}

μは平均、σは標準偏差、iは任意な自然数を表します。

平均は集合の総和を個数で割ることで求められます。

\mu = \frac{1}{n}\sum ^n_{i}x_i

標準偏差は分散を平方根で割ることで求められます。

\sigma = \sqrt{s^2}

また分散は集合の各データから平均を引いたものを二乗和し、個数で割ることで求められます。

s^2 = \dfrac 1n\sum ^n_{i}(x_i - \mu)^2

まずは機械学習ライブラリなどを利用せず、自分で実装してみたいと思います。
標準化を行う対象として、irisデータセットを利用します。

from sklearn.datasets import load_iris

iris = load_iris()
X = iris.data
print(X[:1]) # array([[5.1, 3.5, 1.4, 0.2]])

import math

def standardize(x):
    """
    Parameters
    ----------
    x: 標準化を行う配列、1次元のベクトルを期待.

    Returns
    -------
    mean: 平均
    var:  分散
    std:  標準偏差
    z:    標準化された配列
    """
    mean = None
    var = None
    std = None
    z = None

    # 平均を算出、集合の総和 / 特徴数
    mean = sum(x) / len(x)

    # 分散を算出、集合の平均 - 特徴の差を2乗和したものを個数で割る
    var = sum([(mean - x_i) ** 2 for x_i in x]) / len(x)

    # 分散を平方根で割る
    std = math.sqrt(var)

    # 各特徴から平均を引き、それを標準偏差で割る
    z = [x_i / std for x_i in [x_i - mean for x_i in x]]

    return [mean, var, std, z]

# データセットの1次元の先頭から7個のデータ
sample_data = X[:, :1][:7] 
print(sample_data.tolist()) # [[5.1], [4.9], [4.7], [4.6], [5.0], [5.4], [4.6]]

mean, var, std, z = standardize(sample_data)

print(mean) # [4.9]
print(var)  # [0.07428571]
print(std)  # 0.2725540575476989
print(*z)   # [0.73379939] [3.25872389e-15] [-0.73379939] [-1.10069908] [0.36689969] [1.83449846] [-1.10069908]

sample_data変数が加工され、浮動小数点に変換されていることが確認できます。

次にsklearn.preprocessing.StandardScalerを利用してみます。

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(sample_data)

print(scaler.mean_) # [4.9]
print(scaler.var_)  # [0.07428571]
print(math.sqrt(scaler.var_)) # 0.2725540575476989
print(*scaler.transform(sample_data))  # [0.73379939] [3.25872389e-15] [-0.73379939] [-1.10069908] [0.36689969] [1.83449846] [-1.10069908]

# 値は同一
print(scaler.mean_ == mean) # [ True]
print(scaler.var_ == var)   # [ True]
print(math.sqrt(scaler.var_) == std) # True
print(*(scaler.transform(sample_data) == z)) # [ True] [ True] [ True] [ True] [ True] [ True] [ True] 

このようにStandardScalerを利用することで少ない分量で標準化を実現できます。

またmean_var_などの標準化の際に算出した値を保持しているため、機械学習モデルの学習時にfitしておけば、モデルの推論時に利用するデータ1に対してもprocessed_query = (np.array(query) - scaler.mean_) - np.sqrt(scaler.var_)と出来るので、とても便利だと思います。


  1. モデル推論時に与えるベクトルが学習時に使用したデータセットの集合に属すると仮定した場合。 

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44