python - 生成给定总和的随机(int)列表python

标签 python random

我想用给定的概率prob模拟n个随机选择。

我当前的解决方案如下:

from random import choices

result = [0]*len(prob)
population = list(range(0,len(prob)))
ch = choices(population, weights=prob, k=n)
for i in ch:
   result[i] += 1

我的问题是,我多次调用此代码,并且通常使用较大的 n ,并且此解决方案似乎根本没有效率。

是否有更好的方法(例如某些库的预构建函数)?

总而言之,我想要构建一个随机列表的最有效方法,总和为 $n$,这样获得给定列表的概率等于作为 n 个随机选择获得此列表的概率概率prob

谢谢

[编辑以添加上下文]

我真正做的是在一种马尔可夫链中进行n次随机游走,如下所示:

def rand_walk(n,state):
    next_states,prob = complicated_function(state) // compute the next states and their probability
    succ = distribute_over_next_states(n, prob) // compute how many walk goes to which states
    accu = complicated_function_2(state) // accumulator for the result
    for ns in range(0,len(next_states)):
        accu += rand_walk(succ[i],next_states[I])
    return accu

重点是,下一个状态及其概率的计算成本很高,因此我避免多次计算(因此我避免按顺序运行n)。这就是为什么我想按照给定的概率分配n

我希望这足以清楚地理解......

最佳答案

哼。 Numpy 已经实现 multinomial draws ,所以我们甚至不需要 via_binomial 函数:

In [56]: np.random.multinomial(10**8, [0.2, 0.3, 0.5])
Out[56]: array([20003098, 29996630, 50000272])

In [57]: via_binomial(10**8, [0.2, 0.3, 0.5])
Out[57]: [19993527, 30000996, 50005477]

IIUC,您可以将其视为一系列重复的二项式绘制:

from random import choices
import numpy as np

def original(n, prob):
    result = [0]*len(prob)
    population = list(range(0,len(prob)))
    ch = choices(population, weights=prob, k=n)
    for i in ch:
       result[i] += 1
    return result

def via_binomial(n, prob):
    result = []
    already_handled_prob = 0
    n_left = n
    for p in prob[:-1]:
        draw_prob = p / (1 - already_handled_prob)
        result.append(np.random.binomial(n_left, draw_prob))
        already_handled_prob += p
        n_left -= result[-1]
    result.append(n-sum(result))
    return result

给我

In [29]: %time original(10**6, [1])
Wall time: 343 ms
Out[29]: [1000000]

In [30]: %time via_binomial(10**6, [1])
Wall time: 0 ns
Out[30]: [1000000]

In [31]: %time original(10**6, [0.25, 0.75])
Wall time: 343 ms
Out[31]: [249944, 750056]

In [32]: %time via_binomial(10**6, [0.25, 0.75])
Wall time: 0 ns
Out[32]: [250030, 749970]

In [33]: %time original(10**8, [0.4, 0.3, 0.2, 0.1])
Wall time: 40.1 s
Out[33]: [40004163, 29999878, 19992540, 10003419]

In [34]: %time via_binomial(10**8, [0.4, 0.3, 0.2, 0.1])
Wall time: 0 ns
Out[34]: [39997530, 29999334, 20003182, 9999954]

In [35]: %time via_binomial(10**8, [0.4, 0.3, 0.2, 0.1])
Wall time: 0 ns
Out[35]: [40009324, 29995955, 19996223, 9998498]

(好吧,我使用的是 %time 而不是 %timeit 来作弊。:-) 在我的机器上大约需要 3-10 us。)

关于python - 生成给定总和的随机(int)列表python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51191735/

相关文章:

python - 在Python中制作正则表达式

python - 打印或写入 stdout 时出现 BlockingIOError

javascript - 在不使用 JQuery 的情况下使用 math.random 通过单选按钮移动 div

c++ - C++中的泊松到达代码给出相同的结果

java - 如何管理三角形中的不同顶点

C编程;使用随机数生成二维矩阵而不重复

java - 如何在具有随机大小和随机坐标的画圆内绘制字母?

python - 如何将标准 timedelta 字符串转换为 timedelta 对象

python - 如何添加到 numpy 数组的末尾并从头开始删除?

python - 为什么这个 Fizz Buzz 生成器比这个 Fizz Buzz Iterator 类快得多?