Python Scikit-learnによるRobustScalerの基本と応用 – 外れ値に頑健なスケーリング手法

Python

機械学習のモデル構築において、データの前処理はモデルの性能を大きく左右する非常に重要なステップです。「手元のデータに外れ値(異常値)が含まれていて、うまくモデルの精度が上がらない」「StandardScalerを使っているけど、外れ値の影響を受けている気がする」といった悩みを抱えている方も多いのではないでしょうか。

この記事では、そうした外れ値を含むデータの前処理で絶大な効果を発揮する、Scikit-learnのRobustScalerに焦点を当てて解説します。

この記事を最後まで読むことで、あなたは以下のことができるようになります。

  • なぜデータスケーリングが必要なのか、その本質を理解できる。
  • RobustScalerがなぜ外れ値に強いのか、その仕組みを説明できるようになる。
  • PythonとScikit-learnを使ってRobustScalerを実装し、データを変換できるようになる。
  • StandardScalerMinMaxScalerとの違いを理解し、適切な場面でRobustScalerを選択できるようになる。

外れ値に悩まされる日々から脱却し、より堅牢な機械学習モデルを構築するための一歩を、この記事と共に踏み出しましょう。

なぜデータスケーリングが必要なのか?

結論から言うと、データスケーリングは機械学習モデルの性能を公平かつ最大化するために必要不可欠な処理です。

多くの機械学習アルゴリズム、特に距離の概念を用いて計算を行う手法(例えば、k-NN、サポートベクターマシン(SVM)、主成分分析(PCA)など)や、勾配降下法を用いて学習する手法(例えば、線形回帰、ロジスティック回帰、ニューラルネットワークなど)は、各特徴量(変数)のスケール(単位や範囲)が大きく異なると、その影響を強く受けてしまいます。

例えば、あるECサイトの顧客データについて考えてみましょう。特徴量として「年齢(10〜80歳)」と「年間購入額(5,000〜10,000,000円)」があったとします。

この2つの特徴量をそのままモデルに入力するとどうなるでしょうか。「年間購入額」の数値の範囲は「年齢」に比べて圧倒的に大きいため、モデルは「年間購入額」という特徴量を過度に重視してしまい、「年齢」という特徴量がほとんど考慮されなくなってしまう可能性があります。

つまり、特徴量間でスケールの違いがあることで、モデルに不公平なバイアスがかかってしまうのです。

データスケーリングは、こうした各特徴量のスケールを一定の基準で揃える(正規化または標準化する)ことで、すべての特徴量を公平に扱えるようにし、モデルが本来のパターンを学習するのを助ける役割を果たします。これにより、学習プロセスの安定化や収束の高速化、そして最終的な予測精度の向上が期待できるのです。

RobustScalerとは?外れ値に頑健なスケーリング手法

結論として、RobustScalerは、統計的な中央値と四分位範囲(IQR)を用いてスケーリングを行うため、外れ値の影響をほとんど受けない非常に堅牢な(Robustな)手法です。

一般的なスケーリング手法であるStandardScalerは、データの平均値と標準偏差を利用します。しかし、平均値と標準偏差は、データセット内に極端に大きい、あるいは小さい「外れ値」が存在すると、その値に大きく引っ張られてしまうという性質があります。

例えば、[1, 2, 3, 4, 5] というデータの平均は 3 ですが、ここに 100 という外れ値が1つ加わるだけで、[1, 2, 3, 4, 5, 100] の平均は約 19.2 にまで跳ね上がってしまいます。これでは、データの中心を正しく表現できているとは言えません。

そこで登場するのがRobustScalerです。RobustScalerは、この問題に対処するために、以下の2つの統計量を利用します。

  1. 中央値(Median): データを小さい順に並べたときに、ちょうど真ん中に来る値です。外れ値がデータセットの端に追加されても、中央値はほとんど変動しません。
  2. 四分位範囲(Interquartile Range, IQR): データを小さい順に並べ、4等分したときの「75パーセンタイル(第3四分位点, Q3)」と「25パーセンタイル(第1四分位点, Q1)」の差です(IQR = Q3 - Q1)。これはデータの中央50%がどのくらいの範囲に分布しているかを示す指標であり、外れ値の影響を受けにくいという特徴があります。

