2017-08-01 76 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