在 Python 中使用数组更快的 for 循环

Ove*_*gon 6 python performance for-loop numpy python-3.x

N, M = 1000, 4000000
a = np.random.uniform(0, 1, (N, M))
k = np.random.randint(0, N, (N, M))

out = np.zeros((N, M))
for i in range(N):
    for j in range(M):
        out[k[i, j], j] += a[i, j]
Run Code Online (Sandbox Code Playgroud)

我使用很长的 for 循环;%%timeit在上面pass替换操作产量

1min 19s ± 663 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Run Code Online (Sandbox Code Playgroud)

这在上下文中是不可接受的(C++ 耗时 6.5 秒)。没有理由使用 Python 对象完成上述操作;数组具有明确定义的类型。在 C/C++ 中实现它作为扩展对开发人员和用户端来说都是一种矫枉过正;我只是将数组传递给循环并进行算术运算。

有没有办法告诉 Numpy“将此逻辑移至 C”,或其他可以处理仅涉及数组的嵌套循环的库?我在一般情况下寻求它,而不是针对这个特定示例的解决方法(但如果你有一个,我可以打开一个单独的问答)。

dza*_*ang 5

这基本上是Numba背后的想法。不如 C 快,但可以接近……它使用 jit 编译器将 python 代码编译为机器,并且与大多数 Numpy 函数兼容。(在文档中您可以找到所有详细信息)

import numpy as np
from numba import njit


@njit
def f(N, M):
    a = np.random.uniform(0, 1, (N, M))
    k = np.random.randint(0, N, (N, M))

    out = np.zeros((N, M))
    for i in range(N):
        for j in range(M):
            out[k[i, j], j] += a[i, j]
    return out


def f_python(N, M):
    a = np.random.uniform(0, 1, (N, M))
    k = np.random.randint(0, N, (N, M))

    out = np.zeros((N, M))
    for i in range(N):
        for j in range(M):
            out[k[i, j], j] += a[i, j]
    return out
Run Code Online (Sandbox Code Playgroud)

纯Python:

%%timeit

N, M = 100, 4000
f_python(M, N)
Run Code Online (Sandbox Code Playgroud)

每个循环 338 ms ± 12.6 ms(7 次运行的平均值 ± 标准偏差,每次 1 次循环)

使用 Numba:

%%timeit

N, M = 100, 4000
f(M, N)
Run Code Online (Sandbox Code Playgroud)

每个循环 12 ms ± 534 µs(7 次运行的平均值 ± 标准偏差,每次 100 次循环)