我有一个文件,不同的值的一些概率,例如:
1 0.1
2 0.05
3 0.05
4 0.2
5 0.4
6 0.2
我想用这个分布生成随机数。是否存在处理此问题的现有模块?自己编写代码是相当简单的(构建累积密度函数,生成一个随机值[0,1]并选择相应的值),但这似乎应该是一个常见的问题,可能有人已经为它创建了一个函数/模块。
我需要这个,因为我想生成一个生日列表(它不遵循标准随机模块中的任何分布)。
我有一个文件,不同的值的一些概率,例如:
1 0.1
2 0.05
3 0.05
4 0.2
5 0.4
6 0.2
我想用这个分布生成随机数。是否存在处理此问题的现有模块?自己编写代码是相当简单的(构建累积密度函数,生成一个随机值[0,1]并选择相应的值),但这似乎应该是一个常见的问题,可能有人已经为它创建了一个函数/模块。
我需要这个,因为我想生成一个生日列表(它不遵循标准随机模块中的任何分布)。
当前回答
从Python 3.6开始,Python的标准库中就有了一个解决方案,即random.choices。
示例用法:让我们建立一个与OP问题中匹配的总体和权重:
>>> from random import choices
>>> population = [1, 2, 3, 4, 5, 6]
>>> weights = [0.1, 0.05, 0.05, 0.2, 0.4, 0.2]
现在choices(population, weights)生成一个样本,包含在一个长度为1的列表中:
>>> choices(population, weights)
[4]
可选的仅关键字参数k允许一次请求多个示例。这很有价值,因为有些准备工作是随机的。在生成样本之前,每次调用choice函数都要做的事情;通过一次生成多个样本,我们只需要做一次准备工作。这里我们生成一百万个样本,并使用集合。计数器来检查我们得到的分布是否与我们给出的权重大致匹配。
>>> million_samples = choices(population, weights, k=10**6)
>>> from collections import Counter
>>> Counter(million_samples)
Counter({5: 399616, 6: 200387, 4: 200117, 1: 99636, 3: 50219, 2: 50025})
其他回答
(好吧,我知道你想要薄膜包装,但也许这些自制的解决方案对你来说不够简洁。: -)
pdf = [(1, 0.1), (2, 0.05), (3, 0.05), (4, 0.2), (5, 0.4), (6, 0.2)]
cdf = [(i, sum(p for j,p in pdf if j < i)) for i,_ in pdf]
R = max(i for r in [random.random()] for i,c in cdf if c <= r)
我伪确认,这是通过目测这个表达式的输出:
sorted(max(i for r in [random.random()] for i,c in cdf if c <= r)
for _ in range(1000))
你可能想看看NumPy随机抽样分布
scipy.stats。Rv_discrete可能是您想要的。您可以通过values参数提供您的概率。然后,您可以使用分布对象的rvs()方法来生成随机数。
正如Eugene Pakhomov在评论中指出的那样,你也可以将p关键字参数传递给numpy.random.choice(),例如:
numpy.random.choice(numpy.arange(1, 7), p=[0.1, 0.05, 0.05, 0.2, 0.4, 0.2])
如果你使用的是Python 3.6或更高版本,你可以使用标准库中的random.choices() -请参阅Mark Dickinson的回答。
另一个答案,可能更快:)
distribution = [(1, 0.2), (2, 0.3), (3, 0.5)]
# init distribution
dlist = []
sumchance = 0
for value, chance in distribution:
sumchance += chance
dlist.append((value, sumchance))
assert sumchance == 1.0 # not good assert because of float equality
# get random value
r = random.random()
# for small distributions use lineair search
if len(distribution) < 64: # don't know exact speed limit
for value, sumchance in dlist:
if r < sumchance:
return value
else:
# else (not implemented) binary search algorithm
使用CDF生成列表的一个优点是可以使用二分搜索。当你需要O(n)个时间和空间进行预处理时,你可以得到O(k log n)个数字。由于普通的Python列表效率很低,你可以使用数组模块。
如果你坚持空间不变,你可以做到以下几点;O(n)时间,O(1)空间。
def random_distr(l):
r = random.uniform(0, 1)
s = 0
for item, prob in l:
s += prob
if s >= r:
return item
return item # Might occur because of floating point inaccuracies