正如标题所说,我正在寻找一种转换数组的方式,以便它将成为其适当元素的频率数组。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”(在我的机器上)快得多。 –