更快速地根据阈值拆分numpy数组

时间:2013-09-25 11:50:07

标签: python arrays numpy

假设我有一个随机的numpy数组:

X = np.arange(1000)

和一个门槛:

thresh = 50

我想将X分成两个分区X_lX_r,使X_l中的每个元素都小于或等于threshX_r中,每个元素都大于thresh。之后,这两个分区被赋予递归函数。

使用numpy我创建一个布尔数组,然后用它来分区X

Z = X <= thresh
X_l, X_r = X[Z == 0], X[Z == 1]
recursive_call(X_l, X_r)

这已经好几次了,有没有办法让事情变得更快?是否可以避免在每次调用时创建分区副本?

2 个答案:

答案 0 :(得分:7)

X[~Z]X[Z==0]

In [13]: import numpy as np

In [14]: X = np.random.random_integers(0, 1000, size=1000)

In [15]: thresh = 50

In [18]: Z = X <= thresh

In [19]: %timeit X_l, X_r = X[Z == 0], X[Z == 1]
10000 loops, best of 3: 23.9 us per loop

In [20]: %timeit X_l, X_r = X[~Z], X[Z]
100000 loops, best of 3: 16.4 us per loop

您是否profiled确定这确实是代码中的瓶颈?如果您的代码仅花费1%的时间进行此拆分操作,那么优化此操作的程度将对整体性能产生不超过1%的影响。

通过重新思考算法或数据结构而不是优化这一操作,您可能会受益更多。如果这确实是瓶颈,那么通过重写code in CCython ...

这段也可能会做得更好

如果你有大小为1000的numpy数组,那么使用Python list / sets / dicts的偶然可能会更快。在阵列非常大之前,NumPy阵列的速度优势有时并不明显。您可能希望用纯Python重写代码,并使用timeit对这两个版本进行基准测试。

嗯,让我重新说一下。它不是真正的数组大小使NumPy更快或更慢。它只是拥有小型NumPy数组,有时候表明你正在创建 小型NumPy数组,并且创建NumPy数组要比创建Python列表慢得多:< / p>
In [21]: %timeit np.array([])
100000 loops, best of 3: 4.31 us per loop

In [22]: %timeit []
10000000 loops, best of 3: 29.5 ns per loop

In [23]: 4310/295.
Out[23]: 14.610169491525424

此外,当您使用纯Python编码时,您可能更有可能使用没有直接NumPy等效项的dicts和集合。这可能会导致您使用更快的替代算法。

答案 1 :(得分:1)

您的阵列是否已经排序?在您的示例中,您使用已排序的arange,因此无需进行布尔索引,您只需在适当的位置将数组切成两半即可。这样可以避免使用“高级索引”,因此您无需复制数组。

X = np.arange(0, 2*thresh)
i = X.searchsorted(thresh, side='right') # side='right' for `<=`
X_l, X_r = X[:i], X[i:]

这为排序的数组节省了大量时间,但显然不会起作用:

thresh = 500
X = np.arange(2*thresh)

%%timeit
i = X.searchsorted(thresh, side='right')
X_l, X_r = X[:i], X[i:]
100000 loops, best of 3: 5.16 µs per loop

%%timeit
Z = X <= thresh                         
X_l, X_r = X[Z], X[~Z]
100000 loops, best of 3: 12.1 µs per loop