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_)
と出来るので、とても便利だと思います。
-
モデル推論時に与えるベクトルが学習時に使用したデータセットの集合に属すると仮定した場合。 ↩