機械学習データ前処理:不均衡データ(クラス不均衡)への基本的な対処法【Pandas+Scikit-learn入門】
はじめに:不均衡データという落とし穴
機械学習モデルを構築する際、データの準備である「前処理」は非常に重要なステップです。これまでの記事では、欠損値の扱いやデータ型の変換、特徴量の作成など、さまざまな前処理手法を解説してきました。
今回は、特に分類問題を扱う際によく遭遇する、「不均衡データ(クラス不均衡)」という問題に焦点を当てます。これは、予測したいターゲットのカテゴリ(クラス)のデータ数に大きな偏りがある状況を指します。例えば、クレジットカードの不正利用検知データで、ほとんどの取引が正常である一方で、不正取引はごくわずかしかないようなケースです。
このような不均衡データは、前処理をせずにそのままモデルに学習させると、一見性能が良いように見えても、実際には役に立たないモデルになってしまうことがあります。この記事では、不均衡データがなぜ問題なのかを理解し、その基本的な対処法である「リサンプリング」について、具体的なコード例を交えながら解説します。
不均衡データ(クラス不均衡)とは何か?
不均衡データとは、分類問題において、予測対象となるカテゴリ(クラス)のデータ数が極端に偏っている状態を指します。
例えば、あるオンラインサービスのユーザー行動データを分析し、「購入に至るユーザー」と「購入に至らないユーザー」を予測するモデルを考えます。もし全ユーザーの95%が「購入に至らない」ユーザーで、わずか5%しか「購入に至る」ユーザーがいない場合、これは不均衡データと言えます。
他にも、以下のような例で不均衡データは頻繁に発生します。
- 金融分野: 不正取引検知(正常取引 >> 不正取引)
- 医療分野: 疾患診断(健常者 >> 疾患のある人)
- 製造業: 製品の不良品検知(良品 >> 不良品)
- マーケティング: 特定のアクション(クリック、登録など)に繋がるユーザー予測(アクションしないユーザー >> アクションするユーザー)
データセット全体を対象としたグラフを作成すると、特定のクラス(少数派クラス)のデータ数が、他のクラス(多数派クラス)に比べて圧倒的に少ないことが視覚的に確認できます。
なぜ不均衡データは問題になるのか?
不均衡データをそのまま機械学習モデルに学習させると、多くの場合、モデルはデータ数の多い多数派クラスを優先して学習してしまいます。その結果、少数派クラスをうまく識別できないモデルになってしまう可能性が高くなります。
例えば、先ほどの「購入に至るユーザー」予測の例で、95%が「購入に至らない」ユーザー、5%が「購入に至る」ユーザーだったとします。このデータをそのまま学習させたモデルが、「どんなユーザーも購入に至らない」と予測するモデルだったとします。
このモデルの「正解率(Accuracy)」を計算してみましょう。 - 「購入に至らない」ユーザー(95%)に対して、「購入に至らない」と正しく予測:95% - 「購入に至る」ユーザー(5%)に対して、「購入に至らない」と間違って予測:5% 全体の正解率は 95% + 0% = 95% となります。
正解率だけ見ると95%と非常に高く、一見性能の良いモデルのように見えます。しかし、「購入に至るユーザー」を予測するという本来の目的においては、誰も予測できていない、全く役に立たないモデルです。
このように、不均衡データにおいては、正解率だけを評価指標にするとモデルの真の性能を見誤ってしまいます。少数派クラスをいかに正確に捉えるか(不正を見逃さない、病気を見逃さないなど)が重要になるケースでは、不均衡データへの適切な対処が不可欠です。
不均衡データへの基本的な対処法:リサンプリング
不均衡データに対処するための基本的な手法の一つに「リサンプリング (Resampling)」があります。これは、データセットにおけるクラスのバランスを意図的に変更することで、不均衡を緩和する手法です。
リサンプリングには主に二つのアプローチがあります。
- アンダーサンプリング (Undersampling): 多数派クラスのサンプル数を減らす
- オーバーサンプリング (Oversampling): 少数派クラスのサンプル数を増やす
それぞれの方法について、具体的な例とコードを見ていきましょう。ここでは、不均衡データに対応するためのライブラリである imblearn
(imbalanced-learn) を使用します。imblearn
は、pip install imbalanced-learn
コマンドでインストールできます。
まず、簡単な不均衡データを作成します。
import pandas as pd
from sklearn.datasets import make_classification
# サンプルとして、不均衡なデータセットを作成します
# 1000サンプル中、クラス0が950個、クラス1が50個
X, y = make_classification(
n_samples=1000, # サンプル総数
n_features=2, # 特徴量の数
n_informative=2, # 予測に役立つ特徴量の数
n_redundant=0, # 他の特徴量から導出できる特徴量の数
n_repeated=0, # 重複する特徴量の数
n_classes=2, # クラスの数
n_clusters_per_class=1, # クラスごとのクラスター数
weights=[0.95, 0.05], # クラスの比率 (95%と5%)
flip_y=0, # ラベル付けの間違いをなくす
random_state=42 # 再現性のための乱数シード
)
# pandas DataFrameに変換して確認しやすくします
df = pd.DataFrame(X, columns=['feature1', 'feature2'])
df['target'] = y
print("元のデータセットのクラス分布:")
print(df['target'].value_counts())
元のデータセットのクラス分布:
target
0 950
1 50
Name: count, dtype: int64
出力から、クラス0が950個、クラス1が50個と、クラス間に大きな偏りがあることが確認できます。これが不均衡データです。
1. アンダーサンプリング (Undersampling)
アンダーサンプリングは、多数派クラスからランダムにサンプルを削除し、少数派クラスのサンプル数に合わせる方法です。例えば、上記の例でクラス1が50個なら、クラス0もランダムに50個だけ残し、残りの900個は削除します。
メリット: * データセットのサイズが小さくなるため、モデル学習の計算コストを削減できます。
デメリット: * 多数派クラスの多くのサンプルを捨てるため、重要な情報まで失ってしまう可能性があります。
imblearn.under_sampling.RandomUnderSampler
を使用したコード例です。
from imblearn.under_sampling import RandomUnderSampler
# RandomUnderSamplerを初期化
# sampling_strategy='auto' は、少数派クラスの数に多数派クラスの数を合わせることを意味します
rus = RandomUnderSampler(sampling_strategy='auto', random_state=42)
# アンダーサンプリングを実行
X_resampled_rus, y_resampled_rus = rus.fit_resample(X, y)
# アンダーサンプリング後のクラス分布を確認
df_resampled_rus = pd.DataFrame(X_resampled_rus, columns=['feature1', 'feature2'])
df_resampled_rus['target'] = y_resampled_rus
print("\nアンダーサンプリング後のクラス分布:")
print(df_resampled_rus['target'].value_counts())
アンダーサンプリング後のクラス分布:
target
0 50
1 50
Name: count, dtype: int64
多数派クラス(クラス0)のサンプル数が、少数派クラス(クラス1)と同じ50個に減り、クラスバランスが整ったことがわかります。
2. オーバーサンプリング (Oversampling)
オーバーサンプリングは、少数派クラスのサンプルを複製したり、新しいサンプルを合成したりして、多数派クラスのサンプル数に近づける方法です。
2.1. ランダムオーバーサンプリング (Random Oversampling)
少数派クラスのサンプルを単純に複製して増やします。
メリット: * 実装が非常に簡単です。 * 多数派クラスの情報を失いません。
デメリット: * 同じサンプルを複数回複製するため、モデルが特定のサンプルに過剰に適合する(過学習)リスクが高まります。
imblearn.over_sampling.RandomOverSampler
を使用したコード例です。
from imblearn.over_sampling import RandomOverSampler
# RandomOverSamplerを初期化
# sampling_strategy='auto' は、多数派クラスの数に少数派クラスの数を合わせることを意味します
ros = RandomOverSampler(sampling_strategy='auto', random_state=42)
# オーバーサンプリングを実行
X_resampled_ros, y_resampled_ros = ros.fit_resample(X, y)
# オーバーサンプリング後のクラス分布を確認
df_resampled_ros = pd.DataFrame(X_resampled_ros, columns=['feature1', 'feature2'])
df_resampled_ros['target'] = y_resampled_ros
print("\nランダムオーバーサンプリング後のクラス分布:")
print(df_resampled_ros['target'].value_counts())
ランダムオーバーサンプリング後のクラス分布:
target
0 950
1 950
Name: count, dtype: int64
少数派クラス(クラス1)のサンプル数が、多数派クラス(クラス0)と同じ950個に増え、クラスバランスが整ったことがわかります。
2.2. SMOTE (Synthetic Minority Over-sampling Technique)
SMOTEは、ランダムオーバーサンプリングの欠点である「同じサンプルを複製する」ことによる過学習を防ぐために考案された手法です。少数派クラスの既存サンプルの近傍に、特徴空間上で線形補間を行うことで、人工的な新しいサンプルを合成して生成します。
メリット: * ランダムオーバーサンプリングよりも過学習のリスクを抑えられます。 * 多数派クラスの情報を失いません。
デメリット: * ノイズが多いデータセットでは、不適切な場所に人工サンプルを生成してしまう可能性があります。
imblearn.over_sampling.SMOTE
を使用したコード例です。
from imblearn.over_sampling import SMOTE
# SMOTEを初期化
# sampling_strategy='auto' は、多数派クラスの数に少数派クラスの数を合わせることを意味します
smote = SMOTE(sampling_strategy='auto', random_state=42)
# SMOTEを実行
X_resampled_smote, y_resampled_smote = smote.fit_resample(X, y)
# SMOTE後のクラス分布を確認
df_resampled_smote = pd.DataFrame(X_resampled_smote, columns=['feature1', 'feature2'])
df_resampled_smote['target'] = y_resampled_smote
print("\nSMOTEによるオーバーサンプリング後のクラス分布:")
print(df_resampled_smote['target'].value_counts())
SMOTEによるオーバーサンプリング後のクラス分布:
target
0 950
1 950
Name: count, dtype: int64
SMOTEでも、少数派クラスのサンプル数が多数派クラスと同じになり、クラスバランスが整ったことがわかります。Random Oversamplingとは異なり、これは既存サンプルの複製ではなく、合成によって実現されています。
どのリサンプリング手法を選ぶべきか?
ご紹介したリサンプリング手法は、それぞれにメリットとデメリットがあります。
- アンダーサンプリング: データ量を減らしたい場合や、計算リソースが限られている場合に有効ですが、情報損失のリスクがあります。
- オーバーサンプリング (Random/SMOTE): 情報損失のリスクはありませんが、データ量が増加し、過学習のリスクが伴います(特にRandom Oversampling)。SMOTEは過学習リスクを軽減しますが、データの特性によっては効果が出にくい場合もあります。
どの手法が最適かは、扱うデータセットや解決したい問題によって異なります。まずはこれらの基本的な手法を試してみて、モデルの性能(特に少数派クラスの予測精度に関する評価指標)を比較検討することが重要です。また、これらの手法を組み合わせたり、より高度なリサンプリング手法を検討したりすることも可能です。
まとめ
この記事では、機械学習における「不均衡データ」がどのような問題を引き起こす可能性があるのか、特に分類問題における正解率の落とし穴に触れながら解説しました。
そして、その基本的な対処法として、データセットのクラスバランスを調整する「リサンプリング」手法を紹介しました。具体的には、多数派クラスを減らすアンダーサンプリング(RandomUnderSampler)と、少数派クラスを増やすオーバーサンプリング(RandomOverSampler, SMOTE)について、それぞれの特徴と imblearn
ライブラリを使った簡単なコード例を示しました。
不均衡データへの対処は、機械学習モデルを実際にビジネスで活用する上で避けては通れない重要なステップです。今回学んだリサンプリングは、そのための強力なツールのひとつです。
ただし、不均衡データへの対処はリサンプリングだけではありません。モデルの評価方法を正解率からPrecision, Recall, F1-scoreなどに変更する、コストセンシティブ学習を行う、といったアプローチもあります。データ前処理の旅は続きますが、まずはこのリサンプリングを理解することが、不均衡データに立ち向かうための第一歩となるでしょう。