人間だったら考えて

考えて考えて人間だったら考えて

スケーリングは訓練データだけでやる?テストデータも混ぜてスケーリングする?

この記事は何?

機械学習における前処理として,特徴量のスケーリングがあります.
スケーリングの有無によって,予測器の性能が変化することがあります.
スケーリングにも様々な手法があります.代表的なものとして,「最小値を0,最大値を1とする0-1スケーリング」や,「平均を0,分散を1とするZスコア」があります.

訓練データとテストデータに対してZスコアによるスケーリングを行うとします.Zスコアによるスケーリングでは各特徴量の平均と分散を求める必要がありますが,次の2つの求め方が考えられます.

  1. 訓練データから各特徴量の平均と分散を求める.
  2. 訓練データとテストデータを合わせて,各特徴量の平均と分散を求める.

意識している人は意識しているでしょうが,どちらが正しい求め方なのでしょうか?この記事では2つの求め方の違いについて考えてみます.

予測精度の違いを確かめてみる

簡単な回帰問題で,2つの平均・分散の求め方による予測精度の違いを確かめてみます.
データセットにはsklearnが用意しているdiabetesデータセットを使いました.
予測器にはLassoを使い,評価にはR^2スコアを用いました.
評価は3-fold Cross Validationによって行いました.

ソースコード

import numpy as np
from sklearn import datasets, preprocessing, cross_validation, linear_model, metrics

np.random.seed(0)
dataset = datasets.load_diabetes()
X = dataset.data
ys = dataset.target
n_folds=3
N = X.shape[0]
kf = cross_validation.KFold(N, n_folds=n_folds, shuffle=True)
def scaling_test(X, ys, kf, scaling_all=False):
    scores = []
    for train_index, test_index in kf:
        X_train, ys_train = X[train_index], ys[train_index]
        X_test, ys_test = X[test_index], ys[test_index]
        
        scaler = preprocessing.StandardScaler()
        if scaling_all:
            scaler.fit(X)
        else:
            scaler.fit(X_train)
        X_train_scaled = scaler.transform(X_train)
        X_test_scaled = scaler.transform(X_test)
        
        model = linear_model.Lasso()
        model.fit(X_train_scaled, ys_train)
        ys_pred = model.predict(X_test_scaled)
        
        score = metrics.r2_score(ys_test, ys_pred)
        scores.append(score)
    mean_cv_score = np.mean(scores)
    print(mean_cv_score, scores)
# scaling with train data
scaling_test(X, ys, kf, scaling_all=False)
    0.48948448111 [0.40182607340355103, 0.51899710839470226, 0.54763026153277639]
# scaling with all data
scaling_test(X, ys, kf, scaling_all=True)
    0.489511363845 [0.4017844911712618, 0.51900200106422789, 0.54774759929815264]

訓練データだけで各特徴量の平均と分散を求めるよりも,訓練データとテストデータを合わせて各特徴量の平均と分散を求めた方が,予測精度がわずかに高いようです.

じゃあどっちを使って評価するべきなの?

予測対象の特徴によって,どちらを使って評価するべきかが変わってくると思います.

  • 予測対象が手元に無い未知データのときを想定するならば,スケーリングは訓練データのみを用いて行うべきです.予測対象となるデータを使ってスケーリングはできません.
  • 予測対象が手元にあるデータ(ラベルは未知)だけのときを想定するならば,スケーリングはテストデータも含めて行って良いと思います.これは,トランスダクティブ学習の考え方を根拠としています.

トランスダクティブ学習では,未知データの予測は行わず,手元のデータの予測のみ行います.予測対象のデータはもう分かっているのだから,そのデータだけを正しく当てられるように学習すれば良い…という考え方です.

その他

スケーリングをしたからといって,予測精度は必ずしも上がらないものです…つらいですね……