UnderSamplingで抽出したデータ以外の(使用しなかったindexの)データを取得

2019-10-04 公開

機械学習を行う際、正例(y = 1)と負例(y = 0)との割合が極端に偏っているケースがある。

割合が偏っていると、データの多い方を優先して予測してしまうことが多く、予測結果がすべてy = 0なんてことも。悲惨である。

そういう場合

  • 多すぎるラベルのデータから一部を抽出して割合を近くする(Under Sampling)
  • 少ないラベルのデータをかさましして割合を近くする(Over Sampling)
  • 正例・負例の学習時に重み付けを行う

といった対策が考えられる*1

Pythonであればimblearnというライブラリを使用すると、手軽にUnder SamplingやOver Samplingができて便利。


[参考]

tekenuko.hatenablog.com

ohke.hateblo.jp


とても便利なimblearnだが、Under Samplingを行う際の

  • 抽出したデータだけでなく、抽出されなかったデータも使用したい
  • 元のデータとの繋がり(インデックス)を失いたくない(pandasのデータフレームをnampyのndarrayに変換したくない)

といったささやかな願いを叶えるのが少しだけ面倒。

そこで、これらの願いを叶える方法を以下にメモする。

なお、以下のコード例の主目的は「UnderSamplingで抽出しなかったデータを取得」することだが、副産物として「元のindexを保持したままでの抽出」が可能になっている*2

コード例

from imblearn.under_sampling import RandomUnderSampler

# RandomUnderSampler
resampler = RandomUnderSampler(sampling_strategy=1/1, random_state=64)
_, _ = resampler.fit_sample(X, y)  # Under Samplingを適用, .fit_sampleの返り値の型がnp.ndarrayなので捨てる

# Under Samplingされたインデックスを取得
# Xのうち、どのデータが抽出されたかが分かる
# インデックスそのものではなく、Xの何番目のデータが抽出されたかが記録されている点に注意
re_indices = resampler.sample_indices_

# こちらではUnder Sampling前のデータとre_indicesを使用して、
# Under Samplingされたデータのインデックスそのものを取得している
re_idx = y.index[re_indices]  # 元のデータとインデックスで結合するためのkeyになる)

# Under Samplingされたデータを抽出
X_resampled = X.loc[re_idx]  # re_idxが順番ではなくインデックスそのものなので、.ilocではなく.loc
y_resampled = y.loc[re_idx]

# Under Samplingされなかったデータのインデックスそのものを抽出
# Under Sampling前のデータのインデックスのre_indices番目のインデックスを削除
not_re_idx = y.index.delete(re_indices)  # 元のデータとインデックスで結合するためのkeyになる)

# Under Samplingされなかったデータを抽出
X_not_resampled = X.loc[not_re_idx]  # not_re_idxが順番ではなくインデックスそのものなので、.ilocではなく.loc
y_not_resampled = y.loc[not_re_idx]

案外お役に立つかもしれない。


[参考書籍]

pandasのインデックスでindexからlistを除外したindexを取得するためのメソッド.delete()を見つけるのが結構大変だった。

「どんなクエリで検索すればよいのやら…。」と困っていたところ、以下の本をパラッとめくれば速攻で見つかった。

手元にあって良かった。なんだかんだ、いつも助かっている。ありがとうございます。

Pythonによるデータ分析入門 第2版 ―NumPy、pandasを使ったデータ処理

Pythonによるデータ分析入門 第2版 ―NumPy、pandasを使ったデータ処理

  • 作者: Wes McKinney,瀬戸山雅人,小林儀匡,滝口開資
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2018/07/26
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る


[関連ツイート]

*1:Over Samplingは良い結果を生まない印象(SMOTEだけ?)。SMOTEを使用すると、valid段階ではそこそこ良い精度。しかし、元のデータから前もって分離しておいたデータ(元の比率を維持したデータ)を対象とした予測では、割合の大きい方のラベルばかり予測するという散々な結果に。原因はダミー変数か?(こここ🍀 on Twitter: "Over Samplingしたときに過学習になっている問題、ダミー変数が原因かもしれない。 →")ちなみに、Twitterでも2019-09の下旬頃「Over Samplingは微妙」という話で少し盛り上がりが見られた。

*2:pandasのDataFrame, Seriesを使用している場合