【发布时间】:2014-03-25 06:59:15
【问题描述】:
相关但不同,恕我直言:
(1)numpy: most efficient frequency counts for unique values in an array
(2)Using Numpy arrays as lookup tables
设置:
import numpy as np
from scipy.stats import itemfreq
x = np.array([1, 1, 1, 2, 25000, 2, 2, 5, 1, 1])
fq = itemfreq(x)
fq.astype(int)
array([[ 1, 5],
[ 2, 3],
[ 5, 1],
[25000, 1]])
现在,我想使用 fq 作为查找表,然后这样做:
res = magic_lookup_function(fq, x)
res
array([5, 5, 5, 3, 1, 3, 3, 1, 5, 5])
按照 (1) 和 (2) 中的建议,我可以将 fq 转换为 python 字典,然后从那里查找,然后返回到 np.array。但是有没有更清洁/更快/纯粹的 numpy 方式来做到这一点?
更新:另外,正如 (2) 中所建议的,我可以使用 bincount,但我担心如果我的索引很大,例如~250,000。
谢谢!
更新的解决方案
正如@Jaime 指出的那样(如下),np.unique 最多在 O(n log n) 时间内对数组进行排序。所以我想知道,itemfreq 在幕后会发生什么?原来itemfreq 对数组进行排序,我假设它也是 O(n log n):
In [875]: itemfreq??
def itemfreq(a):
... ... ...
scores = _support.unique(a)
scores = np.sort(scores)
这是一个timeit示例
In [895]: import timeit
In [962]: timeit.timeit('fq = itemfreq(x)', setup='import numpy; from scipy.stats import itemfreq; x = numpy.array([ 1, 1, 1, 2, 250000, 2, 2, 5, 1, 1])', number=1000)
Out[962]: 0.3219749927520752
但似乎没有必要对数组进行排序。如果我们在纯 python 中执行,会发生以下情况。
In [963]: def test(arr):
.....: fd = {}
.....: for i in arr:
.....: fd[i] = fd.get(i,0) + 1
.....: return numpy.array([fd[j] for j in arr])
In [967]: timeit.timeit('test(x)', setup='import numpy; from __main__ import test; x = numpy.array([ 1, 1, 1, 2, 250000, 2, 2, 5, 1, 1])', number=1000)
Out[967]: 0.028257131576538086
哇,快了 10 倍!
(至少,在这种情况下,数组不会太长,但可能包含较大的值。)
而且,正如我所怀疑的那样,仅供参考,使用 np.bincount 执行此操作对于较大的值是低效的:
In [970]: def test2(arr):
bc = np.bincount(arr)
return bc[arr]
In [971]: timeit.timeit('test2(x)', setup='import numpy; from __main__ import test2; x = numpy.array([ 1, 1, 1, 2, 250000, 2, 2, 5, 1, 1])', number=1000)
Out[971]: 0.0975029468536377
【问题讨论】: