中野智文

中野智文(VOYAGE GROUP)のコンピュータなどのメモ

rubyで重み付きルーレット選択(乱択)のワンライナー

2015-01-06 13:36:39 | ruby

背景

rubyで重み付きルーレット選択をする時のワンライナー。

rubyでルーレット

rubyにprefix sumまたはscan(mapとreduceが合わさったような関数)が用意されていればいいが、ないので、sumの部分は外出しで、次のように書いた。
ruby -e 'r=rand;s=0;p [0.1,0.3,0.6].map.with_index{|a,i|[s+=a,i]}.select{|s,i|s>r}.first[1]'
出力結果:
2
出力結果は0-origin。 [0.1,0.3,0.6]の部分が重み付き配列として扱う。合計が1になるように正規化するか、合計値をrandにかけて扱う。

検証コード

ruby -e 'h=Hash.new(0);100000.times{r=rand;s=0;h[( [0.1,0.3,0.6].map.with_index{|a,i|[s+=a,i]}.select{|s,i|s>r}.first[1] )]+=1}; p h'
出力結果:
{2=>60055, 1=>30121, 0=>9824}

関数版

面倒なので、検証コードと共に。(重みの正規化付き)
ruby -e 'def roulette(list) r=rand*list.reduce(:+);s=0;list.map.with_index{|a,i|[s+=a,i]}.select{|s,i|s>r}.first[1] end; h=Hash.new(0); 100000.times{h[roulette([10,30,60])]+=1}; p h'
出力結果:
{2=>59775, 0=>9865, 1=>30360}

まとめ

prefix scanがあればもっと綺麗に書けそう。

最新の画像もっと見る

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。