この記事は何?
機械学習における前処理として,特徴量のスケーリングがあります.
スケーリングの有無によって,予測器の性能が変化することがあります.
スケーリングにも様々な手法があります.代表的なものとして,「最小値を0,最大値を1とする0-1スケーリング」や,「平均を0,分散を1とするZスコア」があります.
訓練データとテストデータに対してZスコアによるスケーリングを行うとします.Zスコアによるスケーリングでは各特徴量の平均と分散を求める必要がありますが,次の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]
訓練データだけで各特徴量の平均と分散を求めるよりも,訓練データとテストデータを合わせて各特徴量の平均と分散を求めた方が,予測精度がわずかに高いようです.
じゃあどっちを使って評価するべきなの?
予測対象の特徴によって,どちらを使って評価するべきかが変わってくると思います.
- 予測対象が手元に無い未知データのときを想定するならば,スケーリングは訓練データのみを用いて行うべきです.予測対象となるデータを使ってスケーリングはできません.
- 予測対象が手元にあるデータ(ラベルは未知)だけのときを想定するならば,スケーリングはテストデータも含めて行って良いと思います.これは,トランスダクティブ学習の考え方を根拠としています.
トランスダクティブ学習では,未知データの予測は行わず,手元のデータの予測のみ行います.予測対象のデータはもう分かっているのだから,そのデータだけを正しく当てられるように学習すれば良い…という考え方です.
その他
スケーリングをしたからといって,予測精度は必ずしも上がらないものです…つらいですね……