前処理の目的
- 体重と身長など複数の異なる特徴量を生で扱ってしまうと、出力に対して使いやすい(大まかにFitしやすい)方を優先してしまう問題がある。
内容
- 問題解決の単純な方法は異なるカテゴリのデータを同じ範囲のデータに変換する。
- 変換は入力だけでなく、出力も変換する。
- また、一般的には各特徴量毎に変換する。ただし、画像のように2次元(行/列)ではあるが、意味が全ての次元で等しい場合には、全体で変換することも考えられる。
具体的な変換方法
- 一般的には正規化と標準化(ZScore化とも言われる)が良く使われる。
- 正規化は、変換後のデータの最小値, 最大値を0, 1変換する。背景にデータが一様分布に従う場合を想定している。
- 標準化は、平均0, 標準偏差1に変換する。背景にデータが正規化分布に従うことを想定している。
実践
- 2次元データ(n_batch, n_feature)のデータであればSklearnのpreprocessingモジュールで簡単に変換できる。
- 3次元データ、例えば(n_batch, n_object_type, n_object_feature)のような場合にはSklearnが使えない。その場合は下記のような関数を使う。
import sys
import numpy as np
import logging
logger = logging.getLogger(__name__)
class Scaler():
'''
Sklearn-API like simple scaler for data preprocessing.
'''
def __init__(self, mode):
if not(mode in ['maxmin', 'standard']):
logger.error("The mode must be 'maxmin' or 'standard'.")
sys.exit(1)
self.mode = mode
self.maxs = None
self.mins = None
self.means = None
self.stds = None
def fit(self, data, axis=0):
'''
Args:
data: Ndim numpy array .
axis: scaling axis, usually batch dimension.
'''
if self.mode == 'maxmin':
self.maxs = data.max(axis=axis)
self.mins = data.min(axis=axis)
elif self.mode == 'standard':
self.means = data.mean(axis=axis)
self.stds = data.std(axis=axis)
return
def transform(self, data):
if self.mode == 'maxmin':
d = (data - self.mins)/(self.maxs - self.mins)
elif self.mode == 'standard':
d = (data - self.means)/(self.stds)
return d
def fit_transform(self, data, axis=0):
self.fit(data, axis)
d = self.transform(data)
return d
def inverse_transform(self, data):
if self.mode == 'maxmin':
d = data*(self.maxs - self.mins) + self.mins
elif self.mode == 'standard':
d = (data - self.means)/(self.stds)
d = data*self.stds + self.means
return d
if __name__ == '__main__':
d0 = np.random.randn(100,4,2)
s = Scaler('maxmin')
s.fit(d0)
d1 = s.transform(d0)
d2 = s.inverse_transform(d1)
s = Scaler('standard')
s.fit(d0)
d1 = s.transform(d0)
d2 = s.inverse_transform(d1)