从python中的2d数组的每一行中随机选择N个元素

时间:2020-04-26 16:48:14

标签: python performance numpy-random

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

所以基本上,我想使用循环来做类似p 而没有的事情,其中​​[ np.random.choice(a[i], N, p=p_arr[i]) for i in range(a.shape[0]) ]是一个与p_arr形状相同的二维数组。 ap_arr中存储每一行​​的概率分布。

我要避免使用for循环的原因是因为运行行探查器表明该循环使我的代码减慢了很多速度(我有大量可用的数组)。

还有更多的python-ic方法吗?

我签出了这些链接(herehere),但它们没有回答我的问题。

谢谢!

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

a

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])

...

2 个答案:

答案 0 :(得分: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()将2D数组转换为1D数组。然后我们可以通过对一维数组执行操作来避免使用循环。

答案 1 :(得分:0)

也许使用列表理解而不是循环将解决此问题:

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]]