4

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

X = np.arange(1000)

和一个阈值:

thresh = 50

我想分成X两个分区X_l,并且X_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)

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

4

2 回答 2

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

您是否已分析以确定这确实是您的代码中的瓶颈?如果您的代码仅花费 1% 的时间来执行此拆分操作,那么无论您如何优化此操作,对整体性能的影响都不会超过 1%。

通过重新考虑算法或数据结构,您可能会比优化这一操作受益更多。如果这真的是瓶颈,你也可以通过用 CCython重写这段代码来做得更好......

当您拥有大小为 1000 的 numpy 数组时,使用 Python 列表/集合/字典可能会更快。NumPy 数组的速度优势有时在数组非常大之前不会变得明显。您可能想用纯 Python 重写代码并使用timeit对两个版本进行基准测试。

嗯,让我重新表述一下。真正使 NumPy 更快或更慢的并不是数组的大小。只是拥有小的 NumPy 数组有时表明您正在创建许多小的 NumPy 数组,并且创建 NumPy 数组比创建 Python 列表要慢得多:

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 等效项的字典和集合。这可能会导致您使用更快的替代算法。

于 2013-09-25T12:02:40.363 回答
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
于 2013-09-25T13:48:58.657 回答