2

In Ruby, I need to draw from an exponential distribution with mean m. Please show me how to do it quickly and efficiently. Eg. let's have:

m = 4.2

def exponential_distribution
  rand( m * 2 )
end

But of course, this code is wrong, and also, it only returns whole number results. I'm already tired today, please hint me towards a good solution.

Boris Stitnicky
  • 12,444
  • 5
  • 57
  • 74

2 Answers2

7

If you want to do it from scratch you can use inversion.

def exponential(mean)
  -mean * Math.log(rand) if mean > 0
end

If you want to parameterize it with rate lambda, the mean and rate are inverses of each other. Divide by -lambda rather than multiplying by -mean.

Technically it should be log(1.0 - rand), but since 1.0 - rand has a uniform distribution you can save one arithmetic operation by just using rand.

pjs
  • 18,696
  • 4
  • 27
  • 56
4

How about using the distribution gem? Here's an example:

require 'distribution'

mean = 4.2
lambda = mean**-1

# generate a rng with exponential distribution
rng = Distribution::Exponential.rng(lambda)

# sample a value
sample = rng.call

If you need to change the value of lambda very often it might be useful to use the p_value method directly. A good sample can be found in the source code for Distribution::Exponential#rng, which basically just uses p_value internally. Here's an example of how to do it:

require 'distribution'

# use the same rng for each call
rng = Random

1.step(5, 0.1) do |mean|
  lambda = mean**-1

  # sample a value
  sample = Distribution::Exponential.p_value(rng.rand, lambda)
end
Patrick Oscity
  • 53,604
  • 17
  • 144
  • 168
  • How many such gems are there? How about the comparison between using eg. Ruby frontend to R? Once I'm sure I've a good one, I'll hapilly use it. Basically this was what I wanted. – Boris Stitnicky Aug 18 '13 at 20:18
  • I believe it is made and used by the guys from SciRuby and i've had a great experience with that. I do not know about any competiting gems. – Patrick Oscity Aug 18 '13 at 20:21
  • 1
    Oh really :-) I'm on my way to become one of those guys, so good to know :-) – Boris Stitnicky Aug 18 '13 at 20:26
  • Please could you help me with one more thing: My lambda changes very often, could you show me how to do it withoug creating a Proc object? – Boris Stitnicky Aug 18 '13 at 20:34
  • Ok i added the code. Basically the exponential distribution RNG takes one parameter lambda. Since the mean of the exponential distribution is `m = λ^-1` you want to pass `λ = m^-1` as argument (source: http://en.wikipedia.org/wiki/Exponential_distribution). – Patrick Oscity Aug 18 '13 at 20:34
  • Thanks, but, the last thing, can I do it without creating a Proc? Proc is amazing for when you draw from the same distribution many times. But if you only draw once, creating Proc is perhaps too much? (I've already accepted the answer.) – Boris Stitnicky Aug 18 '13 at 20:36
  • You're welcome! Btw have a look into [this answer by Marc-André Lafortune](http://stackoverflow.com/questions/198460/how-to-get-a-random-number-in-ruby/2773866#2773866) (see Notes on `Random.new`) to see why it is a good idea to use the same RNG again, anyway! – Patrick Oscity Aug 18 '13 at 20:53
  • @p11y would you mind explaining this line of code 1.step(5, 0.1) do |mean| – Beast_Code Oct 09 '14 at 03:40
  • @Beast_Code it means count from 1 to 5 in steps of 0.1. See http://ruby-doc.org/core-2.1.3/Numeric.html#method-i-step – Patrick Oscity Oct 09 '14 at 05:16