Numpy随机选择生成具有所有唯一值的2D数组

Lj *_*nda 6 python arrays numpy

所以我想知道在使用np.random.choice每行具有唯一值的位置生成二维数组时是否存在更有效的解决方案.

例如,对于具有shape的数组(3,4),我们期望输出:

# Expected output given a shape (3,4)
array([[0, 1, 3, 2],
       [2, 3, 1, 0],
       [1, 3, 2, 0]])
Run Code Online (Sandbox Code Playgroud)

这意味着每行的值必须相对于列数是唯一的.因此对于每一行out,整数应该只在0到3之间.

我知道,我可以通过传递实现它Falsereplace论据.但我只能为每一行而不是整个矩阵.例如,我可以这样做:

>>> np.random.choice(4, size=(1,4), replace=False)
array([[0,2,3,1]])
Run Code Online (Sandbox Code Playgroud)

但是当我尝试这样做时:

>>> np.random.choice(4, size=(3,4), replace=False)
Run Code Online (Sandbox Code Playgroud)

我收到这样的错误:

 File "<stdin>", line 1, in <module>
 File "mtrand.pyx", line 1150, in mtrand.RandomState.choice 
 (numpy\random\mtrand\mtrand.c:18113)
 ValueError: Cannot take a larger sample than population when 
 'replace=False'
Run Code Online (Sandbox Code Playgroud)

我认为这是因为它试图绘制3 x 4 = 12样本,因为矩阵的大小没有替换,但我只给它一个限制4.

我知道我可以通过以下方式解决它for-loop:

 >>> a = (np.random.choice(4,size=4,replace=False) for _ in range(3))
 >>> np.vstack(a)
 array([[3, 1, 2, 0],
        [1, 2, 0, 3],
        [2, 0, 3, 1]])
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有一个没有使用任何for循环的解决方法?(我有点假设如果我有大于1000的行数,添加for循环可能会使它变慢.但是你可以看到我实际创建了一个生成器,a所以我也不确定它是否有影响毕竟.)

Div*_*kar 14

我经常使用的一个技巧是生成一个随机数组,并使用argsort唯一索引作为所需的唯一数字.因此,我们可以做 -

def random_choice_noreplace(m,n, axis=-1):
    # m, n are the number of rows, cols of output
    return np.random.rand(m,n).argsort(axis=axis)
Run Code Online (Sandbox Code Playgroud)

样品运行 -

In [98]: random_choice_noreplace(3,7)
Out[98]: 
array([[0, 4, 3, 2, 6, 5, 1],
       [5, 1, 4, 6, 0, 2, 3],
       [6, 1, 0, 4, 5, 3, 2]])

In [99]: random_choice_noreplace(5,7, axis=0) # unique nums along cols
Out[99]: 
array([[0, 2, 4, 4, 1, 0, 2],
       [1, 4, 3, 2, 4, 1, 3],
       [3, 1, 1, 3, 2, 3, 0],
       [2, 3, 0, 0, 0, 2, 4],
       [4, 0, 2, 1, 3, 4, 1]])
Run Code Online (Sandbox Code Playgroud)

运行时测试 -

# Original approach
def loopy_app(m,n):
    a = (np.random.choice(n,size=n,replace=False) for _ in range(m))
    return np.vstack(a)
Run Code Online (Sandbox Code Playgroud)

计时 -

In [108]: %timeit loopy_app(1000,100)
10 loops, best of 3: 20.6 ms per loop

In [109]: %timeit random_choice_noreplace(1000,100)
100 loops, best of 3: 3.66 ms per loop
Run Code Online (Sandbox Code Playgroud)

  • 使用argsort代替replace = False的好技巧.+1 (2认同)