Python 数组的精确直方图

Python 数组的精确直方图,python,numpy,Python,Numpy,如何获取浮点数组元素的出现计数?。 如果数组是 [-1,2,3,-1,3,4,4,4,4], 结果应该是 [2,1,2,5], 不一定按那个顺序,从计数到被计数的元素的映射是不需要的,只是计数很重要 histogram也可以做类似的事情,但它必须使用bins,这需要预先计算bins大小来分离元素,还可能创建不必要的许多空bins 这也可以通过哈希或排序手动完成,但是 似乎应该有一种没有python级循环的快速、一次性方法 谢谢 编辑: 我尝试了在撰写本文时提出的解决方案,并认为我会分享这些结果,

如何获取浮点数组元素的出现计数?。 如果数组是 [-1,2,3,-1,3,4,4,4,4],
结果应该是 [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
。除非所有浮点数都是以完全相同的方式生成的,否则您不能指望两个值实际上是相同的。@Jaime
numpy.round
/
numpy.around
/
numpy.round
很好地解决了这个问题。@Jaime我同意,谢谢!它确实很短!然而,这将产生二次运行时,因为我相信计数是通过数组上的原始迭代实现的。当已知唯一元素的数量很小时,可能很有用。