機械学習のためのデータ前処理:なぜスケーリングが必要?正規化と標準化の違い【Pandas+Scikit-learn入門】
機械学習モデルを構築する際、データの準備は非常に重要なステップです。特に数値データを含む場合、「スケーリング」と呼ばれる前処理が必要になることがあります。このステップは、モデルの性能に大きく影響を与える可能性があるため、その目的と具体的な手法を理解することは、機械学習を実務に応用する上で欠かせません。
この記事では、数値データのスケーリングが必要な理由から始め、代表的な手法である正規化(Normalization)と標準化(Standardization)について、それぞれの概念、目的、そしてPython(Pandas、Scikit-learn)を用いた実装方法を解説します。
なぜ数値データのスケーリングが必要なのか?
私たちが扱うデータには、様々な種類の数値が含まれています。例えば、顧客データであれば「購入金額」(数百円から数十万円)、企業のデータであれば「従業員数」(数人から数万人)や「設立からの年数」(数年から数十年)などが考えられます。これらの数値は、それぞれスケール(値の範囲)が大きく異なります。
多くの機械学習アルゴリズム、特に距離を計算してデータの関係性を判断するようなアルゴリズム(例:サポートベクターマシン、K近傍法、主成分分析など)は、数値の大小やスケールの違いに影響を受けやすい性質があります。
例えば、購入金額の列が0〜1,000,000、設立年数の列が0〜100のような範囲を持つ場合、購入金額のわずかな差が、設立年数の大きな差よりも、モデルの計算において「重要」であるかのように扱われてしまう可能性があります。これは、単に数値の絶対的な大きさが異なるだけであり、本来意図しないバイアス(偏り)をモデルに与えてしまうことに繋がります。
スケーリングは、このようにスケールが異なる複数の数値特徴量を、同程度の範囲や分布に調整することで、モデルが公平に各特徴量を評価できるようにするための前処理です。これにより、アルゴリズムが数値のスケールに惑わされず、データの本来的なパターンや関係性をより正確に学習できるようになります。
スケーリングの代表的な手法:正規化と標準化
数値データをスケーリングする手法にはいくつか種類がありますが、特によく用いられるのが「正規化(Normalization)」と「標準化(Standardization)」です。これらは目的や計算方法が異なります。
正規化(Normalization)
正規化は、データの値を特定の範囲(多くの場合0から1の間)に収める手法です。最も一般的なのはMin-Maxスケーリングです。
目的: データの最小値を0、最大値を1として、それ以外の値を0と1の間の値に変換します。これにより、全ての数値特徴量の範囲が揃えられます。
計算方法: $$ X_{\text{normalized}} = \frac{X - X_{\text{min}}}{X_{\text{max}} - X_{\text{min}}} $$ ここで、$X$は元の値、$X_{\text{min}}$はその特徴量の最小値、$X_{\text{max}}$は最大値です。
どのような場合に有効か: データの範囲を厳密に指定したい場合や、最小値と最大値が明確で外れ値の影響を受けにくいデータに適しています。ニューラルネットワークなどで、入力値を特定の範囲に収めることが推奨される場合にも利用されます。
Pythonによる実装例(Scikit-learnのMinMaxScaler)
ここでは、数値データを含む簡単なデータフレームを例に、正規化の手順を示します。
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
# サンプルデータの作成
data = {'金額': [1000, 5000, 20000, 300, 150000],
'年齢': [25, 40, 55, 22, 60],
'従業員数': [10, 50, 200, 5, 5000]}
df = pd.DataFrame(data)
print("--- 元のデータ ---")
print(df)
# 正規化(Min-Maxスケーリング)の適用
# MinMaxScalerを初期化
scaler = MinMaxScaler()
# データにスケーリングを適用(訓練データでfit_transformを使用)
# カラム名を保持するため、Pandas DataFrameとして再構築します
df_normalized = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
print("\n--- 正規化後のデータ ---")
print(df_normalized)
このコードでは、MinMaxScaler
を使用して各列のデータを0から1の間に変換しています。fit_transform
メソッドは、データの最小値・最大値を学習(fit)し、その情報を使ってデータを変換(transform)します。
標準化(Standardization)
標準化は、データの平均が0、標準偏差が1になるように変換する手法です。Z-score標準化とも呼ばれます。
目的: データの平均を0に、散らばり具合(標準偏差)を1に揃えることで、データの分布の形状を保ちつつ、異なる特徴量間のスケールを比較可能な状態にします。
計算方法: $$ X_{\text{standardized}} = \frac{X - \mu}{\sigma} $$ ここで、$X$は元の値、$\mu$はその特徴量の平均値、$\sigma$は標準偏差です。
どのような場合に有効か: データの分布が正規分布に近い場合や、外れ値の影響を受けやすい場合(外れ値を含むとMin-Maxスケーリングでは大部分のデータが狭い範囲に圧縮されてしまう)、そして多くの線形モデル(線形回帰、ロジスティック回帰など)や、主成分分析(PCA)などの手法でよく使用されます。
Pythonによる実装例(Scikit-learnのStandardScaler)
import pandas as pd
from sklearn.preprocessing import StandardScaler
# サンプルデータは正規化と同じものを使用
data = {'金額': [1000, 5000, 20000, 300, 150000],
'年齢': [25, 40, 55, 22, 60],
'従業員数': [10, 50, 200, 5, 5000]}
df = pd.DataFrame(data)
print("--- 元のデータ ---")
print(df)
# 標準化(Z-score標準化)の適用
# StandardScalerを初期化
scaler = StandardScaler()
# データにスケーリングを適用(訓練データでfit_transformを使用)
# カラム名を保持するため、Pandas DataFrameとして再構築します
df_standardized = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
print("\n--- 標準化後のデータ ---")
print(df_standardized)
このコードでは、StandardScaler
を使用して各列のデータが平均0、標準偏差1になるように変換しています。fit_transform
の動作はMinMaxScaler
と同様です。標準化後の値は、元の値が平均からどれだけ離れているかを示し、負の値も取ります。
どちらの手法を選ぶべきか?
正規化と標準化のどちらを選ぶかは、使用する機械学習アルゴリズムやデータの性質によって異なります。
- 正規化 (Min-Maxスケーリング):
- メリット: データを特定の範囲に収めるため、範囲が重要なアルゴリズム(例: ニューラルネットワークの活性化関数が入力範囲に制約がある場合)や、データの最小値と最大値が明確で外れ値の影響を受けにくい場合に適しています。
- デメリット: 外れ値が存在すると、最小値や最大値が大きく影響を受け、大部分のデータが狭い範囲に圧縮されてしまう可能性があります。
- 標準化 (Z-score標準化):
- メリット: 外れ値の影響を受けにくい(外れ値自体は存在し続けますが、変換後の値の極端さは正規化ほどではなくなることが多い)。データの分布の形状を保ちます。
- デメリット: 特定の固定された範囲に収まるわけではないため、入力範囲に制約があるアルゴリズムにはそのままでは適さない場合があります。
一般的には、多くのアルゴリズムで標準化がデフォルトの選択肢となることが多いですが、最終的にはいくつかの手法を試して、最もモデルの性能が向上するものを選ぶことが推奨されます。
スケーリングを適用する際の注意点
スケーリング処理を行う上で最も重要な注意点は、「訓練データでスケーラーを学習させ、その学習したスケーラーを使って訓練データとテストデータの両方を変換する」という点です。
機械学習モデルの性能評価では、未知のデータ(テストデータ)に対する予測精度を確認します。テストデータは、モデル構築時には参照すべきではありません。これはスケーリングにおいても同様で、テストデータの平均値や標準偏差、最小値・最大値を使ってスケーラーを学習させてしまうと、テストデータの情報がモデル構築プロセスに漏洩(データリーケージ)することになり、正しい性能評価ができなくなります。
正しい手順は以下のようになります。
- データを訓練データとテストデータに分割する。
- 訓練データのみを使用してスケーラー(
MinMaxScaler
やStandardScaler
など)をfit
(学習)させる。 fit
で学習したスケーラーを使って、訓練データとテストデータの両方をtransform
(変換)する。
これにより、テストデータは訓練データと同じ基準でスケーリングされ、公正な評価が可能になります。
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# サンプルデータの作成(特徴量Xと目的変数yに分ける想定)
data = {'金額': [1000, 5000, 20000, 300, 150000],
'年齢': [25, 40, 55, 22, 60],
'従業員数': [10, 50, 200, 5, 5000],
'購入有無': [0, 1, 1, 0, 1]} # 例:目的変数
df = pd.DataFrame(data)
# 特徴量と目的変数に分割
X = df[['金額', '年齢', '従業員数']]
y = df['購入有無']
# データを訓練用とテスト用に分割
# random_stateを固定することで、毎回同じ分割結果になります
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
print("--- 分割前のデータ ---")
print(X)
print("\n--- 訓練用特徴量データ ---")
print(X_train)
print("\n--- テスト用特徴量データ ---")
print(X_test)
# 標準化(Z-score標準化)の適用
scaler = StandardScaler()
# 訓練データでスケーラーを学習(fit)し、訓練データを変換(transform)
X_train_scaled = scaler.fit_transform(X_train)
# テストデータに、訓練データで学習したスケーラーを適用(transformのみ!)
X_test_scaled = scaler.transform(X_test)
print("\n--- 訓練用特徴量データ(標準化後) ---")
# numpy配列になるためDataFrameに戻して表示
print(pd.DataFrame(X_train_scaled, columns=X_train.columns, index=X_train.index))
print("\n--- テスト用特徴量データ(標準化後) ---")
print(pd.DataFrame(X_test_scaled, columns=X_test.columns, index=X_test.index))
このコード例のように、X_train
に対してはfit_transform
を使い、X_test
に対してはtransform
のみを使うのが正しいスケーリングのプロセスです。
まとめ
この記事では、機械学習における数値データのスケーリングの重要性、そして代表的な手法である正規化(Min-Maxスケーリング)と標準化(Z-score標準化)について解説しました。
- スケーリングの目的: スケールが異なる数値特徴量を同程度の範囲や分布に調整し、モデルが公平に各特徴量を評価できるようにする。
- 正規化: データを特定の範囲(例: 0-1)に変換。Min-Maxスケーリングが代表的。範囲を揃えたい場合に有効。
- 標準化: データの平均を0、標準偏差を1に変換。Z-score標準化が代表的。外れ値に強く、多くのモデルで効果的。
- 実装: Scikit-learnの
MinMaxScaler
やStandardScaler
を使用すると効率的に実装できる。 - 注意点: 訓練データでスケーラーを学習させ、テストデータは学習済みのスケーラーで変換する必要がある。
データ前処理は、機械学習モデルの性能を左右する重要なステップです。特に数値データに対するスケーリングは多くのケースで必要となりますので、ぜひこの記事の内容を参考に、実際のデータで試してみてください。他のデータ前処理手法についても、今後解説していく予定です。