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
?
问题:
回答1:
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
回答2:
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()
回答3:
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 :)
回答4:
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
回答5:
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.
回答6:
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))