Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a random number with a given discrete distribution in Ruby

I'm coding my university assignment that is somewhat connected with distributions and random roll stuff. So the question is: how to get a random number with a given discrete distribution in Ruby.

To be more specific: in trivial example with normal discrete distribution like (0 with P=1/2; 1000 with P=1/2) I could write such a function:

 def chooseNumber(a,b)
  rval = Random.rand(0..1)
  return a if rval == 0
  return b
 end 

First question: is there any way to write it using native Random class?

Second question: what is the best way to deal with distributions like (0 with P=1/5; 2 with P=2/5; 1000 with P=2/5) or even worse (0 with P=0,33; 2 with P=0,49; 1000 with P=0,18)?

like image 365
ddnomad Avatar asked Nov 04 '15 15:11

ddnomad


People also ask

How do you generate a random number in Ruby?

You can also generate random numbers with the Random class. The class method rand provides the base functionality of Kernel#rand along with better handling of floating point values. Unlike Kernel#rand , if Random. rand is given a negative or 0 argument, it raises an ArgumentError.

How do you generate a random number between ranges in ruby?

In Ruby, there are many ways to generate random numbers with various properties. The rand method can be used in 3 ways: Without arguments, rand gives you a floating point number between 0 & 1 (like 0.4836732493) With an integer argument ( rand(10) ) you get a new integer between 0 & that number.


1 Answers

I would go with something like this

def pick_with_distribution(distributions)
  r = rand
  distributions.detect{ |k, d| r -= d; r < 0 }.first
end

distributions = { 0 => 0.33, 2 => 0.49, 1000 => 0.18 }
pick_with_distribution(distributions)
#=> 0

To check if distribution is correct, I run it 10000 times, here is the result:

10000.times.inject({}) do |h, _| 
  r = pick_with_distribution(distributions)
  h[r] ||= 0
  h[r] += 1
  h
end
#=> {0=>3231, 1000=>1860, 2=>4909}
like image 173
fl00r Avatar answered Sep 23 '22 18:09

fl00r