Python 数组的精确直方图
如何获取浮点数组元素的出现计数?。 如果数组是 [-1,2,3,-1,3,4,4,4,4],Python 数组的精确直方图,python,numpy,Python,Numpy,如何获取浮点数组元素的出现计数?。 如果数组是 [-1,2,3,-1,3,4,4,4,4], 结果应该是 [2,1,2,5], 不一定按那个顺序,从计数到被计数的元素的映射是不需要的,只是计数很重要 histogram也可以做类似的事情,但它必须使用bins,这需要预先计算bins大小来分离元素,还可能创建不必要的许多空bins 这也可以通过哈希或排序手动完成,但是 似乎应该有一种没有python级循环的快速、一次性方法 谢谢 编辑: 我尝试了在撰写本文时提出的解决方案,并认为我会分享这些结果,
结果应该是 [2,1,2,5], 不一定按那个顺序,从计数到被计数的元素的映射是不需要的,只是计数很重要 histogram也可以做类似的事情,但它必须使用bins,这需要预先计算bins大小来分离元素,还可能创建不必要的许多空bins 这也可以通过哈希或排序手动完成,但是 似乎应该有一种没有python级循环的快速、一次性方法 谢谢 编辑: 我尝试了在撰写本文时提出的解决方案,并认为我会分享这些结果,因为它们有些出乎意料。 我最初没有提到的是,该流使用的列表非常小,但是该操作被调用了数百万次,这在某种程度上是一种极端情况 测试及其打印输出如下所示。histogramize1是我的原始函数,我想改进它的性能。它比第二快快了2倍,知道原因会很有趣
import numpy as np
from collections import Counter
from timeit import timeit
def histogramize1(X):
cnts = {}
for x in X:
if x in cnts:
cnts[x] += 1
else:
cnts[x] = 1
lst = [ v for k,v in cnts.iteritems() ]
lX = len(X)
return [ float(x)/lX for x in lst ]
def histogramize2(X):
ua,uind= np.unique(X,return_inverse=True)
lX = len(X)
res = [float(x)/lX for x in np.bincount(uind)]
return res
def histogramize3(X):
counts = Counter(X)
lX = len(X)
res = [float(x)/lX for x in counts.viewvalues()]
return res
def histogramize4(X):
lX = len(X)
return [float(X.count(i))/lX for i in np.unique(X)]
if __name__ == '__main__':
lst0 = [-1,2,3,-1,3,4,4,4,4,4]
lst = lst0 + lst0 + lst0 + lst0
num = 100000
print timeit("histogramize1(lst)",setup="from __main__ import histogramize1, lst",number=num)
print timeit("histogramize2(lst)",setup="from __main__ import histogramize2, lst",number=num)
print timeit("histogramize3(lst)",setup="from __main__ import histogramize3, lst",number=num)
print timeit("histogramize4(lst)",setup="from __main__ import histogramize4, lst",number=num)
这张照片是:
1.35243415833
10.0806729794
2.89171504974
15.5577590466对于Python 2.7+:
>>> from collections import Counter
>>> counts = Counter([-1,2,3,-1,3,4,4,4,4,4])
>>> counts.viewvalues() # counts.values() in Python 3+
dict_values([1, 2, 5, 2])
(不过,如果您仍使用较旧的版本,则有2.4和2.5版本的实现。)
由于
计数器
是从dict
中派生出来的子类,因此如果需要,您可以获得计数的值counts.viewitems()
(2.7)或counts.items()
(3+)将为您提供一个可匹配的映射。不确定这是否是最简单的解决方案,但您可以使用此oneliner:
import numpy
aa = [-1,2,3,-1,3,4,4,4,4,4]
histogr = [aa.count(i) for i in numpy.unique(aa)]
如果您确实想要numpy解决方案:
>>> a=np.array( [-1,2,3,-1,3,4,4,4,4,4])
>>> ua,uind=np.unique(a,return_inverse=True)
#This returns the unique values and indices of those values.
>>> ua
array([-1, 2, 3, 4])
>>> uind
array([0, 1, 2, 0, 2, 3, 3, 3, 3, 3])
>>> np.bincount(uind)
array([2, 1, 2, 5])
这还有一个额外的好处,即显示什么计数与什么数字相匹配
小型阵列的启动速度要快一倍多一点:
import numpy as np
from collections import Counter
a=np.random.randint(0,100,(500))
alist=a.tolist()
In [27]: %timeit Counter(alist).viewvalues()
1000 loops, best of 3: 209 us per loop
In [28]: %timeit ua,uind=np.unique(a,return_inverse=True);np.bincount(uind)
10000 loops, best of 3: 85.8 us per loop
@JonClements——不过,还有一条皱纹
bincount
需要非负整数。OP需要numpy.bincount(x-x.min())
或类似的东西bincount
还将返回0
以代替任何“跳过”的元素(例如,如果OP的示例中有5个元素代替了4个元素,则返回的结果将是[2,1,2,0,5]
,告诉您没有4个元素)@JoeKington是我在发布后不久才想到的——因此删除了我的评论——但感谢您花时间解释为什么numpy.bincount
并不像人们最初认为的那样是一个显而易见的解决方案;)这是一个危险的想法。。。浮点运算本质上是不精确的,例如2./3..=1. - 1./3.
在我的系统上返回False
。除非所有浮点数都是以完全相同的方式生成的,否则您不能指望两个值实际上是相同的。@Jaimenumpy.round
/numpy.around
/numpy.round
很好地解决了这个问题。@Jaime我同意,谢谢!它确实很短!然而,这将产生二次运行时,因为我相信计数是通过数组上的原始迭代实现的。当已知唯一元素的数量很小时,可能很有用。