RobustScalerは、各データ点から中央値を引き、それを四分位範囲(IQR)で割ることでスケーリングを行います。数式で表すと以下のようになります。

Xscaled​=IQR(X)X−median(X)​

この計算により、外れ値に惑わされることなく、データ本来の分布構造を保ったままスケーリングを行うことができるのです。

Scikit-learnでRobustScalerを使ってみよう【基本編】

結論として、RobustScalersklearn.preprocessingモジュールからインポートし、fit_transformメソッドを呼び出すだけで、誰でも簡単に利用できます。

ここでは、実際にPythonのコードを動かしながら、RobustScalerの基本的な使い方をマスターしていきましょう。

準備:ライブラリのインポートとサンプルデータ作成

まずは、必要なライブラリをインポートし、意図的に外れ値を含んだサンプルデータを作成します。numpy配列としてデータを用意するのが一般的です。

import numpy as np
from sklearn.preprocessing import RobustScaler

# サンプルデータを作成
# ほとんどのデータは10から20の間に分布しているが、
# 200と-150という極端な外れ値が含まれている
data = np.array([
    [10.0],
    [12.0],
    [15.0],
    [16.0],
    [18.0],
    [20.0],
    [200.0], # 極端に大きい外れ値
    [-150.0] # 極端に小さい外れ値
])

print("--- 元のデータ ---")
print(data)

RobustScalerの基本的な使い方

RobustScalerの使い方は、Scikit-learnの他の変換器(Transformer)と同様、非常にシンプルです。

  1. RobustScalerのインスタンスを作成します。
  2. fit()メソッドで、データからスケーリングに必要な統計量(この場合は中央値とIQR)を計算します。
  3. transform()メソッドで、計算された統計量を使って実際にデータを変換します。

通常は、このfit()transform()を一度に行うfit_transform()メソッドを使用するのが便利です。

# 1. RobustScalerのインスタンスを作成
scaler = RobustScaler()

# 2. fit()とtransform()を同時に行い、データをスケーリング
scaled_data = scaler.fit_transform(data)

print("\n--- RobustScalerでスケーリング後のデータ ---")
print(scaled_data)

# fit()によって計算された統計量も確認できます
print(f"\n計算された中央値 (center_): {scaler.center_}")
print(f"計算された四分位範囲 (scale_): {scaler.scale_}")

実行結果の解説:

--- 元のデータ ---
[[  10.]
 [  12.]
 [  15.]
 [  16.]
 [  18.]
 [  20.]
 [ 200.]
 [-150.]]

--- RobustScalerでスケーリング後のデータ ---
[[ -0.8]
 [ -0.4]
 [  0.2]
 [  0.4]
 [  0.8]
 [  1.2]
 [ 38. ]
 [-32.4]]

計算された中央値 (center_): [15.5]
計算された四分位範囲 (scale_): [5.]Code language: CSS (css)

結果を見ると、元のデータの中央値であった15.50.20.4の間に変換されていることがわかります(このデータの場合、偶数個なので15と16の平均である15.5が中央値)。 RobustScalerは中央値を0に変換しようとします。スケーリング後のデータ[0.2][0.4]のちょうど中間が0.3あたりになりますが、これは計算上の丸め誤差やデータ点そのものの位置によるものです。重要なのは、データの中心が0付近に寄せられている点です。

また、200-150といった外れ値は、それぞれ38.0-32.4という非常に大きな(または小さな)値に変換されていますが、他のデータ[-0.8, -0.4, ..., 1.2]は比較的小さな範囲に収まっています。これは、外れ値の影響を受けずに、主要なデータ群の構造を維持しながらスケーリングが行われたことを示しています。

このように、RobustScalerは非常に簡単に利用でき、外れ値が存在するデータに対して強力な前処理手法となります。

RobustScalerと他のスケーラーとの比較【応用編】

結論として、データの分布や外れ値の有無に応じて、StandardScalerMinMaxScalerRobustScalerの中から最適なスケーラーを選択することが、モデルの性能向上において非常に重要です。

RobustScalerの有効性をより深く理解するために、同じ外れ値を含むデータを他の代表的なスケーラーで処理した場合と比較してみましょう。

StandardScalerとの比較

