運行np.unique()時,它首先將數組平整,對數組進行排序,然後查找唯一值。當我有形狀的陣列(10,3000,3000)時,需要大約一秒鐘的時間才能找到唯一身份,但這很快就會加起來,因爲我需要多次調用np.unique()。由於我只關心數組中唯一數字的總數,排序似乎是浪費時間。有效地計算唯一元素的數量--NumPy/Python
是否有更快的方法找到除np.unique()以外的大數組中唯一值的總數?
運行np.unique()時,它首先將數組平整,對數組進行排序,然後查找唯一值。當我有形狀的陣列(10,3000,3000)時,需要大約一秒鐘的時間才能找到唯一身份,但這很快就會加起來,因爲我需要多次調用np.unique()。由於我只關心數組中唯一數字的總數,排序似乎是浪費時間。有效地計算唯一元素的數量--NumPy/Python
是否有更快的方法找到除np.unique()以外的大數組中唯一值的總數?
下面是一個適用於dtype爲np.uint8
的數組比np.unique
快的方法。
首先,創建一個陣列的工作:
In [128]: a = np.random.randint(1, 128, size=(10, 3000, 3000)).astype(np.uint8)
對於以後的比較,使用np.unique
找到獨特的價值觀:
In [129]: u = np.unique(a)
這裏的更快的方法; v
將包含結果:
In [130]: q = np.zeros(256, dtype=int)
In [131]: q[a.ravel()] = 1
In [132]: v = np.nonzero(q)[0]
驗證我們得到了相同的結果:
In [133]: np.array_equal(u, v)
Out[133]: True
時間:
In [134]: %timeit u = np.unique(a)
2.86 s ± 9.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [135]: %timeit q = np.zeros(256, dtype=int); q[a.ravel()] = 1; v = np.nonzero(q)
300 ms ± 5.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
所以2.86秒爲np.unique()
,和0.3秒的替代方法。
這工作完美。謝謝。它似乎也可以用來返回一個排序的唯一數組。我想知道爲什麼numpy決定實施他們獨特的()方式。 – onepint16oz
'numpy.unique'可以處理任意數據類型的數組(所有的各種整數和浮點類型,複數類型和結構化數組)。對於'numpy.unique'來說,使用這種方法處理一個(可能是兩個)字節整數類型是一種特殊情況,這似乎是可行的。 –
我們可以利用這樣一個事實:元素被限制在uint8
範圍內,通過與np.bincount
分箱計數,然後簡單地計算其中的非零數。因爲np.bincount
需要1D
陣列,我們會用np.ravel()
將輸入平坦化,然後將其輸入bincount
。
因此,實現將是 -
(np.bincount(a.ravel())!=0).sum()
運行測試
助手函數來創建與各種數目的唯一號碼的輸入數組 -
def create_input(n_unique):
unq_nums = np.random.choice(np.arange(256), n_unique,replace=0)
return np.random.choice(unq_nums, (10,3000,3000)).astype(np.uint8)
其他方法(ES ):
# @Warren Weckesser's soln
def assign_method(a):
q = np.zeros(256, dtype=int)
q[a.ravel()] = 1
return len(np.nonzero(q)[0])
驗證提出的方法的 -
In [141]: a = create_input(n_unique=120)
In [142]: len(np.unique(a))
Out[142]: 120
In [143]: (np.bincount(a.ravel())!=0).sum()
Out[143]: 120
計時 -
In [124]: a = create_input(n_unique=128)
In [125]: %timeit len(np.unique(a)) # Original soln
...: %timeit assign_method(a) # @Warren Weckesser's soln
...: %timeit (np.bincount(a.ravel())!=0).sum()
...:
1 loop, best of 3: 3.09 s per loop
1 loop, best of 3: 394 ms per loop
1 loop, best of 3: 209 ms per loop
In [126]: a = create_input(n_unique=256)
In [127]: %timeit len(np.unique(a)) # Original soln
...: %timeit assign_method(a) # @Warren Weckesser's soln
...: %timeit (np.bincount(a.ravel())!=0).sum()
...:
1 loop, best of 3: 3.46 s per loop
1 loop, best of 3: 378 ms per loop
1 loop, best of 3: 212 ms per loop
不錯。我也嘗試過'bincount',但它似乎比較慢。實際上,當我使用你的代碼時,'assign_method(a)'爲295 ms,'(np.bincount(a.ravel())!= 0).sum()'爲425 ms。去搞清楚。 –
@WarrenWeckesser可能是硬件(CPU,RAM)。我在英特爾i7-6700HQ,16GB RAM。但是,您的ideone具有可重現性:https://ideone.com/WDWq9j – Divakar
我使用的是「2013年後期」Macbook Pro,2.6 GHz Intel Core i7,16 GB 1600 MHz DDR3。另外:Python 3.5.2,numpy 1.13.1。 –
你是什麼陣列的數據類型(例如什麼是「a.dtype」)? –
@WarrenWeckesser uint8 – onepint16oz
熊貓的獨特功能不排序,因此速度更快。您可能需要檢查:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.unique.html – ayhan