假设我有一个随机的numpy数组:
X = np.arange(1000)
和一个门槛:
thresh = 50
我想将X
分成两个分区X_l
和X_r
,使X_l
中的每个元素都小于或等于thresh
在X_r
中,每个元素都大于thresh
。之后,这两个分区被赋予递归函数。
使用numpy我创建一个布尔数组,然后用它来分区X
:
Z = X <= thresh
X_l, X_r = X[Z == 0], X[Z == 1]
recursive_call(X_l, X_r)
这已经好几次了,有没有办法让事情变得更快?是否可以避免在每次调用时创建分区副本?
答案 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 C或Cython ...
这段也可能会做得更好如果你有大小为1000的numpy数组,那么使用Python list / sets / dicts的偶然可能会更快。在阵列非常大之前,NumPy阵列的速度优势有时并不明显。您可能希望用纯Python重写代码,并使用timeit对这两个版本进行基准测试。
嗯,让我重新说一下。它不是真正的数组大小使NumPy更快或更慢。它只是拥有小型NumPy数组,有时候表明你正在创建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