StandardScalerは、平均を0、標準偏差を1に変換する、最も広く使われているスケーラーです。しかし、前述の通り、平均と標準偏差は外れ値の影響を強く受けます。

from sklearn.preprocessing import StandardScaler

# StandardScalerのインスタンスを作成
std_scaler = StandardScaler()

# 同じデータでスケーリング
std_scaled_data = std_scaler.fit_transform(data)

print("\n--- StandardScalerでスケーリング後のデータ ---")
print(std_scaled_data)

print(f"\n計算された平均 (mean_): {std_scaler.mean_}")
print(f"計算された標準偏差 (scale_): {std_scaler.scale_}")

実行結果の解説:

--- StandardScalerでスケーリング後のデータ ---
[[-0.14695511]
 [-0.12569269]
 [-0.0937989 ]
 [-0.08316769]
 [-0.06190527]
 [-0.04064285]
 [ 1.93655106]
 [-1.38448855]]

計算された平均 (mean_): [16.375]
計算された標準偏差 (scale_): [93.42852296]Code language: CSS (css)

200-150という外れ値の影響で、平均が16.375に、標準偏差が93.4というとてつもなく大きな値になっています。その結果、外れ値ではないデータ(10から20の範囲)はすべて-0.15から-0.04という非常に狭い範囲に押し込められてしまいました。これでは、各データの持つ本来の差異が失われてしまい、モデルが有用な情報を学習するのが困難になります。

MinMaxScalerとの比較

MinMaxScalerは、データを指定した範囲(デフォルトは0から1)に収まるようにスケーリングします。このスケーラーは、最大値と最小値を利用するため、外れ値に対して最も敏感です。

from sklearn.preprocessing import MinMaxScaler

# MinMaxScalerのインスタンスを作成
minmax_scaler = MinMaxScaler()

# 同じデータでスケーリング
minmax_scaled_data = minmax_scaler.fit_transform(data)

print("\n--- MinMaxScalerでスケーリング後のデータ ---")
print(minmax_scaled_data)

実行結果の解説:

--- MinMaxScalerでスケーリング後のデータ ---
[[0.45714286]
 [0.46285714]
 [0.47142857]
 [0.47428571]
 [0.48      ]
 [0.48571429]
 [1.        ]
 [0.        ]]Code language: CSS (css)

最小値が-150、最大値が200なので、MinMaxScaler-1500に、2001に変換します。その結果、StandardScalerの例と同様に、10から20の間のデータは0.45から0.48という極めて狭いレンジに圧縮されてしまいました。これではデータ間の違いがほとんどなくなり、StandardScaler以上に情報の損失が大きいと言えます。

どのような場合にRobustScalerを選択すべきか?

ここまでの比較から、RobustScalerがどのような場面で特に有効なのかが見えてきました。

  • データに外れ値やノイズが含まれていることが明らかな場合: これがRobustScalerの最も得意とする領域です。金融データでの異常取引、センサーデータのエラー値、医療データでの特異な検査結果など、現実世界の多くのデータセットで有効です。
  • データが正規分布に従っていない場合: StandardScalerはデータが正規分布に従うことを暗黙的に仮定しています。データが歪んだ分布(スキューした分布)を持つ場合、中央値を基準とするRobustScalerの方が、データの中心をより適切に捉えることができます。
  • 他のスケーラーでモデルの性能が向上しない場合: データの前処理で行き詰まった際に、試してみる価値のある強力な選択肢となります。

逆に、データに外れ値がほとんどなく、分布が正規分布に近いとわかっている場合は、StandardScalerが依然として非常に優れた性能を発揮します。常にデータの分布を可視化・分析し、その特性に合ったスケーラーを選択する癖をつけることが重要です。

RobustScalerのパラメータと注意点

結論として、RobustScalerの主要なパラメータであるwith_centeringquantile_rangeを理解し、訓練データとテストデータへの適用の仕方を間違えないことが、正しく活用する上で重要です。

with_centering

このパラメータは、スケーリング前にデータから中央値を引くかどうかを決定します。

  • with_centering=True (デフォルト): データから中央値を引き、データの中心を0に近づけます。これが通常のRobustScalerの動作です。
  • with_centering=False: データから中央値を引きません。データの中心位置は変えずに、IQRによるスケーリングのみを行います。スパースデータ(0が多いデータ)など、データの中心を動かしたくない場合に利用することがあります。

