📑

アンダーサンプリングによる不均衡データへの対処

2024/06/06に公開

アンダーサンプリングとは

アンダーサンプリングとは、目的変数がある特定の値(クラス)に偏っている場合、その偏りを解消するためにテスト用データでのクラスの比率を均一にすることです。

どういうことかというと、例えばボートレースの着順を予測するモデルを作るとします。
ボートレースや競馬においては3連単のように3着以内に入るかが重要であるため、4着以下はすべて4着扱いにまとめるように前処理をしたとします。
つまり、5着や6着であっても4着として扱うようにします。

すると、結果的に以下のように4着のデータが多くなります。

df['arrival'] = df['arrival'].fillna(6)
df["arrival"] = df["arrival"].astype(int)
df['arrival'] = df['arrival'].apply(lambda x: 4 if x > 3 else x)
df['arrival'].value_counts()
arrival
4    81081
2    27030
1    27026
3    27025
Name: count, dtype: int64

このような偏りがあるデータをこれを不均衡データといいます。

このようなデータを用いてモデルの学習を行うと、モデルは4着のデータを多く学習するため、4着の予測精度は高くなるものの、1着、2着、3着の予測精度は低くなります。
予測が多数クラスに偏るようなことを避けるため、訓練データでは各クラスのサンプル数を揃える必要があります。

アンダーサンプリングを用いることで、少数クラス(1着, 2着, 3着)に合わせて多数クラス(4着)のデータを減らし、クラス間のバランスを取ります。

もうひとつ例を出しておくと、スパムメールの分類なんかも不均衡データが多いと思います。
仮にスパムメールが全体の1%しかない場合、スパムメールのデータが少なく、非スパムメールのデータが多いというクラス不均衡が発生します。

これらの例から分かるように、アンダーサンプリングは主に分類問題において使用されるデータ準備の手法です。
例えば、回帰問題では目標値が連続値であり、クラス不均衡の概念は直接適用されません。
したがって、アンダーサンプリングは通常、回帰問題に対して使用されません。

実装例

from imblearn.under_sampling import RandomUnderSampler

def undersample_data(
    X_train: pd.DataFrame, y_train: pd.Series, random_state: int = 42
) -> tuple[pd.DataFrame, pd.Series]:
    class_counts = y_train.value_counts()
    sample_count = class_counts.min()
    sampling_strategy = {cls: sample_count for cls in class_counts.index}

    rus = RandomUnderSampler(sampling_strategy=sampling_strategy, random_state=random_state)
    X_train_resampled, y_train_resampled = rus.fit_resample(X_train, y_train)

    return X_train_resampled, y_train_resampled

X = df.drop(columns=['arrival'])
y = df['arrival']

X_resampled, y_resampled = undersample_data(X, y)
y_resampled.value_counts()
arrival
1    27025
2    27025
3    27025
4    27025
Name: count, dtype: int64

補足

テストデータの分割

訓練データのアンダーサンプリングとテストデータの分割は別々に行います。
テストデータではクラスの比率を自然に保つことが一般的です。
これにより、モデルの評価が実際のデータの分布を反映するようになります。

適用範囲

アンダーサンプリングは、クラス不均衡が存在する場合に有効です。
ただし、データの全体数が少ない場合や、重要なデータが失われるリスクがある場合には注意が必要です。

Discussion