Sliding probability scale for randomly picking a number between a range [closed]

江枫思渺然 提交于 2019-12-13 08:18:03

问题


Let's say I have lots of cash I want to give out in random increments between $500 and $5,000. I'd like the lower end of the range to be much more probable than the higher range. What's the most efficient algorithm I can write in Ruby to randomly hand out cash in this manner?


回答1:


I think the easiest way is to just use the case statement:

def get_price
  case rand(100) + 1
    when  1..50  then 500 
    when 50..75  then 1000
    when 75..99  then 2500
    when 99..100 then 10000
  end
end

p get_price # => 500

Calling get_price will return 500 with 50% probability but 10000 will only be returned 2% of the time.




回答2:


One approach is to start by defining a number of ranges and assigning a probability 'weight' for each. Here's an example:

weights = {[500,  1000] => 17,
           [1001, 1500] => 15,
           [1501, 2000] => 13,
           [2001, 2500] => 12,
           [2501, 3000] => 11,
           [3001, 3500] => 10,
           [3501, 4000] => 10,
           [4001, 4500] => 10,
           [4501, 5000] => 10}

Here, the range [1001, 1500], with weight 15, is 50% more likely to be selected than any of the four highest ranges, which each have a weight of 10. You can have any number of ranges and (as here) weights need not sum to 100. Here you could replace the four highest ranges with the single range [3001, 5000] => 40.

The idea is to select a range at random, using the weights you've provided and then select a random value within that range, where each value within the range is equally likely to be chosen.

ranges = weights.keys       # => [[500,  1000], [1001, 1500],.., [4501, 5000]]
cum_wights = weights.values # => [17, 15,.., 10] 
(1..weights.size-1).each {|i| cum_weights[i] += cum_weights[i-1]}
   # cum_weights => [17, 32,.., 108]

# Obtain range randomly
rn = rand(cum_weights) # => random number between 0 and cum_weights.last (here 108)
i = 0 # range index
i += 1 while cum_weights[i] <= rn
rr = ranges[i] # random range

# Obtain uniform random value in range rr
# Obtain uniform random value in range i
# Since `rn` is equally-likely for any value in `rr`,
cwt_min, cwt_max = (i > 0 ? cum_weights[i-1] + 1 : 0), cum_weights[i]
random_amount = rr.first + ((rn - cwt_min).to_f/(cwt_max - cwt_min + 1)) * (rr.last-rr.first + 1)

or simply generate another random number:

random_amount = rr.first + rand(rr.last-rr.first)

Incidentally, I am very experienced at giving away random amounts of money. Let me know if I can help.




回答3:


Sounds like you want to generate random numbers with a Gaussian (aka normal) distribution skewed towards the left (or right, I can never keep them straight; the hump goes on the left).

A VBA implementation of the algorithm for sampling a skewed normal distribution is here (warning: popups): http://www.ozgrid.com/forum/showthread.php?t=108175

It ought not be difficult to translate it to ruby.



来源:https://stackoverflow.com/questions/19149957/sliding-probability-scale-for-randomly-picking-a-number-between-a-range

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!