将数组元素转换为频率的最快方法

时间:2015-09-15 16:40:03

标签: python numpy

正如标题所说,我正在寻找一种转换数组的方法,因此它将是其适当元素的频率数组。

我找到textarea, input[type="number"]:not(.target) { background-color: #ffffff; border: 0 solid #CCCCCC; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.035) inset; transition: border 0.2s linear 0s, box-shadow 0.2s linear 0s; } select, input[type="number"]:not(.target) { border-radius: 2px 2px 2px 2px; color: #555555; display: inline-block; height: 37px; font-size: 14px; line-height: 15px; margin-bottom: 0px; padding: 2px 6px; vertical-align: middle; } np.count,但它不是我要找的

类似的东西:

自:

np.histogram

要:

array_ = np.array([0,0,0,1,0,0,2,0,0,1,2,0])

提前致谢!

2 个答案:

答案 0 :(得分:5)

如果数组中的值是非负整数且不是太大,则可以使用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.uniquereturn_inversereturn_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,一切都不会丢失!您仍然可以使用return_inverse的{​​{1}}参数,它会返回一个与原始数组排列相同的小整数数组。这个新数组现在处于完美状态,np.unique可以有效地处理它:

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_

所有这些解决方案都适用于纯NumPy,因此它们应该比通过Python >>> 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]) Counter的解决方案更有效。但是,与往常一样,如果效率是一个问题,那么您应该剖析以找出最合适的效率。特别要注意dict正在进行排序,因此其理论复杂度高于纯np.unique解决方案。如果没有时间安排,这在实践中是否有所作为是不可能的。 让我们来做一些时间,使用IPython的np.bincount(这是在Python 3.4上)。首先,我们将为我们需要的操作定义函数:

timeit

现在我们创建一个测试数组:

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方法之间存在数量级差异。来自@ Kasramvd解决方案的np.unique方法比Counter方法稍慢,但可能会在不同的计算机上或使用不同版本的Python和NumPy进行更改:您应该使用适合您的数据进行测试用例。

答案 1 :(得分:3)

作为一种快速方法,您可以使用colections.Counter这是获得可迭代项目频率的更加pythonic方式:

>>> 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])
相关问题