やりたいこと
現在forループで実装している部分を、numpyのメソッドを使うなどして高速化したいと考えております。
(初めにお伝えしますが、本文中に何度かLightGBMに関する話題が登場しますが、実装したいこと自体にはLightGBMは関係なく本ページ下部の「やったこと」章にあるコードのforループを高速化したいだけです。LightGBMに詳しくない方もブラウザバックせずにご一読いただければ嬉しいです。)
具体的には、LightGBMのrambdarankでグループ内での予測順1位かつ正解順1位のaccuracyを求めるカスタムメトリックを作成したいです。
しかし、自分で作成したメトリックはfor文を使っているため学習が非常に遅くなってしまいます。
例えば、以下のようにpreds
とlabel
とgroup
を与えられます。
group
はpreds
とlabel
の要素が何個づつグループに所属しているかを示しています。preds
はLightGBMから渡される予測値です。大きいほうがより高い予測順位となります。label
は学習に使用する正解順位のラベルです。0,1,2のいずれかの値を持ち、最大値の2は各グループで必ず1回だけ登場します。大きいほうがより高い正解順位となります。
preds = [-0.112,0.025,0.998,1.112,1.226,0.520,2.112,-0.220,2.174,1.552] label = [0,0,1,2,0,2,1,0,2,1] group = [4,3,3]
グループ内で一番大きなpreds
を持っている要素のlabel
が2であれば正しく予測できている、それ以外だと正しく予測できていないことになります。
文字で説明しても分かりづらいと思いますので表で表現してみます。
- index列は
input
とlabel
のインデックスです。 - preds列は
preds
の値です。 - label列は
label
の値です。 - 「----」となっている行で
group
に基づくグループ分けを行い、preds
とlabel
の要素を区切ります。
この場合ですと、indexが03、46、7~9の3グループに分けられ、それぞれのグループの中で最大のpreds
を持つ行のlabel
が2であれば、そのグループは正しく予測できている(TorF = true)、それ以外だと正しく予測できていない(TorF = false)となります。
3グループのうち正しく予測しているのは2グループなので、求めたい値(accuracy)は2/3=0.67となります。
|index|preds|label|T or F|
|:--|:--|||
|0|-0.112|0||
|1|0.025|0||
|2|0.998|1||
3 | 1.112 | 2 | true |
---|---|---|---|
4 | 1.226 | 0 | |
5 | 0.520 | 2 | |
6 | 2.112 | 1 | false |
---- | ---- | ---- | ---- |
7 | -0.220 | 0 | |
8 | 2.174 | 2 | true |
9 | 1.552 | 1 |
やったこと
次のようなコードで実装しました。
Python3
1def accuracy(preds, data): 2 BEST_LABEL = 2 3 label = data.get_label() 4 group = data.get_group() 5 6 i = 0 7 acc = 0 8 for n in group: 9 max = preds[i:i+n].argmax() 10 acc += (label[i+max] == BEST_LABEL) 11 i += n 12 acc = acc/len(group) 13 return "accuracy", acc, True
しかしこのコードだとforで回しており学習が非常に遅くなってしまうので、numpyのメソッドを使用するなどで高速化を図りたいです。
自分では良い実装が思いつかなかったため、皆様のお力をお借りしたいと考えました。よろしくおねがいします。
環境
Windows10
Python 3.10.0
回答3件
あなたの回答
tips
プレビュー