雑記 in hibernation

頭の整理と備忘録

ビニングにも色々あるらしい

機械学習でビニングって手法があるじゃないですか。あるんですよ。

最近SASの公式ドキュメントを眺めていて知ったのですが、どうも一口に "ビニング" といっても色々な分割方法があるみたいです。あまり馴染みのない情報だったので、ざっくりまとめてみました。

まとめつつ気づいたのですが、ビニング自体は意識せずとも特徴量エンジニアリングとして割と普通にやってることだったりしますし、まあ目新しいことはあんまりないと思います。あえて整理するならこんな感じ、みたいなノリです。

この記事は個人的な備忘録として作成しています。

 

 

1. そもそもビニングとは

特徴量エンジニアリングの手法の一つです。連続値の特徴量を離散化してカテゴリ変数に変換する手法です。主に線形モデルに対して、表現力を高める効果が期待できます。

処理の手順はだいたい以下のような流れです。

  1. 一つの特徴量(連続値)について、これを何らかのルールに則って分割する
  2. 分割した各領域(ビン)にカテゴリ変数をふる
  3. 各ビン内のサンプルの特徴量の値を、そのビンのカテゴリ変数で置き換える
  4. カテゴリ変数の値を使って学習なり何なりする

下の図は適当に生成したサンプルに対して線形モデルをフィッティングした例です。縦線で区切られた間隔がビンを表しています。ビニングを行うことで、線形モデルであっても直線的・単調増加でない特徴を捉えることができるようになります。特徴量にひと工夫加えるだけで表現力が大きく向上することがわかります。

f:id:toeming:20200427172429j:plain 

ちなみに、ビニングでは領域内のサンプルは同じカテゴリ変数を持っていることになります。ビンの中ではモデルの出力値は一定、つまり傾きを持ちません。交互作用と併用することで傾きを与えることもできますが、この記事ではそこまで深追いしません。

なお上図は『Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎』第4章のビニングの説明部分をベースに、Pythonでコードを書き起こして出力してます。この章ではビニング・交互作用・2次以上の多項式への拡張などを使って線形モデルの表現力を高める手法について議論されています。興味ある方はご参照ください。 

f:id:toeming:20200418023237j:plain

 

2. 等分割だけがビニングじゃない

SASの公式ページを眺めていたところ、ビンの分割方法は等分割する以外にもバリエーションがあるらしいことを知りました。こういった情報が体系的にまとまっている情報はあまり見たことがなかったので、せっかくなのでSAS公式を参考にビニングの種別について簡単にまとめてみます。

なお、本記事はとりあえずざっくりの概要説明なので、交差検証や精度の確認までは行いません。検証時にbinの領域外のデータがあったらどうすんの?みたいな話も本記事では特に考慮していないです。加えて、英語の情報を自力(と今話題のDeepLさんのお力添え)で解読・解釈しているので若干不正確な部分があるやもしれません。ご容赦ください。大意は掴めているはずです。

 

2.1. バケットビニング

SAS公式の紹介はこちら

これが最も一般的な方法ではないでしょうか。処理対象の特徴量について、サンプルの最大値から最小値までの範囲を等分割し、これをビンとします。分割数がパラメータになります。

実際やってみるとこんな感じです。

f:id:toeming:20200427172454j:plain
各ビンの領域が同じ幅になっていることがわかります。シンプルな挙動でわかりやすいですね。

 

2.2. 分位ビニング

SAS公式の紹介はこちら

特徴量の分位数を境界として分割する方法です。これも分割数がパラメータになります。例えば100サンプルを元に特徴量を10分割する場合であれば、特徴量の値でサンプルをソートした後、上から10番目,20番目,30番目 ... のサンプルの特徴量の値をビニングの境界値として採用するようなイメージです。この場合、境界値は10分位数となることがわかると思います。

実際やってみるとこんな感じです。

f:id:toeming:20200427172512j:plain

 分割幅は不均一ですが、一方で分割領域あたりのサンプルサイズが等しいことが確認できます。これは、分位ビニングが各領域あたりのサンプルサイズにむらが起きないように留意された手法であることに起因しますが、同じ特徴量の値を持つサンプルが複数あった場合はサンプルサイズに偏りが生じることもあります。

特徴量空間でサンプルの分布に疎密がある場合、単純な特徴量値の等分割によるビニングでは疎な領域が無駄に分割され、変換後のカテゴリ変数の水準数が無駄に増える可能性があります。これは特徴量表現としては非効率です。分位ビニングであれば、密な領域にビンが増える一方で疎な領域では無駄に領域が分割されることを防ぐことができます。

 

2.3. ツリーベースドビニング

SAS公式の紹介はこちら

目的変数も考慮し、分割の境界値を決定木アルゴリズムで探索する方法です。分割には目的変数を必要とします。決定木アルゴリズムの学習相当のパラメータが必要になります(木の深さや不純度の計算方法など)。目的変数も考慮して機械的に分割を決めることができます。一方で考慮すべきパラメータが増えるという意味では、やや扱いづらいかもしれません。 

 

2.4. 手動

SAS公式の紹介はこちら。"Cutpoint Binning" と紹介されていますね。

ビンの境界値を任意の値に設定する方法です。とりあえず適当に境界値を設定して出力してみたのが下の図です。

f:id:toeming:20200427172538j:plain
 ルールベースで機械的に分割するよりもドメイン知識を活かしてヒューリスティックに領域を決めたい時に有効かもしれません。

 

3.おまけ

3.1. ウィンザライズドビニング

SASでは外れ値処理とバケットビニングを一つのプロシージャでサポートしていて、その機能の一つが「ウィンザライズドビニング」と名付けられています。ビニングとしての処理はバケットビニングと変わらないようだったので、2章ではなくこの「おまけ」の章で扱うことにしました。

SAS公式の紹介はこちら

まず「ウィンザライズド」ってなに?というところから説明します。集団の平均値をとる際、ある特徴量でソートした時の上位数%・下位数パーセントのサンプルを取り除くことで外れ値を除去し、その上で平均値を計算する手法があります。上位・下位のサンプルを完全に除去する場合はトリム平均と呼ばれています。上位・下位のサンプルの値を、上位・下位の集団に入っていないサンプル群の最大値・最小値で代用した場合はウィンザライズド平均と呼ばれています。

ウィンザライズドビニングでは、バケットビニングを行う前に、ウィンザライズド平均を計算する際と同様の外れ値処理を行います。

実際やってみるとこんな感じです。全サンプルのうちの上下5%に対して外れ値処理したサンプルを描画しています。

 

f:id:toeming:20200427172550j:plain

3.2. ソースコード

今回の結果出力に使用したソースコードこちらに置きました。Pythonで書いてます。

ツリーベースドビニング以外は一通り実装してます。ライブラリなど使って怠けようと思ったのですが、実装されているパッケージがなさそうだったので手実装する羽目になりました。

 

4. まとめ

ビニングのバリエーションについて簡単にまとめてみました。「等分割だけやないんやで」ってところは伝わったかと思います。

目的変数やドメイン知識を利用すれば、本記事で紹介した方法以外にも色々な分割方法が考えられそうです。ビニングと意識していないだけで、特徴量エンジニアリングの一環として似たようなことを行っていることも多いと思います。ビニングを活用して線形モデルに無限の可能性を与えてあげましょう。めんどいから最初っから非線形のモデル使おうとか、そんな悲しいことは言わないであげてください。