正如標題所說,我正在尋找一種轉換數組的方式,以便它將成爲其適當元素的頻率數組。numpy將數組的元素轉換爲其頻率的最快方法
我發現np.count
和np.histogram
,但它不是我所期待的
喜歡的東西:
來源:
array_ = np.array([0,0,0,1,0,0,2,0,0,1,2,0])
要:提前
array_ = np.array([8,8,8,2,8,8,2,8,8,2,2,8])
謝謝!
正如標題所說,我正在尋找一種轉換數組的方式,以便它將成爲其適當元素的頻率數組。numpy將數組的元素轉換爲其頻率的最快方法
我發現np.count
和np.histogram
,但它不是我所期待的
喜歡的東西:
來源:
array_ = np.array([0,0,0,1,0,0,2,0,0,1,2,0])
要:提前
array_ = np.array([8,8,8,2,8,8,2,8,8,2,2,8])
謝謝!
如果陣列中的值都是非負整數,其也不會太大,你可以使用np.bincount
。使用原始數組作爲bincount
結果的索引可獲得所需的輸出。
>>> array_ = np.array([0,0,0,1,0,0,2,0,0,1,2,0])
>>> np.bincount(array_)
array([8, 2, 2])
>>> np.bincount(array_)[array_]
array([8, 8, 8, 2, 8, 8, 2, 8, 8, 2, 2, 8])
熊記住,np.bincount
結果有大小max(array_) + 1
,所以如果你的陣列有較大的值這種方式是低效的:你最終建立一個非常大的中間結果。
另一種方法應該是即使有大的或負的輸入有效的是使用np.unique
與return_inverse
和return_counts
參數,如下所示:
>>> array_ = np.array([0,0,0,1,0,0,2,0,0,1,2,0])
>>> _, inv, counts = np.unique(array_, return_inverse=True, return_counts=True)
>>> counts[inv]
array([8, 8, 8, 2, 8, 8, 2, 8, 8, 2, 2, 8])
注意,return_counts
論點NumPy的1.9.0是新,所以你需要一個最新版本的NumPy。如果你沒有NumPy 1.9.0,一切都不會丟失!您仍然可以使用np.unique
的參數return_inverse
,它可以讓您返回與原始佈局相同排列的小整數數組。這個新的數組現在是在完美的形狀bincount
以它高效地工作:
>>> array_ = np.array([0,0,0,1,0,0,2,0,0,1,2,0])
>>> _, inverse = np.unique(array_, return_inverse=True)
>>> np.bincount(inverse)[inverse]
array([8, 8, 8, 2, 8, 8, 2, 8, 8, 2, 2, 8])
又如,具有較大array_
內容:
>>> array_ = np.array([0, 71, 598, 71, 0, 0, 243])
>>> _, inverse = np.unique(array_, return_inverse=True)
>>> inverse
array([0, 1, 3, 1, 0, 0, 2])
>>> np.bincount(inverse)[inverse]
array([3, 2, 1, 2, 3, 3, 1])
所有這些解決方案中純NumPy的工作,所以他們應該比通過Python Counter
或dict
的解決方案效率更高。但是,一如既往,如果效率是一個問題,那麼你應該找出最適合的方法。特別要注意的是,np.unique
正在進行一些分析,所以它的理論複雜度要高於純粹的np.bincount
解決方案。無論在實踐中是否有所作爲都不可能沒有時間表示。 所以我們來做一些計時,使用IPython的timeit
(這是在Python 3.4上)。首先,我們將定義功能,我們需要的操作:
In [1]: import numpy as np; from collections import Counter
In [2]: def freq_bincount(array):
...: return np.bincount(array)[array]
...:
In [3]: def freq_unique(array):
...: _, inverse, counts = np.unique(array, return_inverse=True, return_counts=True)
...: return counts[inverse]
...:
In [4]: def freq_counter(array):
...: c = Counter(array)
...: return np.array(list(map(c.get, array)))
...:
現在我們創建一個測試陣列:
In [5]: test_array = np.random.randint(100, size=10**6)
然後我們做了一些時機。這裏是我的機器上的結果:
In [6]: %timeit freq_bincount(test_array)
100 loops, best of 3: 2.69 ms per loop
In [7]: %timeit freq_unique(test_array)
10 loops, best of 3: 166 ms per loop
In [8]: %timeit freq_counter(test_array)
1 loops, best of 3: 317 ms per loop
還有的np.bincount
方法和np.unique
方法之間的訂單數量級的差別。來自@ Kasramvd解決方案的Counter
方法比np.unique
方法稍微慢一些,但這可能會在另一臺機器上或不同版本的Python和NumPy中改變:您應該測試適合您的用例的數據。
作爲一個快速的方法,你可以使用colections.Counter
這是獲得一個可迭代項目的頻率更Python的方式:
>>> import numpy as np
>>> array_ = np.array([0,0,0,1,0,0,2,0,0,1,2,0])
>>> from collections import Counter
>>> c=Counter(array_)
>>> np.array(map(c.get,array_))
array([8, 8, 8, 2, 8, 8, 2, 8, 8, 2, 2, 8])
'array_'是否包含大值? 'np.bincount(array _)[array_]'可以滿足你這個例子的需要,但是如果你的原始'array_'中有很大的值,那麼效率會很低。 –
使用熊貓是否可用?如果是這樣,你可以使用'pd.Series(array _)。map(pd.value_counts(array _))。values'。這種基於哈希表的方法相當快速 - 仍然比Mark Dickinson提出的超快速「計數」方法慢得多,但比「獨特」快得多,而且比「Counter」(在我的機器上)快得多。 –