Python numpy性能-超大阵列上的选择

Python numpy性能-超大阵列上的选择,python,arrays,performance,numpy,indexing,Python,Arrays,Performance,Numpy,Indexing,我正在尝试优化一些代码,其中一个耗时的操作如下: import numpy as np survivors = np.where(a > 0)[0] pos = len(survivors) a[:pos] = a[survivors] b[:pos] = b[survivors] c[:pos] = c[survivors] 在我的代码中,是一个非常大(超过100000个)的浮点数组。他们中的许多人将是0 有什么方法可以加快速度吗?在我看来,没有任何东西可以用纯NumPy来加快速度。但

我正在尝试优化一些代码,其中一个耗时的操作如下:

import numpy as np
survivors = np.where(a > 0)[0]
pos = len(survivors)
a[:pos] = a[survivors]
b[:pos] = b[survivors]
c[:pos] = c[survivors]
在我的代码中,是一个非常大(超过100000个)的浮点数组。他们中的许多人将是0


有什么方法可以加快速度吗?

在我看来,没有任何东西可以用纯NumPy来加快速度。但是,如果您有numba,您可以使用jitted函数编写此“选择”的自己版本:

import numba as nb

@nb.njit
def selection(a, b, c):
    insert_idx = 0
    for idx, item in enumerate(a):
        if item > 0:
            a[insert_idx] = a[idx]
            b[insert_idx] = b[idx]
            c[insert_idx] = c[idx]
            insert_idx += 1
在我的测试运行中,这大约比NumPy代码快2倍。但是,如果您不使用
conda
,numba可能是一个严重的依赖项

例子: 时间: 很难准确地计算时间,因为所有方法都在适当的位置工作,所以我实际上使用
number=1
来测量计时(这避免了由于解决方案的适当性而导致计时中断)我使用了所产生的计时列表的
min
,因为这在文档中被宣传为最有用的定量度量:

注 从结果向量中计算平均值和标准偏差并报告它们是很有诱惑力的。然而,这不是很有用。在典型情况下,最低值给出了机器运行给定代码段的速度下限;结果向量中较高的值通常不是由Python速度的变化引起的,而是由干扰计时精度的其他进程引起的。因此,结果的min()可能是您应该感兴趣的唯一数字。之后,您应该查看整个向量并应用常识而不是统计数据

努巴溶液 0.007700118746939211

原液 0.028622144571883723

Alexander McFarlane的解决方案(现已删除) 0.058305527038669425


因此,Numba解决方案实际上可以将速度提高3-4倍,而Alexander McFarlane的解决方案实际上比原始方法慢(2倍)。然而,少量的
repeat
s可能会在一定程度上影响计时。

什么是
b
c
您使用的是
a=0是否为它们编制索引?是。因此,a、b和c代表同一对象的不同特征。然后我想选择a>0的对象,并得到一个新的a、b和c,其中只有这个对象
a[:pos]
意味着
a[pos:
之后的所有内容都是未使用的,同样的
b
c
这是真的吗?这是一种遗传算法吗?你想把幸存者留到下一代吗?没错。从哪里开始,我只关心
a[:pos]
,而不是整个a。顺便问一下,我如何在注释中生成内联代码?因此
a
必须保持其原始形状?@AlexanderMcFarlane我不太确定您的方法是否正确。我根本无法解释矢量化numpy运算的1000倍加速。我想如果避免使用临时数组或使用更高效的操作,您可以期望的速度限制是2-5倍。我现在要测试它,但是如果“a”、“b”和“c”是其他数组上的视图,您的解决方案是否有效?它们会根据我的需要进行修改吗?顺便说一句,我一直在测试代码的其他瓶颈,特别是numpy数组的操作(相同的形状、求和、除法、获取数组和),发现它比原始numpy代码慢。。。有什么一般建议吗?是的,它将在视图上工作(您可以通过运行
选择(a[0:2],b,c)
而不是
选择(a,b,c)来验证这一点)
在我的示例中。@MSeifert感谢您研究我的方法!在您的帮助下,我了解了一点
%%timeit
magic命令的弱点-我将删除我的解决方案,因为它将彻底迷惑正在查看它的人-请在您的答案中加入它,作为解决问题的方法avoid@DiogoSantos很难给他基因ral关于numba性能的指南。重击的一个规则是:自己编写所有循环,并尽量避免在numba函数中调用“复杂”的numpy函数(例如,高级索引或创建临时数组的操作)。然后还有不同的方法来迭代numpy数组,有时对数组中的元素使用
或对范围内的idx(len(array))使用
甚至对np.nditer(array)中的元素使用
会更快
。要获得最快的numba函数,必须进行一些试验,有时最快的方法取决于numba版本。
>>> import numpy as np
>>> a = np.array([0., 1., 2., 0.])
>>> b = np.array([1., 2., 3., 4.])
>>> c = np.array([1., 2., 3., 4.])
>>> selection(a, b, c)
>>> a, b, c
(array([ 1.,  2.,  2.,  0.]),
 array([ 2.,  3.,  3.,  4.]),
 array([ 2.,  3.,  3.,  4.]))
import timeit

min(timeit.repeat("""selection(a, b, c)""",
              """import numpy as np
from __main__ import selection

a = np.arange(1000000) % 3
b = a.copy()
c = a.copy()
""", repeat=100, number=1))
import timeit

min(timeit.repeat("""survivors = np.where(a > 0)[0]
pos = len(survivors)
a[:pos] = a[survivors]
b[:pos] = b[survivors]
c[:pos] = c[survivors]""",
              """import numpy as np
a = np.arange(1000000) % 3
b = a.copy()
c = a.copy()
""", repeat=100, number=1))
import timeit

min(timeit.repeat("""survivors = comb_array[:, 0].nonzero()[0]
comb_array[:len(survivors)] = comb_array[survivors]""",
              """import numpy as np
a = np.arange(1000000) % 3
b = a.copy()
c = a.copy()

comb_array = np.vstack([a,b,c]).T""", repeat=100, number=1))