I want to generate a random integer within a range but on average I want it to be biased toward a particular number. For example, I want to pick a number from 0-50
N times
and the average of all the chosen random numbers should be around 20
. I tried to use the random.normalvariate
function in python and casting it from float
to int
but I'm not sure if it's a proper solution. I set the mean
to 20
but I am not sure what the standard deviation
should be in order to make sure that on average we pick 20
from the range.
r = int(random.normalvariate(20, st_dev???))
r = 50 if r > 50 else r # clamp
CodePudding user response:
There are several choices, but one discrete random distribution that satisfies the properties is binomial distribution. In particular, a binomial distribution with parameters n=50
and p=0.4
is distributed on {0, ..., 50}
and has mean 20
(because n * p = 20
). Also its distribution is close to a normal distribution (loosely by central limit theorem).
from scipy.stats import binom
r = binom.rvs(50, 0.4, size=1000)
print(r) # [20 16 24 24 18 21 21 25 27 22 22 22 20 18 23 ... (a sample)
print(sum(r) / len(r)) # 20.022 (sample mean)
CodePudding user response:
If a mean of 20 is the only requirement for pseudo-random integers generated from 1 to 50, this simple generator based on random.random()
will meet it:
import random
def biased_uniform(n, invert_threshold):
u = random.random()
if u > 0.5 and random.random() > invert_threshold:
u = 1 - u
v = int(50 * u 0.5) 1
v = 1 if v == 0 else v
return v
total, n = 0, 1000000
for i in range(n):
v = biased_uniform(50, 0.52)
total = v
mean = total / n
print(f"mean {mean}")
You can tune the mean by adjusting the invert_threshold
in the semi-open interval [0.0, 1.0).