データの前処理という重要な工程を勉強しました。
何事にも準備は大切だよね。
今まで、データの処理を行わずに機械学習の訓練を行っていました。機械学習の精度を向上させるためには、アルゴリズムのチューニングより、訓練するためのデータを整えることが重要だということを学びました。今回は、前処理の一つである、「標準化」というものを試してみました。
こんな人の役に立つかも
・機械学習プログラミングの勉強をしている人
・機械学習のデータの標準化を勉強している人
・scikit-learnで標準化プログラムを作成している人
データを整えよう:標準化
機械学習アルゴリズムに与えるデータは、整えてあげることでより精度を向上させる可能性があります。このように、機械学習アルゴリズムにデータを入れる前にあらかじめデータを整えたりすることを「前処理」といいます。
その中で、「標準化」と呼ばれる手法はかなり一般的に行われている前処理の手法とのことです。
標準化は、データの平均を「0」にして、標準偏差を「1」にそろえる操作です。
特徴量のデータの中心が0になるってことだね。
データを確認してみる
scikit-learnの乳がんデータを見てみます。
#ホールドアウトのimport
from sklearn.model_selection import train_test_split,cross_val_score
#乳がんデータ
from sklearn.datasets import load_breast_cancer
#サポートベクターマシン
from sklearn import svm
import numpy as np
import matplotlib.pyplot as plt
panda_box = load_breast_cancer()
print(panda_box.DESCR)
#訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, stratify=y)
print文でDESCRを表示すると、特徴量のデータの最大値、最小値が確認できます。(表示は省略しています。)
:Summary Statistics:
===================================== ====== ======
Min Max
===================================== ====== ======
radius (mean): 6.981 28.11
texture (mean): 9.71 39.28
perimeter (mean): 43.79 188.5
area (mean): 143.5 2501.0
smoothness (mean): 0.053 0.163
compactness (mean): 0.019 0.345
concavity (mean): 0.0 0.427
concave points (mean): 0.0 0.201
これを見ると、4番目の「area」は143~2501という範囲の値に対して、5番目の「smoothness」は、0.019~0.345というとても小さな数値になっています。この特徴量のスケール感の違いを整えるのが、標準化です。
乳がんデータの標準化
乳がんデータの標準化をして、サポートベクターマシンで分類してみます。
標準化プログラム
まずは、scikit-learnの標準化モジュール、「StandardScaler」をimportします。
「StandardScaler」は、「作成」→「訓練(fit)」→「変換(transform)」という順番で使用します。fitでデータの平均や標準偏差を計算します。そして、transformでスケールの変換を実行する、という流れです。
ちなみに、今回は「fit_transform」という訓練と変換を一括にやってくれる機能を利用しています。
#標準化
from sklearn.preprocessing import StandardScaler
#StandardScalerの作成
scaler = StandardScaler()
#訓練データをもとに標準化して訓練データを標準化
X_train_scaled = scaler.fit_transform(X_train)
#テストデータにも標準化を適用
X_test_scaled = scaler.transform(X_test)
ここで「fit_transform」したStandardScalerは、訓練データである「X_train」のデータのスケール感を訓練した状態です。テストデータである「X_test」もこのscalerでtransformすることで同じ変換処理が適用されます。
変換したデータの平均と標準偏差を確認してみます。
print("標準化後の訓練データの特徴量毎の平均")
print(X_train_scaled.mean(axis=0))
print("標準化後の訓練データの標準偏差")
print(X_train_scaled.std(axis=0))
print("標準化後のテストデータの特徴量毎の平均")
print(X_test_scaled.mean(axis=0))
print("標準化後のテストデータの標準偏差")
print(X_test_scaled.std(axis=0))
結果を表示させるとこうなりました。
標準化後の訓練データの特徴量毎の平均
[-5.65435153e-15 1.25590722e-15 1.34340895e-15 1.34213845e-15
-7.81690831e-15 -1.04819648e-15 -7.33372674e-16 -4.64938469e-16
-4.70489584e-15 -4.71453862e-15 1.58975597e-16 -3.40103532e-17
4.13336553e-16 -2.21523373e-18 -2.29863077e-15 7.32851443e-16
8.37618967e-16 -5.21231467e-16 -2.37551241e-15 -8.49607291e-17
-1.90457978e-15 2.33511697e-16 1.45944811e-15 -3.04008253e-16
3.10653954e-15 -4.74320635e-16 1.23010626e-16 -1.13107228e-15
9.69457952e-16 1.46205426e-15]
標準化後の訓練データの標準偏差
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
1. 1. 1. 1. 1. 1.]
標準化後のテストデータの特徴量毎の平均
[ 0.02214126 -0.07753231 0.015516 0.02055765 0.03964471 -0.01806883
-0.03413629 -0.01230238 -0.01455386 -0.00388306 -0.05251804 -0.07983874
-0.05968312 -0.05541079 -0.06611514 -0.11989697 -0.08788572 -0.14531317
-0.071661 -0.105188 0.05040835 0.0104074 0.04547696 0.04249597
0.08954665 0.04337621 0.03819328 0.03023246 0.03281321 0.046278 ]
標準化後のテストデータの標準偏差
[1.01744689 0.98213063 1.00887351 0.96575101 1.02946778 0.99576098
0.9032149 0.97734615 1.07684983 1.07321399 0.78424382 0.86599438
0.77013281 0.67309677 1.03709972 0.74153747 0.98700292 0.94083615
1.11229326 0.64750198 1.04075701 0.93852737 1.02484206 0.9899336
1.07787471 0.97597566 1.04643254 1.13041962 0.95084632 0.96157146]
標準化した訓練データのそれぞれの特徴量の平均値が配列で並んでいます。それぞれの特徴量のデータの平均が「e-15」などと、かなり0に近い数値になっています。
そして、標準偏差は、すべての特徴量で「1」になっています。
次の、標準化後のテストデータは訓練データのscalerを基準に標準化したので、訓練データほど平均は0に近くないですが、かなりデータの中心が0に近づいていることがわかります。標準偏差も1に近い値になっています。
最初、完全にぴったり0にならなければいけないのかと考えていましたが、そうではなく、「特徴量同士の値のスケール感を近づけてあげる」ことが重要であることを勉強しました。
サポートベクターマシンで分類
今回は、「rbfカーネル」(デフォルト設定)のサポートベクターマシンを利用します。
サポートベクターマシンについてはこちらの記事もご参考ください。
まずは、標準化なしのデータです。
#標準化していないデータ
cls = svm.SVC().fit(X_train,y_train)
print("訓練データ:{:.4f}" .format(cls.score(X_train,y_train)))
print("テストデータ:{:.4f}" .format(cls.score(X_test,y_test)))
訓練データ:0.9155
テストデータ:0.9371
訓練データよりテストデータへの正解率が高いので、過学習も起きていなく、いい感じです。
そして、標準化したデータです。
#標準化したデータ
cls2 = svm.SVC().fit(X_train_scaled,y_train)
print("訓練データ:{:.4f}" .format(cls2.score(X_train_scaled,y_train)))
print("テストデータ:{:.4f}" .format(cls2.score(X_test_scaled,y_test)))
訓練データ:0.9859
テストデータ:0.9860
標準化するだけで、すごく精度が向上しました。標準化が一般的に行われる前処理であることを確信しました。
データ前処理、こんな大切だったんだね・・・
こうかはばつぐんだ