Python numpy.unique与collections.计数器性能问题

Python numpy.unique与collections.计数器性能问题,python,numpy,Python,Numpy,我试图计算成对值的出现次数。运行以下代码时,numpy版本(pairs_frequency2)比依赖collections.Counter的版本慢50%以上(点数增加时会变得更糟)。有人能解释一下原因吗 是否有可能进行numpy重写以获得更好的性能 提前谢谢 import numpy as np from collections import Counter def pairs_frequency(x, y): counts = Counter(zip(x, y)) res =

我试图计算成对值的出现次数。运行以下代码时,numpy版本(pairs_frequency2)比依赖collections.Counter的版本慢50%以上(点数增加时会变得更糟)。有人能解释一下原因吗

是否有可能进行numpy重写以获得更好的性能

提前谢谢

import numpy as np
from collections import Counter

def pairs_frequency(x, y):
    counts = Counter(zip(x, y))
    res = np.array([[f, a, b] for ((a, b), f) in counts.items()])
    return res[:, 0], res[:, 1], res[:, 2]

def pairs_frequency2(x, y):
    unique, counts = np.unique(np.column_stack((x,y)), axis=0, return_counts=True)
    return counts, unique[:,0], unique[:,1]


x = np.random.randint(low=1, high=11, size=50000)
y = x + np.random.randint(1, 5, size=x.size)

%timeit pairs_frequency(x, y)

%timeit pairs_frequency2(x, y)

numpy.unique
对其参数进行排序,因此其时间复杂度为O(n*log(n))。看起来
计数器
类可能是O(n)

如果数组中的值是不太大的非负整数,则此版本非常快:

def pairs_frequency3(x, y, maxval=15):
    z = maxval*x + y
    counts = np.bincount(z)
    pos = counts.nonzero()[0]
    ux, uy = np.divmod(pos, maxval)
    return counts[pos], ux, uy
maxval
设置为1加上
x
y
中的最大值。(您可以删除参数,并添加代码以查找函数中的最大值。)

计时(
x
y
如问题中所述生成):

注意第三个结果的时间单位的变化

pairs\u frequency3
以与
pairs\u frequency2
相同的顺序返回数组,因此很容易验证它们是否返回相同的值:

In [26]: counts2, x2, y2 = pairs_frequency2(x, y)

In [27]: counts3, x3, y3 = pairs_frequency3(x, y)

In [28]: np.all(counts2 == counts3) and np.all(x2 == x3) and np.all(y2 == y3)
Out[28]: True

我无法复制您的计时:
%timeit pairs\u频率(x,y)39.3 ms±1.96 ms/循环(平均±标准偏差为7次运行,每个循环10次)
%timeit pairs\u频率2(x,y)15.6 ms±200µs/循环(平均±标准偏差为7次运行,每个循环100次)
numpy
对我来说仍然以2个数量级的优势获胜。不过,可能有更好的方法,我得到的结果与Gael的类似,使用Python3.6.4和Numpy1.15.2.0。我在3.6.3,numpy 1.13.3。我不确定它在这段代码中是否重要,但它是在Windows 7上用MKL编译的,谢谢,我曾尝试过对pairs_frequency3使用类似的解决方案,但担心np.bincount返回的数组的大小,如果x和y中的值不限于小的数字,那么数组的大小可能会变得非常大:乘法z可能会变得非常大。是的,这就是为什么我添加了一个关于值不可用的模糊限定符“太大了”。)
In [26]: counts2, x2, y2 = pairs_frequency2(x, y)

In [27]: counts3, x3, y3 = pairs_frequency3(x, y)

In [28]: np.all(counts2 == counts3) and np.all(x2 == x3) and np.all(y2 == y3)
Out[28]: True