如何有效地操作大型numpy数组

时间:2018-10-26 21:07:40

标签: python numpy

我有一段基于大型numpy数组的代码,然后操作另一个数组。由于这是一个非常大的阵列,请您让我知道是否有一种有效的方法可以实现我的目标? (我认为应该通过直接在数组上而不是通过for循环来实现有效的方法。)

谢谢,请在下面找到我的代码:

N = 1000000000
rand = np.random.rand(N)
beta = np.zeros(N)
for i in range(0, N):
    if rand[i] < 0.5:
        beta[i] = 2.0*rand[i]
    else:
        beta[i] = 1.0/(2.0*(1.0-rand[i]))

3 个答案:

答案 0 :(得分:2)

通过使用Python执行处理,您在这里基本上失去了numpy的效率。 numpy的想法是处理 bulk 中的项目,因为它在C ++中具有执行实际处理工作的高效算法。您可以将numpy的Python结尾更多地视为“接口”。

现在要回答您的问题,我们基本上可以首先将0到2之间的随机数数组乘以2来构成它:

rand = 2.0 * np.random.rand(N)

接下来,我们可以使用类似于条件选择器的np.where(..) [numpy-doc]:我们在这里传递三个“数组”:第一个是布尔数组,用于编码“条件”的真实性,第二个是在相关条件为true时要填充的值数组,第三个值是在条件为false时要插入的值数组,因此我们可以这样写:

N = 1000000000
rand = 2 * np.random.rand(N)
beta = np.where(rand < 1.0, rand, 1.0 / (2.0 - rand))

答案 1 :(得分:2)

N = 1000000000对我造成了MemoryError。最小化为100。 您可以使用np.where routine

在两种情况下,从根本上来说,您都在遍历数组并应用函数。 但是np.where使用了一种更快的循环方式(基本上是编译后的代码),而您的“ python”循环被解释了,因此对于大的N来说确实很慢。

这是一个实现示例。

N = 100
rand = np.random.rand(N)
beta = np.where(rand < 0.5,  2.0 * rand, 1.0/(2.0*(1.0-rand))

答案 2 :(得分:1)

正如其他答案所指出的那样,应该(而且可以)几乎总是避免在Python循环中迭代numpy数组的元素。在大多数情况下,从Python循环到数组操作可以使速度提高约100倍。

但是,如果性能绝对至关重要,那么您通常可以使用Cython来压缩另一个2倍至10倍的因素(以我的经验)。 这是一个示例:

%%cython
cimport numpy as np
import numpy as np
cimport cython
from cython cimport floating

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
cpdef np.ndarray[floating, ndim=1] beta(np.ndarray[floating, ndim=1] arr):
    cdef:
        Py_ssize_t i
        Py_ssize_t N = arr.shape[0]
        np.ndarray[floating, ndim=1] result = np.zeros(N)

    for i in range(N):
        if arr[i] < 0.5:
            result[i] = 2.0*arr[i]
        else:
            result[i] = 1.0/(2.0*(1.0-arr[i]))

    return result

然后您将其称为beta(rand)。 如您所见,这使您可以使用原始的循环结构,但现在可以使用有效的类型化本机代码。与np.where相比,我的速度提高了约2.5倍。

应该注意,在许多情况下,与numpy中的单行代码相比,这不值得付出额外的精力—但这很可能对性能至关重要。