嗨,我正在为基因组学课程编写一些代码,但在某些方面遇到了困难。
我有一组具有概率的互斥事件
我想以给定的概率模拟随机抽样事件 n 次。
输入:概率 = {0.3, 0.2, 0.5} 事件{e1,e2,e3} n=100
输出:e3 应该有 ~50 个结果,e2 应该有 ~20 个结果,e1 应该有 ~30 个结果。请注意,这些可能不完全是 50、20、30,因为经验值与理论值不同......
Python 没有内置任何加权采样功能(NumPy/SciPy 有),但对于这样一个非常简单的情况,它非常简单:
import itertools
import random
probabilities = [0.3, 0.2, 0.5]
totals = list(itertools.accumulate(probabilities))
def sample():
n = random.uniform(0, totals[-1])
for i, total in enumerate(totals):
if n <= total:
return i
如果你没有 Python 3.2+,你就没有这个accumulate
功能;如果列表真的这么短,你可以用低效的单行来伪造它:
totals = [sum(probabilities[:i+1]) for i in range(len(probabilities))]
…或者你可以编写一个显式循环,或者一个丑陋的调用,或者从文档reduce
中复制等效的 Python 函数。
另外,请注意,如果您可以确定您的数字加起来等于 1.0,那么这random.uniform(0, totals[-1])
只是一种更复杂的书写方式。random.random()
一个快速的测试方法:
>>> samples = [sample() for _ in range(100000)]
>>> samples.count(0)
29878
>>> samples.count(1)
19908
>>> samples.count(2)
50214
这些分别非常接近 100000 的 30%、20% 和 50%。
假设我们有三个事件,每个事件的概率分别为 0.3、0.2 和 0.5。然后对于生成的每个样本,我们生成一个范围为 [0,1) 的数字,我们称之为“rand”。如果 "rand" < .3,我们生成事件 1,如果 .3 <= "rand" < .5,我们生成偶数 2,否则我们生成事件 3。这可以使用random()来完成,它确实生成了一个数字在 [0,1) 范围内。