2017-08-01 42 views
3

所以我想知道是否有更有效的解决方案来生成使用np.random.choice的2-D阵列,其中每行都有唯一的值。Numpy随机选择产生具有所有唯一值的2D阵列

例如,对于与形状(3,4)阵列,我们期望的输出:

# Expected output given a shape (3,4) 
array([[0, 1, 3, 2], 
     [2, 3, 1, 0], 
     [1, 3, 2, 0]]) 

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

我知道我可以通过将False传递给参数来实现它。但是我只能为每一行做,而不是整个矩阵。举例来说,我可以这样做:

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

但是,当我尝试这样做:

>>> np.random.choice(4, size=(3,4), replace=False) 

我得到这样一个错误:

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' 

我想这是因为它试图绘制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]]) 

但我想知道是否有一个变通方法,而无需使用任何for循环? (我有点假设添加for循环可能会使它变慢,如果我有大于1000的行数。但正如你可以看到我实际上在a创建一个生成器,所以我也不确定它是否有一个效果毕竟)

回答

10

我常用的一个技巧是生成一个随机数组,并使用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) 

样品试验 -

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

运行测试 -

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

计时 -

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 
使用argsort来取代替换
+2

好的技巧=假。 +1 –

+0

太棒了!非常感谢! –

+0

这是天才,谢谢! – Anonymous