python - 对于大型数组的手动元素操作,numpy 的更快替代方案?

标签 python arrays performance numpy optimization

我有一些代码最初是用 C 语言(由其他人)使用 C 风格的 malloc 数组编写的。后来我使用 vector<vector<vector<complex>>> 将其中的很多转换为 C++ 风格。数组以与我的项目的其余部分保持一致。我从来没有计时过,但这两种方法的速度似乎差不多。

我最近在 python 中开始了一个新项目,我想使用一些旧代码。不想在项目之间来回移动数据,我决定将这段旧代码移植到 python 中,这样它们就都在一个项目中了。我天真地用 python 语法输入了所有代码,用 numpy 数组替换旧代码中的任何数组(像这样初始化它们 array = np.zeros(list((1024, 1024)), dtype=complex) )。代码工作正常,但速度非常慢。如果非要我猜的话,我会说它慢了大约 1000 倍。

现在调查了一下,我看到很多人说 numpy 对于元素操作来说非常慢。虽然我已经将一些 numpy 函数用于常见的数学运算,例如 FFT 和矩阵乘法,但我的大部分代码都涉及嵌套的 for 循环。其中很多都非常复杂,在我看来似乎无法简化为在 numpy 中更快的简单数组操作。

所以,我想知道是否有比 numpy 更快的替代方法来进行此类计算。理想的情况是有一个我可以导入的模块,它具有很多相同的功能,所以我不必重写我的大部分代码(即,可以以相同的方式执行 FFT 和初始化数组的代码)等),但如果做不到这一点,我会很高兴至少可以将其用于代码中计算要求更高的部分,并根据需要在 numpy 数组之间来回转换。

cpython 数组听起来很有前途,但我见过的很多基准测试并没有显示出足够的速度差异来满足我的目的。为了让您了解我正在谈论的事情,这是减慢我的代码速度的方法之一。这被称为数百万次,并且 vz_at()方法包含一个查找表并进行一些插值以给出最终返回值:

    def tra(self, tr, x, y, z_number, i, scalex, idx, rmax2, rminsq):
        M = 1024
        ixo = int(x[i] / scalex)
        iyo = int(y[i] / scalex)
        nx1 = ixo - idx
        nx2 = ixo + idx
        ny1 = iyo - idx
        ny2 = iyo + idx

        for ix in range(nx1, nx2 + 1):
            rx2 = x[i] - float(ix) * scalex
            rx2 = rx2 * rx2
            ixw = ix
            while ixw < 0:
                ixw = ixw + M
            ixw = ixw % M
            for iy in range(ny1, ny2 + 1):
                rsq = y[i] - float(iy) * scalex
                rsq = rx2 + rsq * rsq
                if rsq <= rmax2:
                    iyw = iy
                    while iyw < 0:
                        iyw = iyw + M
                    iyw = iyw % M
                    if rsq < rminsq:
                        rsq = rminsq
                    vz = P.vz_at(z_number[i], rsq)
                    tr[ixw, iyw] += vz

总共有几千行代码;这只是举个例子的一小段。需要明确的是,我的很多数组都是 1024x1024x1024 或 1024x1024 并且是复值的。其他的是一百万个元素数量级的一维数组。加快这些元素操作的最佳方式是什么?

最佳答案

有关信息,您的一些代码可以变得更简洁,从而更具可读性。例如:

array = np.zeros(list((1024, 1024)), dtype=complex)).

可以写

array = np.zeros((1024, 1024), dtype=complex)

在您试用 Python 时,这至少是一个不错的好处 :-)

现在,对于你的问题,在当前的 Python 科学领域有几种解决方案:

  1. Numba是专用于数组处理的 Python 即时编译器,在 NumPy 达到极限时实现良好的性能。

    优点:只需编写纯 Python,几乎无需修改代码,在许多情况下都表现出良好的性能。 Numba 应该识别一些 NumPy 操作以避免 Numba->Python->NumPy 减速。
    缺点:安装和分发基于 Numba 的代码可能很繁琐。

  2. Cython是 Python 和 C 的混合体,用于生成编译函数。您可以从纯 Python 文件开始,通过类型注释和使用一些“C”-isms 来加速代码。

    优点:稳定、广泛使用、相对容易分发基于 Cython 的代码。
    缺点:需要重写性能关键代码,即使只是部分。

作为额外的提示,Nicolas Rougier(法国科学家)写了一本在线书籍,介绍了许多可以使用 NumPy 加速 Python 代码的情况:http://www.labri.fr/perso/nrougier/from-python-to-numpy/

关于python - 对于大型数组的手动元素操作,numpy 的更快替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45622211/

相关文章:

python - 如何分发具有依赖项的 "statically compiled "Python 应用程序

python - 如何以编程方式区分普通网址和图片网址

java - JAVA 字符数组中的特定元素排列?

java - 如何用Java洗牌?

performance - R 批处理模式下的回显时间戳

c# - 较大的显示器会降低 winforms 应用程序的速度吗?

python - 请求是否依赖于 Selenium ?

python - list1对应list2的元素总和

javascript - VUE | JavaScript : How to access a key as a date format?

mysql - innoDB 上的慢计数 (*)