Python Speedup np.unique

时间:2012-12-03 17:43:06

标签: python performance numpy

我希望加快以下代码:

NNlist=[np.unique(i) for i in NNlist] 

其中NNlist是包含重复条目的np.arrays列表。

谢谢:)

5 个答案:

答案 0 :(得分:2)

numpy.unique已经相当优化,除非您了解基础数据的其他内容,否则您不可能获得超过现有速度的速度。例如,如果数据都是小整数,则可以使用numpy.bincout,或者如果每个数组中的唯一值大致相同,则可能会对整个数组列表进行一些优化。

答案 1 :(得分:0)

以下是一些基准:

In [72]: ar_list = [np.random.randint(0, 100, 1000) for _ in range(100)]

In [73]: %timeit map(np.unique, ar_list)
100 loops, best of 3: 4.9 ms per loop

In [74]: %timeit [np.unique(ar) for ar in ar_list]
100 loops, best of 3: 4.9 ms per loop

In [75]: %timeit [pd.unique(ar) for ar in ar_list] # using pandas
100 loops, best of 3: 2.25 ms per loop

因此pandas.unique似乎比numpy.unique更快。然而,文档字符串提到值是"不一定排序",(部分)解释,它更快。 使用列表推导或map在此示例中没有区别。

答案 2 :(得分:0)

pandas.unique()numpy.unique()快得多。 Pandas版本没有对结果进行排序,但你可以自己做,如果结果比输入小得多(即有很多重复值),它仍然会快得多:

np.sort(pd.unique(arr))

时序:

In [1]: x = np.random.randint(10, 20, 50000000)

In [2]: %timeit np.sort(pd.unique(x))
201 ms ± 9.32 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [3]: %timeit np.unique(x)
1.49 s ± 27.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

答案 3 :(得分:0)

我还研究了list(set())和列表中的字符串,它们在pandas系列和python列表之间。

data = np.random.randint(0,10,100)
data_hex = [str(hex(n)) for n in data] # just some simple strings

sample1 = pd.Series(data, name='data')
sample2 = data.tolist()

sample3 = pd.Series(data_hex, name='data')
sample4 = data_hex

然后是基准:

%timeit np.unique(sample1) # 16.4 µs ± 464 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit np.unique(sample2) # 15.9 µs ± 743 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit np.unique(sample3) # 45.8 µs ± 5.88 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit np.unique(sample4) # 20.6 µs ± 680 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit pd.unique(sample1) # 60.3 µs ± 5.39 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit pd.unique(sample2) # 196 µs ± 18.7 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit pd.unique(sample3) # 79.7 µs ± 3.98 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit pd.unique(sample4) # 214 µs ± 61 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each

%timeit list(set(sample1)) # 16.3 µs ± 1.63 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit list(set(sample2)) # 1.64 µs ± 83.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit list(set(sample3)) # 17.8 µs ± 1.96 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit list(set(sample4)) # 2.48 µs ± 439 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

要害是:

  • 从带有整数的Pandas系列开始?使用np.unique()list(set())

  • 从带有字符串的Pandas系列开始?与list(set())

  • 一起使用
  • 从整数列表开始?与list(set())

  • 一起使用
  • 从字符串列表开始?与list(set())

  • 一起使用

但是,如果N = 1,000,000,结果将有所不同。

%timeit np.unique(sample1) # 26.5 ms ± 616 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.unique(sample2) # 98.1 ms ± 3.64 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit np.unique(sample3) # 1.31 s ± 78.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.unique(sample4) # 174 ms ± 2.57 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit pd.unique(sample1) # 10.5 ms ± 472 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit pd.unique(sample2) # 99.3 ms ± 5.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit pd.unique(sample3) # 46.4 ms ± 4.73 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit pd.unique(sample4) # 113 ms ± 11.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit list(set(sample1)) # 25.9 ms ± 2.11 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit list(set(sample2)) # 11.2 ms ± 496 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit list(set(sample3)) # 37.1 ms ± 1.28 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit list(set(sample4)) # 20.2 ms ± 843 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
  • 从带有整数的Pandas系列开始?与pd.unique()

  • 一起使用
  • 从带有字符串的Pandas系列开始?与list(set())

  • 一起使用
  • 从整数列表开始?与list(set())

  • 一起使用
  • 从字符串列表开始?与list(set())

  • 一起使用

答案 4 :(得分:0)

numpy.unique() 基于排序(quicksort),pandas.unique() 基于哈希表。通常,根据我的基准,后者更快。它们已经非常优化。 对于一些特殊情况,您可以继续优化性能。 例如,如果数据已经排序,则可以跳过排序方法:

# ar is already sorted
# this segment is from source code of numpy
mask = np.empty(ar.shape, dtype=np.bool_)
mask[:1] = True
mask[1:] = ar[1:] != ar[:-1]
ret = ar[mask]

我遇到了和你类似的问题。我编写了 unique 函数供我使用。因为 pandas.unique 不支持 return_counts 选项。这是快速实施。但是我的实现只支持整数数组。您可以查看源代码 here