我有一个文件,不同的值的一些概率,例如:
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]并选择相应的值),但这似乎应该是一个常见的问题,可能有人已经为它创建了一个函数/模块。
我需要这个,因为我想生成一个生日列表(它不遵循标准随机模块中的任何分布)。
当前回答
这里有一个更有效的方法:
只需使用'weights'数组调用以下函数(假设索引为相应的项)和no。所需样品的数量。可以很容易地修改此函数以处理有序对。
使用它们各自的概率返回采样/选择(带有替换)的索引(或项):
def resample(weights, n):
beta = 0
# Caveat: Assign max weight to max*2 for best results
max_w = max(weights)*2
# Pick an item uniformly at random, to start with
current_item = random.randint(0,n-1)
result = []
for i in range(n):
beta += random.uniform(0,max_w)
while weights[current_item] < beta:
beta -= weights[current_item]
current_item = (current_item + 1) % n # cyclic
else:
result.append(current_item)
return result
关于while循环中使用的概念的简短说明。 我们从累积beta(均匀随机构造的累积值)中减少当前项的权重,并增加当前索引以找到与beta值匹配的项。
其他回答
你可能想看看NumPy随机抽样分布
使用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
基于其他解决方案,您可以生成累积分布(作为整数或浮点数),然后您可以使用平分使其更快
这是一个简单的例子(我在这里使用整数)
l=[(20, 'foo'), (60, 'banana'), (10, 'monkey'), (10, 'monkey2')]
def get_cdf(l):
ret=[]
c=0
for i in l: c+=i[0]; ret.append((c, i[1]))
return ret
def get_random_item(cdf):
return cdf[bisect.bisect_left(cdf, (random.randint(0, cdf[-1][0]),))][1]
cdf=get_cdf(l)
for i in range(100): print get_random_item(cdf),
get_cdf函数会将20、60、10、10转换为20、20+60、20+60+10、20+60+10+10
现在我们随机选择一个20+60+10+10的随机数。然后我们用二分法快速得到实际值
(好吧,我知道你想要薄膜包装,但也许这些自制的解决方案对你来说不够简洁。: -)
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))
这里有一个更有效的方法:
只需使用'weights'数组调用以下函数(假设索引为相应的项)和no。所需样品的数量。可以很容易地修改此函数以处理有序对。
使用它们各自的概率返回采样/选择(带有替换)的索引(或项):
def resample(weights, n):
beta = 0
# Caveat: Assign max weight to max*2 for best results
max_w = max(weights)*2
# Pick an item uniformly at random, to start with
current_item = random.randint(0,n-1)
result = []
for i in range(n):
beta += random.uniform(0,max_w)
while weights[current_item] < beta:
beta -= weights[current_item]
current_item = (current_item + 1) % n # cyclic
else:
result.append(current_item)
return result
关于while循环中使用的概念的简短说明。 我们从累积beta(均匀随机构造的累积值)中减少当前项的权重,并增加当前索引以找到与beta值匹配的项。