Make a number more probable to result from random

2019-04-18 01:17发布

I'm using x = numpy.random.rand(1) to generate a random number between 0 and 1. How do I make it so that x > .5 is 2 times more probable than x < .5?

6条回答
成全新的幸福
2楼-- · 2019-04-18 02:00

if you want a more fluid randomness, you can just square the output of the random function

(and subtract it from 1 to make x > 0.5 more probable instead of x < 0.5).

x = 1 - sqr(numpy.random.rand(1))
查看更多
等我变得足够好
3楼-- · 2019-04-18 02:07

This is overkill for you, but it's good to know an actual method for generating a random number with any probability density function (pdf).

You can do that by subclassing scipy.stat.rv_continuous, provided you do it correctly. You will have to have a normalized pdf (so that its integral is 1). If you don't, numpy will automatically adjust the range for you. In this case, your pdf has a value of 2/3 for x<0.5, and 4/3 for x>0.5, with a support of [0, 1) (support is the interval over which it's nonzero):

import scipy.stats as spst
import numpy as np
import matplotlib.pyplot as plt
import ipdb


def pdf_shape(x, k):
    if x < 0.5:
        return 2/3.
    elif 0.5 <= x and x < 1:
        return 4/3.
    else:
        return 0.


class custom_pdf(spst.rv_continuous):
    def _pdf(self, x, k):
        return pdf_shape(x, k)

instance = custom_pdf(a=0, b=1)

samps = instance.rvs(k=1, size=10000)

plt.hist(samps, bins=20)
plt.show()

Example histogram

查看更多
我想做一个坏孩纸
4楼-- · 2019-04-18 02:11

You could take a "mixture model" approach where you split the process into two steps: first, decide whether to take option A or B, where B is twice as likely as A; then, if you chose A, return a random number between 0.0 and 0.5, else if you chose B, return one between 0.5 and 1.0.

In the example, the randint randomly returns 0, 1, or 2, so the else case is twice as likely as the if case.

  m = numpy.random.randint(3)
  if m==0:
    x = numpy.random.uniform(0.0, 0.5)
  else:
    x = numpy.random.uniform(0.5, 1.0)

This is a little more expensive (two random draws instead of one) but it can generalize to more complicated distributions in a fairly straightforward way.

查看更多
手持菜刀,她持情操
5楼-- · 2019-04-18 02:15

First off, numpy.random.rand(1) doesn't return a value in the [0,1) range (half-open, includes zero but not one), it returns an array of size one, containing values in that range, with the upper end of the range having nothing to do with the argument passed in.

The function you're probably after is the uniform distribution one, numpy.random.uniform() since this will allow an arbitrary upper range.

And, to make the upper half twice as likely is a relatively simple matter.

Take, for example, a random number generator r(n) which returns a uniformly distributed integer in the range [0,n). All you need to do is adjust the values to change the distribution:

x = r(3)     # 0, 1 or 2, @ 1/3 probability each
if x == 2:
    x = 1    # Now either 0 (@ 1/3) or 1 (@ 2/3)

Now the chances of getting zero are 1/3 while the chances of getting one are 2/3, basically what you're trying to achieve with your floating point values.

So I would simply get a random number in the range [0,1.5), then subtract 0.5 if it's greater than or equal to one.

x = numpy.random.uniform(high=1.5)
if x >= 1: x -= 0.5

Since the original distribution should be even across the [0,1.5) range, the subtraction should make [0.5,1.0) twice as likely (and [1.0,1.5) impossible), while keeping the distribution even within each section ([0,0.5) and [0.5,1)):

 [0.0,0.5)  [0.5,1.0)  [1.0,1.5)  before
<---------><---------><--------->
 [0.0,0.5)  [0.5,1.0)  [0.5,1.0)  after
查看更多
乱世女痞
6楼-- · 2019-04-18 02:18
tmp = random()
if tmp < 0.5: tmp = random()

is pretty easy way to do it

ehh I guess this is 3x as likely ... thats what i get for sleeping through that class I guess

from random import random,uniform

def rand1():
    tmp = random()
    if tmp < 0.5:tmp = random()
    return tmp
def rand2():
    tmp = uniform(0,1.5)
    return tmp if tmp <= 1.0 else tmp-0.5

sample1 = []
sample2 = []
for i in range(10000):
    sample1.append(rand1()>=0.5)
    sample2.append(rand2()>=0.5)

print sample1.count(True) #~ 75% 
print sample2.count(True) #~ 66% <- desired i believe :)
查看更多
7楼-- · 2019-04-18 02:21

That's a fitting name!

Just do a little manipulation of the inputs. First set x to be in the range from 0 to 1.5.

x = numpy.random.uniform(1.5)

x has a 2/3 chance of being greater than 0.5 and 1/3 chance being smaller. Then if x is greater than 1.0, subtract .5 from it

if x >= 1.0:
    x = x - 0.5
查看更多
登录 后发表回答