quantile_range

これは、スケール計算に使用するパーセンタイルの範囲を指定するパラメータです。

  • quantile_range=(25.0, 75.0) (デフォルト): 第1四分位点(Q1)と第3四分位点(Q3)の範囲、つまり四分位範囲(IQR)を使用します。
  • quantile_range=(10.0, 90.0) など: このように変更すると、10パーセンタイル点と90パーセンタイル点の範囲を使ってスケーリングを行います。これにより、さらに外れ値に対して頑健になる可能性がありますが、どの範囲が最適かはデータに依存します。

訓練データとテストデータへの適用

これはRobustScalerに限らず、全てのスケーラーや前処理に共通する非常に重要な注意点です。

機械学習モデルを構築する際、データを訓練データ(モデルの学習用)とテストデータ(モデルの性能評価用)に分割します。このとき、スケーラーのfitメソッドは、必ず訓練データにのみ適用しなければなりません。

なぜなら、テストデータは「モデルがまだ見たことのない未知のデータ」という位置づけだからです。もしテストデータも含めてfitしてしまうと、未来のデータの情報(中央値やIQR)を学習時に盗み見てしまうことになり、これを**データリーケージ(Data Leakage)**と呼びます。データリーケージが起こると、モデルの性能を過大評価してしまい、実際の運用時に期待した性能が出なくなります。

正しい手順は以下の通りです。

  1. データを訓練データとテストデータに分割する。
  2. 訓練データのみを使ってスケーラーをfitする(統計量を計算させる)。
  3. fit済みのスケーラーを使って、訓練データとテストデータの両方transformする。

具体的なコードで見てみましょう。

from sklearn.model_selection import train_test_split

# 2次元のサンプルデータで実践
X = np.array([
    [10], [12], [15], [16], [18], [20], [200], [-150],
    [5], [7], [8], [9], [11], [13], [100], [-80]
])
y = np.arange(16) # yは今回は使いませんが、分割のために必要

# 1. データを訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

# スケーラーのインスタンスを作成
final_scaler = RobustScaler()

# 2. 訓練データ(X_train)のみでfitする
final_scaler.fit(X_train)

# 3. 訓練データとテストデータの両方をtransformする
X_train_scaled = final_scaler.transform(X_train)
X_test_scaled = final_scaler.transform(X_test)

print("--- スケーリング前のテストデータ ---")
print(X_test)
print("\n--- スケーリング後のテストデータ ---")
print(X_test_scaled)
print(f"\n訓練データから計算された中央値: {final_scaler.center_}")
print(f"訓練データから計算されたIQR: {final_scaler.scale_}")

このコードは、テストデータ(X_test)のスケーリングに、訓練データ(X_train)から計算された中央値とIQRを使っている点がポイントです。これにより、データリーケージを防ぎ、モデルの性能を正しく評価することができます。

まとめ

今回は、外れ値に強いデータスケーリング手法であるRobustScalerについて、その仕組みから実践的な使い方、他のスケーラーとの比較まで、網羅的に解説しました。

最後に、この記事の要点をまとめます。

  • データスケーリングは、特徴量間のスケールを揃え、モデルが公平に学習するために不可欠な前処理である。
  • RobustScalerは、平均や標準偏差の代わりに中央値と**四分位範囲(IQR)**を用いるため、データに含まれる外れ値の影響を劇的に軽減できる。
  • Scikit-learnを使えば、RobustScaler()fit_transform()を呼び出すだけで、数行のコードで簡単に実装できる。
  • データに外れ値が多い場合や、分布が正規分布から大きく外れている場合にRobustScalerは特に有効であり、StandardScalerMinMaxScalerの適切な代替手段となる。
  • モデルを正しく評価するためには、訓練データのみでfitし、そのスケーラーで訓練・テストの両データをtransformするというルールを徹底する必要がある。

データ前処理は地味な作業に見えるかもしれませんが、その質が機械学習プロジェクト全体の成否を分けると言っても過言ではありません。RobustScalerという強力なツールをあなたの道具箱に加え、ぜひお手元のデータでその効果を試してみてください。きっと、モデルの性能向上に繋がる新たな発見があるはずです。

コメント

タイトルとURLをコピーしました