【问题标题】:making random.choice from a matrix of propabilities从概率矩阵中随机选择
【发布时间】:2019-05-10 17:01:24
【问题描述】:

我正在尝试将传入消息的模拟器模拟到输出端口。 我得到了输入端口的数量 (N) 和输出端口的数量 (M) 以及 N*M (mat) 概率的扁平矩阵。我还以数组 (in_freq) 的形式获得传入消息的数量。 我认为为了将每条消息从输入端口引导到输出端口,我应该使用 numpy.random.choice,但没能成功。

我尝试的是:

 for k in range (N):  
       enqueue = np.random.choice(M, in_freq[k], p=[(mat[k*N:k*N+M-1])])

当 enqueue 是消息目的地的数组时。

但遇到消息:

ValueError: 对象对于所需数组来说太深

【问题讨论】:

  • 不清楚为什么需要从矩阵中做出选择。为什么不能从 N 中选择一个值,从 M 中选择一个值?
  • 你的概率参数不是1d。

标签: python numpy random


【解决方案1】:

问题

正如 hpaulj 在 cmets 中指出的那样,您看到的 ValueError 是因为您的 p 参数包含在列表括号 [] 中。这个额外的封闭list 使np.random.choice 将您的p 解释为形状为(1, x) 的二维数组,而不是一维数组。由于np.random.choice 的第一个参数是一个整数,因此该函数期望p 是一维的,因此当它发现它不是一维时会抛出一个错误(有关完整的详细信息,请参阅choice docs)。

您可以通过删除p 周围的括号来修复ValueError

enqueue = np.random.choice(M, in_freq[k], p=mat[k*N:k*N+M-1])

但是,现在您的代码将引发一个新的不同的ValueError

ValueError: a and p must have same size

这个ValueError 是由于您生成扁平 NxM 矩阵mat 的行切片的方式不正确造成的。

解决办法

根据您问题中的描述,您似乎打算通过切片 1D mat 来循环原始 2D mat 的行。以下是如何修复代码中的切片,以便在 for 循环中迭代 mat 的行:

import numpy as np

N = 10
M = 5

in_freq = np.random.randint(0, 10, N)
mat = np.random.rand(N, M)
# normalize so that each row is a probability dist
mat /= mat.sum(axis=1, keepdims=True)
# flatten to match OP's question
mat = mat.flat

for k in range(N):
    print((M*k, M*(k + 1)))
    enqueue = np.random.choice(M, in_freq[k], p=mat[M*k:M*(k + 1)])

测试

为了证明现在正在生成正确的切片,我添加了一个打印语句,用于在for 循环的每次迭代中输出切片索引。输出如下:

(0, 5)
(5, 10)
(10, 15)
(15, 20)
(20, 25)
(25, 30)
(30, 35)
(35, 40)
(40, 45)
(45, 50)

这表明迭代mat 的行所需的切片现在确实按预期生成。

关于将 2D 索引转换为其 1D 扁平化等效项的注意事项

给定一个包含N 行和M 列的数组,将二维x,y 索引转换为其扁平一维等效i 的通用公式是:

i = x + M*y

您可以在此old thread 中找到更深入的讨论。

【讨论】: