精确的数组直方图

时间:2013-08-02 12:43:12

标签: python numpy

如何获取float数组元素的出现次数? 如果数组是 [-1,2,3-,-1,3,4,4,4,4,4],
结果应该是 [2,1,2,5], 不一定按照这个顺序,并且不需要从计数到计数的元素的映射,只计算重要性。

numpy.histogram会做类似的事情,但它必须使用bin,这需要预先计算bin-size来分隔元素,并且还可以创建不必要的许多空bin。

这也可以使用散列或排序手动完成,但是 似乎应该有一个没有python级循环的快速,一次性的方式。

谢谢!

编辑:

我尝试了撰写本文时提出的解决方案,并认为我会分享结果,因为它们有些出乎意料。 我最初没有提到的是流程使用相当小的列表,但是操作被调用了数百万次,这有点像是一个角落。

测试及其打印输出如下。 histogramize1是我原来的功能,我希望改进它的性能。比第二快的速度快x2,知道原因会很有趣。

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

3 个答案:

答案 0 :(得分:5)

对于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])

http://docs.python.org/library/collections.html#collections.Counter(如果您坚持使用旧版本,则会有2.4和2.5的实现。)

由于Counterdict的子类,因此可以获取您需要时计算的值。 counts.viewitems()(2.7)或counts.items()(3+)将为您提供可迭代的映射。

答案 1 :(得分:4)

如果你想要一个笨拙的解决方案:

>>> 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

答案 2 :(得分:0)

不确定这是否是最优雅的解决方案,但您可以使用这个衬垫:

import numpy
aa = [-1,2,3,-1,3,4,4,4,4,4]
histogr = [aa.count(i) for i in numpy.unique(aa)]