2

我有一个二维数组,比如说,a = [ [1, 2, 3, 4], [5, 6,7, 8], [9, 10, 11, 12], ...[21, 22, 23, 24] ]我想根据每行可能不同的概率分布从每一行中随机N选择元素。p

所以基本上,我想做一些类似[ np.random.choice(a[i], N, p=p_arr[i]) for i in range(a.shape[0]) ] 使用循环的事情,其中p_arr​​ 2d 数组的形状与a. p_arr将每一行的概率分布存储在a.

我想避免使用 for 循环的原因是因为运行 line profiler 表明循环大大减慢了我的代码(我有大型数组要使用)。

有没有更多的python-ic方式来做到这一点?

我查看了这些链接(此处此处),但它们没有回答我的问题。

谢谢!

我想在没有循环的情况下做的一个例子:

a = np.ones([500, 500])

>>> p_arr = np.identity(a.shape[0])

>>> for i in range(a.shape[0]):

... a[i] = a[i]*np.arange(a.shape[0])

...

>>> [print(np.random.choice(a[i], p =p_arr[i])) for i in range(a.shape[0])]

4

2 回答 2

1

也许使用列表推导而不是循环可以解决这个问题:

import numpy as np

shape = (10,10)
N     = 4
distributions = np.random.rand(*shape)
distributions = distributions/(np.sum(distributions,axis=1)[:,None])
values        = np.arange(shape[0]*shape[1]).reshape(shape)

sample        = np.array([np.random.choice(v,N,p=r) for v,r in zip(values,distributions)])

输出:

print(np.round(distributions,2))
[[0.03 0.22 0.1  0.09 0.2  0.1  0.11 0.05 0.08 0.01]
 [0.04 0.12 0.13 0.03 0.16 0.22 0.16 0.05 0.   0.09]
 [0.15 0.04 0.08 0.07 0.17 0.13 0.01 0.15 0.1  0.1 ]
 [0.06 0.13 0.16 0.03 0.17 0.09 0.08 0.11 0.05 0.12]
 [0.07 0.08 0.09 0.08 0.13 0.18 0.12 0.13 0.07 0.07]
 [0.1  0.04 0.11 0.06 0.04 0.16 0.18 0.15 0.01 0.15]
 [0.06 0.09 0.17 0.08 0.14 0.15 0.09 0.01 0.06 0.15]
 [0.03 0.1  0.11 0.07 0.14 0.14 0.15 0.1  0.04 0.11]
 [0.05 0.1  0.18 0.1  0.03 0.18 0.12 0.05 0.05 0.13]
 [0.13 0.1  0.08 0.11 0.06 0.14 0.11 0.   0.14 0.14]]

print(sample)
[[ 6  4  8  5]
 [16 19 15 10]
 [25 20 24 23]
 [37 34 30 31]
 [41 44 46 45]
 [59 55 53 57]
 [64 63 65 61]
 [79 75 76 77]
 [85 81 83 88]
 [99 96 93 90]]

如果您希望在每一行上都使用非重复样本,您可以尝试另一种优化。通过展平值和分布,您可以根据每行的各自分布创建整个矩阵的索引的非重复洗牌。使用扁平分布,属于同一行的每组值将具有(作为一组)等效分布。这意味着,如果您在它们的原始行上重新组合混洗索引但保持其稳定的混洗有序,那么您可以取一片混洗矩阵来获取您的样本:

flatDist    = distributions.reshape((distributions.size,))
flatDist    = flatDist/np.sum(flatDist)
randomIdx   = np.random.choice(np.arange(values.size),flatDist.size,replace=False,p=flatDist)
shuffleIdx  = np.array([randomIdx//shape[1],randomIdx%shape[1]])
shuffleIdx  = shuffleIdx[:,np.argsort(shuffleIdx[0,:],kind="stable")]
sample      = values[tuple(shuffleIdx)].reshape(shape)[:,:N]

输出:

print(sample)
[[ 3  7  2  5]
 [13 12 14 16]
 [27 23 25 29]
 [37 31 33 36]
 [47 45 48 49]
 [59 50 52 54]
 [62 61 60 66]
 [72 78 70 77]
 [87 82 83 86]
 [92 98 95 93]]
于 2020-04-27T16:44:58.260 回答
0

这可以用来代替使用循环。

a = np.ones([500, 500])
p_arr = np.identity(a.shape[0])
a2 = a.flatten()
a3 = a2*np.full(shape=a.shape, fill_value=np.arange(a.shape[0])).flatten()
p_arr3 = p_arr.flatten()/a.shape[1]
print(np.random.choice(a3, a.shape[1], p =p_arr3))

我不得不np.array.flatten()多次使用将二维数组转换为一维数组。然后我们可以通过对一维数组执行操作来避免使用循环。

于 2020-04-26T18:13:23.220 回答