データの前処理は、機械学習において見落とされがちな重要なステップである。
実は、この前処理は、それに適合させるためのピカピカのモデルと同じくらい重要なのです。
ということです。
ガーベッジイン – ガーベッジアウト。
ゴミを入れる。
どんな種類の問題に対しても、最高のモデルを作ることができます – もしそれにゴミを食べさせれば、ゴミを吐き出します。
しかし、「ゴミ」はランダムなデータを指すのではないことに留意する必要があります。
ゴミ」はランダムなデータを指すのではなく、モデルがベストを尽くせないデータに対して付けられる厳しいレッテルなのです。
つまり、同じデータでも、あるモデルには悪いが、別のモデルには素晴らしいということがあるのです。
一般的に、様々な機械学習モデルは、スケールのばらつきが大きいデータではうまく一般化できないので、モデルに投入する前に、そのばらつきを調整する必要があります。
ということです。
正規化と標準化は、データ前処理でよく使われる手法で、特徴量を共通の尺度に調整するものです。
このガイドでは、Feature Scalingとは何かを掘り下げ、データセットの特徴をよりフィットする尺度にスケーリングします。
そして、元のデータとスケーリングされたデータで SGDRegressor
モデルの学習を行い、この特定のデータセットに大きな効果があったかを確認します。
特徴量スケーリングとは – 正規化・標準化
スケーリング(Feature Scaling)とは、特定のフィーチャーのスケールを共通のものに変更するプロセスである。
これは通常、正規化と標準化(スケーリング技術)によって達成される。
- 正規化とは、データを[0, 1]の範囲にスケーリングするプロセスです。回帰のタスクではより便利で一般的です。
x′=x-xminxmax-xminx′=x-xminxmax-xmin。
- 標準化とは、データの平均値が0、標準偏差が1になるようにスケーリングすることです。
x′=x-μσ x′=x-μσ
x’ = frac{x-mu}{sigma}
これらの値を持つ正規分布を標準正規分布と呼びます。
なお、データを標準化したからといって、必ず[0,1]の範囲に入るとは限りません。
これは、この範囲を期待する特定のアルゴリズムにとって問題となり得ます。
標準化を行うために、Scikit-Learn は StandardScaler
クラスを提供しています。
標準化は Min-Max Scaling とも呼ばれ、Scikit-Learn はこの目的のために MinMaxScaler
クラスを用意しています。
一方、 Normalizer
も提供されているので、少し混乱するかもしれません。
注意: Normalizer
クラスは MinMaxScaler
と同じスケーリングを行うわけではありません。
ノーマライザー (Normalizer
) は行に対して動作し、フィーチャーに対しては動作しません。
また、行とは独立してスケーリングします。
Feature Scalingを行うタイミングは?
Feature Scalingは、すべてのモデルでより良いモデル性能を保証するものではありません。
例えば、スケールが重要でない場合、Feature Scalingはあまり役に立ちません。
K-Meansクラスタリングでは、ユークリッド距離が重要なので、Feature Scalingは大きな影響を与えます。
また、勾配に依存するアルゴリズム、例えばGradient Descentで損失を最小化することでフィットする線形モデルなどでも大きな影響を与えます。
主成分分析(PCA)も、適切にスケーリングされていないデータには影響を受けます。
Scikit-Learn の場合、LinearRegression
では目に見える違いはありませんが、SGDRegressor
ではかなりの違いがあります。
これは SGDRegressor
も線形モデルですが、パラメータの適合に Stochastic Gradient Descent を使用しているためです。
木ベースのモデルはスケールが全く影響しないので、スケールのないデータでも問題ありませんが、Classifiers に対して Gradient Boosting を実行すると、スケールは学習に影響します。
データの取り込みと探索的データ解析
ここでは、アイオワ州のAmesで販売された住宅とその販売価格に関する79個の素性を含むAmes Housing Datasetを使用します。
このデータセットは、基本的な回帰訓練と高度な回帰訓練に最適なデータセットです。
なぜなら、微調整できる多くの特徴があり、最終的には通常何らかの形で販売価格に影響を与えるからです。
これらの価格をより正確に予測するためのディープラーニングモデルを生成する、Kerasによるディープラーニングに関する一連の記事を読みたい場合は、ガイド付きプロジェクトをご覧ください。
Pythonの機械学習によるハンズオン住宅価格予測をご覧ください。
データをインポートして、使用する機能のいくつかを見てみましょう。
import pandas as pd
import matplotlib.pyplot as plt
# Load the Dataset
df = pd.read_csv('AmesHousing.csv')
# Single out a couple of predictor variables and labels ('SalePrice' is our target label set)
x = df[['Gr Liv Area', 'Overall Qual']].values
y = df['SalePrice'].values
fig, ax = plt.subplots(ncols=2, figsize=(12, 4))
ax[0].scatter(x[:,0], y)
ax[1].scatter(x[:,1], y)
plt.show()
Gr Liv Area” フィーチャーと “SalePrice” フィーチャーの間には、明らかに強い正の相関があり、異常値は2つだけです。
また、”Overall Qual “と “SalePrice “の間にも強い正の相関があります。
しかし、これらはスケールが大きく異なります。
「Gr Liv Area」は最大5000(平方フィートで測定)、「Overall Qual」機能は最大10(品質の個別カテゴリー)に及びます。
もし、この2つを同じ軸にプロットしたら、「Overall Qual」機能はあまりわからないでしょう。
fig, ax = plt.subplots(figsize=(12, 4))
ax.scatter(x[:,0], y)
ax.scatter(x[:,1], y)
さらに、その分布をプロットしても、あまりうまくいかない。
fig, ax = plt.subplots(figsize=(12, 4))
ax.hist(x[:,0])
ax.hist(x[:,1])
これらの特徴のスケールは非常に異なっており、一緒にプロットしてもあまり意味がない。
そこで、特徴量のスケーリングが行われます。
StandardScaler
StandardScalerクラスは、データを標準化して変換するために使用されます。
このクラスをインポートして、fit_transform()` メソッドでデータをスケーリングしてみましょう。
import pandas as pd
import matplotlib.pyplot as plt
# Import StandardScaler
from sklearn.preprocessing import StandardScaler
fig, ax = plt.subplots(figsize=(12, 4))
scaler = StandardScaler()
x_std = scaler.fit_transform(x)
ax.hist(x_std[:,0])
ax.hist(x_std[:,1])
Note: ここでは、 StandardScaler
クラスの使い方を示し、その効果を可視化するために、データセット全体に対して fit_transform()
を使用しています。
これから行うようなモデルやパイプラインの構築では、データセット全体を fit_transform()
するのではなく、トレーニングデータのみを fit()
して、テストデータのみを transform()
してください。
このコードを実行すると、μとσのパラメータが計算されます。
この処理はデータのフィッティングと呼ばれ、これらの値がそれぞれ1、0に対応するように変換されます。
これらの特徴量の分布をプロットすると、より扱いやすいプロットになります。
もう一度散布図でプロットすると、標準化の効果がより明確にわかると思います。
fig, ax = plt.subplots(figsize=(12, 4))
scaler = StandardScaler()
x_std = scaler.fit_transform(x)
ax.scatter(x_std[:,0], y)
ax.scatter(x_std[:,1], y)
MinMaxScaler
特徴量を正規化するために、 MinMaxScaler
クラスを使用します。
このクラスは StandardScaler
とほぼ同じように動作しますが、データのスケーリングには基本的に異なるアプローチを使用します。
fig, ax = plt.subplots(figsize=(12, 4))
scaler = MinMaxScaler()
x_minmax = scaler.fit_transform(x)
ax.hist(x_minmax [:,0])
ax.hist(x_minmax [:,1])
これらは [0, 1] の範囲で正規化されます。
もし、もう一度分布をプロットすると、次のようになります。
分布の歪度は保たれていますが,標準化によって分布がより重なり合うようになったのとは異なります.しかし,もう一度散布図を通してデータをプロットすると,次のようになります.
fig, ax = plt.subplots(figsize=(12, 4))
scaler = MinMaxScaler()
x_minmax = scaler.fit_transform(x)
ax.scatter(x_minmax [:,0], y)
ax.scatter(x_minmax [:,1], y)
しかし、”Overall Qual “は、”Gr Liv Area “の異常値によって分布の大部分が左側に追いやられたため、右側に大きく張り出していることがわかります。
外れ値の影響
正規化も標準化も外れ値に敏感です。
データセットにたった1つの外れ値があるだけで、物事は本当に奇妙に見えてしまいます。
Gr Liv Area “機能に合成エントリーを追加して、スケーリング処理にどのような影響を与えるか見てみましょう。
fig, ax = plt.subplots(figsize=(12, 4))
scaler = MinMaxScaler()
x_minmax = scaler.fit_transform(x)
ax.scatter(x_minmax [:,0], y)
プロットの右端にある1つの異常値は、新しい分布に大きな影響を及ぼしています。
異常値を除いたすべてのデータは、最初の2つの四分位値に位置しています。
fig, ax = plt.subplots(figsize=(12, 4))
scaler = MinMaxScaler()
x_minmax = scaler.fit_transform(x)
ax.hist(x_minmax [:,0])
Scikit-Learnパイプラインによる特徴量スケーリング
最後に、事前にフィーチャーをスケーリングした場合としない場合のモデルをトレーニングしてみましょう。
機械学習のプロジェクトでは、通常、フィッティングするモデルに到達する前に、データのパイプラインを用意します。
今回は Pipeline
クラスを使用します。
これにより、データのスケーリングとモデルのフィットの2つのステップだけで、このプロセスを最小化し、ある程度自動化することができます。
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.linear_model import SGDRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_absolute_error
import sklearn.metrics as metrics
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Import Data
df = pd.read_csv('AmesHousing.csv')
x = df[['Gr Liv Area', 'Overall Qual']].values
y = df['SalePrice'].values
# Split into a training and testing set
X_train, X_test, Y_train, Y_test = train_test_split(x, y)
# Define the pipeline for scaling and model fitting
pipeline = Pipeline([
("MinMax Scaling", MinMaxScaler()),
("SGD Regression", SGDRegressor())
])
# Scale the data and fit the model
pipeline.fit(X_train, Y_train)
# Evaluate the model
Y_pred = pipeline.predict(X_test)
print('Mean Absolute Error: ', mean_absolute_error(Y_pred, Y_test))
print('Score', pipeline.score(X_test, Y_test))
この結果
Mean Absolute Error: 27614.031131858766
Score 0.7536086980531018
平均絶対誤差は27000で、精度スコアは75%です。
これは、私たちのモデルが平均して27000ドル価格を間違えたことを意味し、それほど悪くはないように思えますが、これ以上に改善することは可能です。
最も重要なのは、私たちが使用したモデルのタイプが少し硬すぎることと、あまり多くの機能を投入していないことで、この2つは間違いなく改善できる点です。
しかし、私たちが興味を持っていることに集中しましょう。
Feature Scalingを使わない場合、このモデルはどのように動作するのでしょうか?パイプラインを変更して、スケーリングステップをスキップしてみましょう。
pipeline = Pipeline([
("SGD Regression", SGDRegressor())
])
驚くようなことが起こるかもしれません。
Mean Absolute Error: 1260383513716205.8
Score -2.772781517117743e+20
特徴量のスケーリングをスキップするだけで、精度が75%から3%に向上しました。
特徴量のスケールに依存する学習アルゴリズムは、通常、特徴量のスケーリングから大きな利益を得ることができる。
そうでないものは、あまり大きな違いは感じないでしょう。
例えば、同じデータで LinearRegression
をスケーリングあり、なしで学習させた場合、スケーリングの結果には変化がなく、モデル自体にはそれなりの結果が出るでしょう。
pipeline1 = Pipeline([
("Linear Regression", LinearRegression())
])
pipeline2 = Pipeline([
("Scaling", StandardScaler()),
("Linear Regression", LinearRegression())
])
pipeline1.fit(X_train, Y_train)
pipeline2.fit(X_train, Y_train)
Y_pred1 = pipeline1.predict(X_test)
Y_pred2 = pipeline2.predict(X_test)
print('Pipeline 1 Mean Absolute Error: ', mean_absolute_error(Y_pred1, Y_test))
print('Pipeline 1 Score', pipeline1.score(X_test, Y_test))
print('Pipeline 2 Mean Absolute Error: ', mean_absolute_error(Y_pred2, Y_test))
print('Pipeline 2 Score', pipeline2.score(X_test, Y_test))
Pipeline 1 Mean Absolute Error: 27706.61376199076
Pipeline 1 Score 0.7641840816646945
Pipeline 2 Mean Absolute Error: 27706.613761990764
Pipeline 2 Score 0.7641840816646945
結論
フィーチャースケーリングとは、フィーチャーの値をより管理しやすい規模にスケーリングするプロセスです。
通常、前処理の段階で、スケールの影響を受けるアルゴリズムにこれらの特徴を投入する前に実行します。
このガイドでは、Scikit-Learnを用いたPythonによる特徴量のスケーリングとは何か、そしてその実行方法について見てきました。
標準化を行うには StandardScaler
を、正規化を行うには MinMaxScaler
を用います。
また、外れ値がこれらの処理にどのように影響するか、そしてFeature Scalingを使用した場合と使用しない場合のスケールセンシティブモデルの違いに注目しました。