Help us understand the problem. What is going on with this article?

StandardScalerを試してみる

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. モデル推論時に与えるベクトルが学習時に使用したデータセットの集合に属すると仮定した場合。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした