1. はじめに
1-1. 記事の内容
過去に取り組んだ仕事やKaggleコンペ等の経験を踏まえ、不均衡データを取り扱う分類モデルを作る際に役に立つ(かもしれない)、TIPSをいくつかまとめてみました。
簡単なメモ程度の内容ですが、機械学習のビギナーの方々が、不均衡データに向き合う際の、参考となれば幸いです。内容は、(厳密さは捨てて)できる限り、雰囲気を感じ取れるよう、噛み砕いた言葉で書くように努めています。この記事をざっと眺めて、雰囲気を掴んでから、詳しい資料を読み進めてもらうと、不均衡データの取り扱いについて、より効率的に、理解を深めていけるかと思います。データサイエンスや機械学習に係る、多くの資料は英語なので、その参考にしてもらえるよう、ところどころに、カッコ書きで、英語の用語を入れるようにしています。
1-2. 記事の見方
2章に、「不均衡データとは」、3章に、「不均衡データを取り扱う分類モデルを作る際に役に立つ(かもしれない)10TIPS」をまとめています。すでに不均衡データに馴染みのある方や急ぎの方は、2章をすっ飛ばして、3章から眺めてもらっても、問題はありません。
1-3. とりあえずはTIPSを試してみよう!!
どんな対処の方法があるのか、それぞれどのような対処なのか、ざっくり理解できてきたら、とりあえず、片っ端から試してみましょう。お持ちのデータ/問題で、どのTIPSが有効に働くのかは、(仮に、あなたが機械学習のエキスパートだとしても、)試してみないと分かりません。ここで、紹介しているTIPSは、いずれも
- LightGBMやPyCaret等の機械学習のライブラリで、オプションを指定するだけ、
- imbalanced-learnなど、不均衡データを簡単に取扱うためのライブラリで、数行のコードを追加するだけ、
など、簡単な方法で試すことができるものばかりです。ぜひ、お手持ちのデータ/問題で、試してみて下さい。
2. 不均衡データとは
2-1. 不均衡データ?なんぞ??
不均衡データ(Imbalanced/unbalanced dataset)は、ラベル毎のサンプルの数に偏りがあるデータです。サンプルの数が多いクラスを大多数クラス(Majority Class)、サンプルの数が少ないクラスを少数クラス(Minority Class)と呼んでいます。
2-2. どんなデータがあるの?
一般に、異常検知(Anomaly detection)に使われるようなデータが、偏りの大きい、不均衡データとなっていることが多いです。例えば、
- 正常/異常なメール(スパムメール)のデータ
- クレジットカードの正常/不正な取引のデータ
- 機械設備の正常/異常時のセンサーデータ(センサーで取得した温度、振動、音など)
などは、全体のデータの数に比べて、検知の対象となるデータ(ここで言うと、スパムメールのデータ/不正な取引のデータ/故障の予兆を示すデータ)の数が著しく少ないことがあります。
2-3. 何か問題あんの?
分類モデルを作る際に、特定のクラスだけサンプルの数が少ないと、そのクラスのサンプルの特徴をうまく学習できないことがあります。そのような場合、思った通りの性能の分類モデルが作れなくなります。場合によっては、全てのデータを、サンプルの数が多いクラス(Majority)のデータと判断してしまって、一切、サンプルが数が少ないクラス(Minority)のデータを見つけられない、(つまり、何もしない、ダメな)分類モデルになってしまうこともあります。機械学習の世界では、「不均衡データの呪い (Curse of imbalanced training Sets)」などと、言われることもあります。
一般には、大多数クラス(Majority Class)のサンプルの数に対し、少数クラス(Minority Class)のサンプルが少ないほど、性能の高い分類モデルを作ることが難しくなります。
不均衡の度合い | 少数クラスのサンプルの数の比率 | 良い分類モデルを作る難易度 |
---|---|---|
弱い (Mild) | 全てのサンプルの20-40% | 低 |
中間 (Moderate) | 全てのサンプルの1-20% | 中 |
強い (Extreme) | 全てのサンプルの1%未満 | 高 |
(引用元 : Google Machine Learning Foundational courses)
3. 不均衡データを取り扱う分類モデルを作る際に役に立つ10TIPS
不均衡データを取り扱う分類モデルを作る際に役に立つ(かもしれない)、10個のTIPSについてまとめています。
- 01 | 適切な性能評価の指標を使う
- 02 | サンプル数が少ないクラスのサンプルの重みを変える
- 03 | サンプル数が少ないクラスの一部のサンプルの重みを変える
- 04 | サンプル数が少ないクラスのサンプルを増やす
- 05 | サンプル数が多いクラスのサンプルを減らす
- 06 | サンプル数が少ないクラスのサンプルを増やし、サンプル数が多いクラスのサンプルを減らす
- 07 | 複数の分類モデルを組み合わせる
- 08 | 異常検知 他の分野で使われている技術を組み合わせる
- 09 | サンプル数が多いクラスのサンプルを減らし、その重みを増やす
- 10 | Balanced splitを使ってデータセットを分割する
01 | 適切な性能評価の指標を使う
Recall
、Precision
、F1
スコアなど、サンプルの数が少ないクラス(Minority)のサンプルの分類の予測の成否に敏感な性能評価の指標(Evaluation metrics)を使うようにしましょう。使用する機械学習のライブラリによっては、デフォルトの性能評価の指標がAccuracy
になっていることがあります。忘れず変更するようにしましょう。
lightgbm.LGBMClassifierを使って、分類(Classification)モデルを作る場合は、パラメータmetric="metric_you_like"
を指定すると、性能評価に用いる指標を設定することができます。
02 | サンプル数が少ないクラスのサンプルの重みを変える
サンプルの数が少ないクラス(Minority)のサンプルの重み(Sample weight)を大きくして、重点的に、学習を進められるようにしましょう。XGBoostやLightGBMなどの機械学習用のライブラリでは、オプションでサンプルの重みを設定することができるようになっています。不均衡データを取り扱えるモードが用意されており、サンプルの重みを指定しなくても、自動的に適切な値に設定されるライブラリもあります。
lightgbm.LGBMClassifierを使って、多クラスの分類(Multi-class classification)モデルを作る場合は、パラメータclass_weight={class_label: weight}
を指定すると、クラス毎の、サンプルの重みを設定することができます。キーワードclass_weight="balanced"
を指定すると、不均衡データを取り扱うモードになり、自動的に、適切な重み(クラス毎のサンプル数の大小に応じた値)が設定されます。
lightgbm.LGBMClassifierを使って、2クラスの分類(Binary classification)モデルを作る場合は、scale_pos_weight=weight
を指定すると、サンプルの数が少ないクラス(Minority)のサンプルの重みを設定することができます。パラメータis_unbalance=True
を指定すると、不均衡データを取り扱うモードになります。両オプションを同時に使うことはできないので、注意が必要です。
03 | サンプル数が少ないクラスの一部のサンプルの重みを変える
サンプルの数が少ないクラス(Minority)のサンプルの中に、分類しやすい/しにくいサンプル(Easy/hard samples)があることが、分かっている場合には、個別のサンプルの重み(Sample weight)を調整して、効率的に、学習を進められるようにしましょう。XGBoostやLightGBMなどの機械学習用のライブラリでは、オプションで、サンプル毎の重みを設定することができるようになっています。
lightgbm.LGBMClassifierを使って、分類(Classification)モデルを作る場合は、
fitメソッドの引数sample_weight
で、サンプル毎の重みを設定することができます。
04 | サンプル数が少ないクラスのサンプルを増やす
サンプル数が少ないクラス(Minority)のサンプルを増やすことで、分類(Classification)モデルの予測の性能が上がることがあります。Imbalanced-learnなど、不均衡データの取り扱いに特化したライブラリを使うと、数行のコードを追加するだけで、簡単にサンプルを増やすこと(Over-sampling)ができます。サンプルの増やし方には、様々なバリエーションがあり、取扱うデータ/問題に適したものを選べるようになっています。以下は、その一例です。
-
Naive random over-sampling
元のサンプルを繰り返し使うことで、あたかもサンプルが増えたかのように見せかける方法です。 -
SMOTE (Synthetic Minority Oversampling TEchnique)
元のサンプルを内挿して、似通ったサンプルを作り出す方法です。 -
ADASYN (ADAptive SYNthetic sampling method)
こちらも、元のサンプルを内挿して、似通ったサンプルを作り出す方法です。ただし、SMOTEとは異なり、分類しずらいサンプルを重点的に作ります。
どの方法を用いるかによって、出来上がるサンプルが変わってきます。下図には、それぞれの方法を使って、(サンプルの数が少ない)青と紫のクラスのサンプルを増やした例を示しています。Naive random over-sampling(右上)は、元のサンプルを繰り返し使うので、グラフの見た目は、サンプルを増やす前(左上)と変わりません。SMOTE(左下)やADASYN(右下)は、元のサンプルの周りに、新しいサンプルが作られていることが分かります。前者の場合は、比較的まばらにサンプルが作られていますが、後者の場合は、色の異なるサンプルが重なっているあたりに、多くサンプルが作られていることが分かります。
(Imbalanced-learnのユーザーガイドから引用)
Imblearnでは、BorderlineSMOTE、KMeansSMOTEなどなど、他にもいくつかのバリエーションが用意されています。分類の予測の性能が上がる可能性があるので、いろいろなやり方を試してみましょう。
その他、PyCaretなど、オプションを指定するだけで、サンプルを増やすことができる、機械学習ライブラリもあります。そういったライブラリを使うのもオススメです。
PyCaretを使って、分類(Classification)モデルを作る場合は、
setup関数のパラメータfix_imbalance=True
とfix_imbalance_method=estimator_you_like
を指定するだけで、SMOTE等を使って、サンプルを増やすことができます。
05 | サンプル数が多いクラスのサンプルを減らす
サンプル数が多いクラス(Majority)のサンプルを減らすことで、分類(Classification)モデルの予測の性能が上がることがあります。Imbalanced-learnなど、不均衡データの取り扱いに特化したライブラリを使うと、数行のコードを追加するだけで、簡単にサンプルを減らすこと(Under-sampling)ができます。サンプルの減らし方には、様々なバリエーションがあり、取扱うデータ/問題に適したものを選べるようになっています(テキトーにサンプルを減らしてしまうと、データの分布や特徴が変わってしまうことがあるので、そうならないような工夫がなされた様々な方法があります。)。以下は、その一例です。
-
Random under-sampling
元のサンプルから、一部のサンプルだけを、ランダムに選び出して使う方法です。 -
ClusterCentroids
(元のサンプルから選び出すのではなく、)少ないサンプルで、元のサンプルの分布を再現できるようなサンプルを、新たに作り出す方法です。
下図に、それぞれの方法を使って、サンプルを減らした例を示しています。Random under-sampling(右上)は、元のサンプル(左上)の一部が選ばれていることが分かります。ランダムに選ばれているので、サンプルがたくさん集まっているところやまばらなところがあります。それに対し、ClusterCentroids(右下)で作ったサンプルは、より均等に分布するようなサンプルとなっています。
(Imbalanced-learnのユーザーガイドから引用)
Imblearnでは、Tomek’s links、EditedNearestNeighboursなどなど、他にもいくつかのバリエーションが用意されています。分類の予測の性能が上がる可能性があるので、いろいろなやり方を試してみましょう。
PyCaretを使って、分類(Classification)モデルを作る場合は、
setup関数のパラメータfix_imbalance=True
とfix_imbalance_method=estimator_you_like
を指定するだけで、Random under-sampling等を使って、サンプルを減らすことができます。
06 | サンプル数が少ないクラスのサンプルを増やし、サンプル数が多いクラスのサンプルを減らす
上で紹介した2つのTIPS(サンプル数が少ないクラスのサンプルを増やす/サンプル数が多いクラスのサンプルを減らす)を組み合わせることで、分類(Classification)モデルの予測の性能が上がることがあります。Imbalanced-learnなど、不均衡データの取り扱いに特化したライブラリを使うと、数行のコードを追加するだけで、簡単に、サンプルを増やしたり(Over-sampling)、減らしたりすること(Under-sampling)ができます。サンプルの増やし方や減らし方には、様々なバリエーションがあり、取扱うデータ/問題に適したものを選べるようになっています。以下は、その一例です。
-
SMOTEENN
SMOTEでサンプルを増やした後、Edited nearest-neighboursでサンプルを減らす方法です。SMOTEでサンプルを増やすと、学習の邪魔になるようなサンプル(Noisy sample)が出来てしまうことがあります。そういったサンプルを除くため、一旦サンプルを増やした後に、減らす処理(Cleaning)を行っています。 -
SMOTETomek
SMOTEでサンプルを増やした後、Tomek’s linkでサンプルを減らす方法です。SMOTEでサンプルを増やすと、学習の邪魔になるようなサンプル(Noisy sample)が出来てしまうことがあります。そういったサンプルを除くため、一旦サンプルを増やした後に、減らす処理(Cleaning)を行っています。
(Imbalanced-learnのユーザーガイドから引用)
PyCaretを使って、分類(Classification)モデルを作る場合は、
setup関数のパラメータfix_imbalance=True
とfix_imbalance_method=estimator_you_like
を指定するだけで、SMOTEENN等を適用することができます。
07 | 複数の分類モデルを組み合わせる
特性の異なる複数の分類モデルを組み合わせること(Ensemble)で、分類(Classification)モデルの予測の性能が上がることがあります。Kaggleコンペなどで、よく使われるテクニックですが、不均衡データを取扱う分類モデルを作る際にも使えます。異なるアルゴリズムで作ったモデルを組み合わせる、異なるデータを学習させたモデルを組み合わせる、などなど様々なバリエーションが考えられますので、いろいろ試してみると良いです。VotingやBoostingなど、分類モデルの組み合わせのやり方にも、様々なバリエーションがあります。こちらも併せて試してみましょう。
08 | 異常検知 他で使われている技術を組み合わせる
異常検知(Anomaly detection)やグループ分け(Clustering)で使われている技術を、分類モデルの学習に用いることで、分類(Classification)モデルの予測の性能が上がることがあります。Improving Imbalanced Classification by Anomaly Detectionでは、サンプルの外れ値の度合い(Outlier score)やクラスの境界付近にあるサンプルなのか、離れたところにあるサンプルなのか、などなど異常検知を行う際に用いられているパラメータを、特徴量(feature/attribute)に加えることで、分類(Classification)モデルの予測の性能が上がった旨が報告されています。これに関しては、(私の知る限り、)他のTIPSと異なり、簡単に実装できるようなライブラリはありませんが、自身で簡単に実装できるかと思いますので、一度試してみて下さい。
09 | サンプル数が多いクラスのサンプルを減らし、その重みを増やす
サンプル数が多いクラス(Majority class)のサンプルを減らし(Downsampling)、さらに、その重みを増やすこと(Upweighting)で、分類(Classification)モデルの予測の性能が上がることがあります。この方法は、Google Machine Learning Foundational coursesで紹介されている方法です。
これに関しても、(私の知る限り、)簡単に実装できるようなライブラリはありませんが、以下の手順で、簡単に実装できるかと思います。一度試してみて下さい。
(引用元 : Google Machine Learning Foundational courses)
⭐️ Step 1 : サンプル数が多いクラスのサンプルを減らす (Downsampling)
サンプル数が多いクラス(Majority class)のサンプルの中から、ランダムにサンプルを選び出します。Google様のサイトで紹介されている手順では、ランダムに選び出すようにしていますが、上記で紹介しているImbalanced-learnの、ClusterCentroidsなどを使って、サンプルを減らすのも良いかと思います。
⭐️ Step 2 : 選び出したサンプルの重みを増やす (Upweighting)
選び出したサンプルの重み(Weight)を増やします。クラス毎のサンプルの重みは、上記で紹介しているlightgbm.LGBMClassifierの、パラメータclass_weight={class_label: weight}
を指定することで、調整することができます。他のライブラリでも、何らかの方法で、同じように、調整することができます。
10 | Balanced splitを使ってデータセットを分割する
学習/テストに用いるデータセットの分割の仕方を工夫することで、分類(Classification)モデルの予測の性能が上がることがあります。一般には、ランダムに分割したり(例えば、Sklearnのkfold など)、階層化して分割したり(例えば、Sklearnのstratified-kfold など)、することが多いですが、サンプル数が少ないクラスのサンプルの数を踏まえて、データセットを分割すること(Balanced split)で、分類(Classification)モデルの予測の性能が上がる旨が報告されています。
これに関しても、(私の知る限り、)簡単に実装できるようなライブラリはありませんが、以下の手順で、簡単に実装できるかと思います。一度試してみて下さい。
(引用元 : Balanced Split: A new train-test data splitting strategy for imbalanced datasets)
⭐️ Step 1 : 学習に用いるサンプル数を求める
最初に、学習に用いるサンプル数を求めます。学習に用いるサンプルの数m * tr
は、全てのサンプルの数m
に、学習に用いるサンプルの割合tr
(Training ratio) を掛け合わせることで求めることができます。クラス毎のサンプルの数のバランスを取るため、tr
には、N * min(m(A), m(B), ..., m(N)) / m
(Nはクラスの数。m(A)
は、クラスAのサンプルの数。)を上限とした、いずれかの値を設定します(サンプルの数が最も少ないクラスのサンプルの数に基づいて、tr
の上限を決めます。)。
⭐️ Step 2 : クラス毎のサンプルの数を求める
クラス毎のサンプルの数を求めます。クラス毎のサンプルの数m * tr / N
は、Step 1で求めたサンプルの数m * tr
を、クラスの数N
で割ることで求めることができます。
⭐️ Step 3 : クラス毎にサンプルを選び出す
クラス毎に、ランダムにサンプルを選び出します。選び出すサンプルの数は、Step 2で求めたサンプル数m * tr / N
とします。選び出したサンプルを学習に用います。(tr
が上限より小さい値に設定されている場合は)残りのサンプルをテストに用います(tr
を上限の値に設定してしまうと、テストに用いるサンプルがなくなってしまうので、それよりも小さい値を設定することが推奨されています。)。
4. 参考資料
不均衡データの取扱いについて、より詳しく知りたい方は、以下の資料も確認してみましょう。
● DeepL Translate
ここで紹介する資料は、全て英語の資料です。もし、英語が苦手であれば、DeepL等を使って、日本語に翻訳してしまいましょう。
● imbalanced-learnのユーザーガイド
不均衡データを取り扱う分類モデルを作る際に使える、様々なツールをまとめたライブラリ、Imbalanced-learnのユーザーガイドです。様々な不均衡データの取り扱いの方法について、分かりやすくまとめられています。この記事の内容のほとんどは、これを参考にしています。
● imbalanced-learnの適用例
不均衡データを取り扱う分類モデルを作る際に使える、様々なツールをまとめたライブラリ、Imbalanced-learnを、実際のデータに適用した例です。サンプルコードや結果が、分かりやすくまとめられています。
● LightGBMのマニュアルとQ&A
LightGBMのマニュアルです。is_unbalance
やscale_pos_weight
など、不均衡データを取り扱う分類モデルを作る際に使える、パラメータについてまとめられています。ものによって、3つ以上のクラスの分類には使えない、組み合わせて使えない、など制限があったりするので、よく読んで理解しておくことをオススメします。LightGBMのQ&A 「[Question] how to deal with data imbalance #3702」に、不均衡データを取り扱う分類モデルを作る際に使えるオプションがまとめられています。
● Kaggleのノートブック 「XGBoost & LightGBM & Catboost - Imbalanced Data」
Kaggleで公開されているノートブック 「XGBoost & LightGBM & Catboost - Imbalanced Data」です。よく使われる、3つの決定木アルゴリズム(XGBoost/LightGBM/Catboost)を使って、 不均衡データを取り扱う分類モデルを作った例がまとめられています。サンプルコードだけでなく、オプションの値を変えて、予測の結果がどう変わるかを確認した結果もまとめられており、非常に、参考になります。Kaggleには、他にも、役に立つコードがたくさんあるはずなので、ご自身で探してみることをオススメします。
● PyCaretのマニュアル
ローコード機械学習ツールPyCaretのマニュアルです。同ツールにも、不均衡データを取扱う分類モデルを作る際に使える、便利な機能が実装されています。オプションを指定するだけで、簡単に、SMOTEを適用することができます。
● Improving Imbalanced Classification by Anomaly Detection
異常検知の分野で使われている技術を組み合わせることで、不均衡データを取扱う分類モデルの性能を向上できる可能性がある旨が紹介されている論文です。不均衡データを取扱う方法の概要や歴史なども記載されているので、読んでみると、すごく勉強になります。
● Google Machine Learning Foundational courses
Google Machine Learning Foundational courses のサイトです。不均衡データを取り扱う方法が紹介されています。不均衡データの取り扱い以外にも、機械学習に係る様々なトピックスがまとめられています。ざっと読んでみるだけでも、ものすごく勉強になります。
5. さいごに
不均衡データを取り扱う分類モデルを作る際に役に立つ(かもしれない)、8個のTIPSをまとめてみました。
- 01 | 適切な性能評価の指標を使う
- 02 | サンプル数が少ないクラスのサンプルの重みを変える
- 03 | サンプル数が少ないクラスの一部のサンプルの重みを変える
- 04 | サンプル数が少ないクラスのサンプルを増やす
- 05 | サンプル数が多いクラスのサンプルを減らす
- 06 | サンプル数が少ないクラスのサンプルを増やし、サンプル数が多いクラスのサンプルを減らす
- 07 | 複数の分類モデルを組み合わせる
- 08 | 異常検知の分野で使われている技術を組み合わせる
- 09 | サンプル数が多いクラスのサンプルを減らし、その重みを増やす
- 10 | Balanced splitを使ってデータセットを分割する
機械学習のビギナーの方々が、不均衡データを取り扱う分類モデルを作る際の一助となれば、幸いです。