【问题标题】:Vectorize too slow in python? Or is it quad.integrate? Or is it my code?在 python 中矢量化太慢?还是quad.integrate?还是我的代码?
【发布时间】:2020-06-09 17:54:32
【问题描述】:

我是社区的新手,如果我没有按预期提供信息,请原谅我。

我正在尝试学习 python,来自 Matlab。我有一个非常简单的代码用于启动目的:

from numpy import vectorize
from scipy import integrate
from scipy.special import j1
from math import sqrt, exp, pi, log
import matplotlib.pyplot as plt
import numpy as np



def plot_hc(radius, pd):
    q = np.linspace(0.008, 1.0, num=500)
    y = hc(q, radius, pd)
    plt.loglog(q, y)
    plt.show()

def hc_formfactor(q, radius):
    y = (1.0 / q) * (radius * j1(q * radius))
    y = y ** 2
    return y

def g_distribution(z, radius, pd):
    return (1 / (sqrt(2 * pi) * pd)) * exp(
        -((z - radius) / (sqrt(
            2) * pd)) ** 2)


def ln_distribution(z, radius, pd):
    return (1 / (sqrt(2 * pi) * pd * z / radius)) * exp(
        -(log(z / radius) / (sqrt(2) * pd)) ** 2)

# Dist=1(for G_Distribution)
# Dist=2(for LN Distribution)
Dist = 1


@vectorize
def hc(x, radius, pd):
    global d
    if Dist == 1:
        nmpts = 4
        va = radius - nmpts * pd
        vb = radius + nmpts * pd
        if va < 0:
             va = 0
        d = integrate.quad(lambda z: g_distribution(z, radius, pd), va, vb)
    elif Dist == 2:
        nmpts = 4
        va = radius - nmpts * pd
        vb = radius + nmpts * pd
        if va < 0:
            va = 0
        d = integrate.quad(lambda z: ln_distribution(z, radius, pd), va, vb)
    else:
       d = 1

   def fun(z, x, radius, pd):
        if Dist == 1:
            return hc_formfactor(x, z) * g_distribution(z, radius, pd)
        elif Dist == 2:
            return hc_formfactor(x, z) * ln_distribution(z, radius, pd)
        else:
            return hc_formfactor(x, z)

    y = integrate.quad(lambda z: fun(z, x, radius, pd), va, vb)[0]
    return y/d[0]

if __name__ == '__main__':
plot_hc(radius=40, pd=0.5)

正如一些人所建议的,我应该使用 for 循环,但这会进一步降低速度。使用for循环的代码如下:

from numpy import vectorize
from scipy import integrate
from scipy.special import j1
from math import sqrt, exp, pi, log
import matplotlib.pyplot as plt
import numpy as np



def plot_hc(radius, pd):
    q = np.linspace(0.008, 1.0, num=500)
    y = hc(q, radius, pd)
    plt.loglog(q, y)
    plt.show()

def hc_formfactor(q, radius):
    y = (1.0 / q) * (radius * j1(q * radius))
    y = y ** 2
    return y

def g_distribution(z, radius, pd):
    return (1 / (sqrt(2 * pi) * pd)) * exp(
        -((z - radius) / (sqrt(
            2) * pd)) ** 2)


def ln_distribution(z, radius, pd):
    return (1 / (sqrt(2 * pi) * pd * z / radius)) * exp(
        -(log(z / radius) / (sqrt(2) * pd)) ** 2)

# Dist=1(for G_Distribution)
# Dist=2(for LN Distribution)
Dist = 1


def hc(q, radius, pd):
    if Dist == 1:
        nmpts = 4
        va = radius - nmpts * pd
        vb = radius + nmpts * pd
        if va < 0:
            va = 0
        d = integrate.quad(lambda z: g_distribution(z, radius, pd), va,vb)
    elif Dist == 2:
        nmpts = 4
        va = radius - nmpts * pd
        vb = radius + nmpts * pd
        if va < 0:
            va = 0
        d = integrate.quad(lambda z: ln_distribution(z, radius, pd), va, vb)
    else:
        d = 1

    def fun(z, q, radius, pd):
        if Dist == 1:
            return hc_formfactor(q, z) * g_distribution(z, radius, pd)
        elif Dist == 2:
            return hc_formfactor(q, z) * ln_distribution(z, radius, pd)
        else:
            return hc_formfactor(q, z)

    y = empty([len(q)])
    for n in range(len(q)):
        y[n] = integrate.quad(lambda z: fun(z, q[n], radius, pd), va, vb)[0]

    return y / d[0]
if __name__ == '__main__':
plot_hc(radius=40, pd=0.5)

如果我在 Matlab 中为相同的值运行相同的程序,它会非常非常快。我不知道我在这里犯了什么错误。请帮忙:)

【问题讨论】:

  • 慢是什么意思?
  • 您没有阅读documentation 吗?它明确指出“提供矢量化功能主要是为了方便,而不是为了性能。实现本质上是一个 for 循环。”
  • 非常感谢@juanpa.arrivillaga 的回复。我之前确实阅读过文档,但问题是当我使用 for 循环时它变得更慢。这就是我使用矢量化的唯一原因,如代码所示。我已经编辑了我的问题以使用 for 循环发布代码。我可能犯了一个错误。
  • @EdekiOkoh,我所说的慢是指与其他程序相比,评估函数所花费的时间更多:)
  • 您可以使用 Numba 来加速您的功能(很容易做到,但调用开销保持不变)或使用 cfunc(可以用 C、Cython、Numba 等编写),例如。 stackoverflow.com/a/49732825/4045774

标签: python matlab scipy vectorization integration


【解决方案1】:

注意事项

提供vectorize 函数主要是为了方便,而不是为了 表现。该实现本质上是一个 for 循环。

MATLAB 具有 jit 编译能力,numpy 没有(numba 提供了一些)。要获得最佳的numpy 速度,您需要考虑整个数组操作,就像我们在过去的 MATLAB 时代一样。

【讨论】:

  • 非常感谢您的回复。如上所述,我使用了 for 循环,它进一步降低了速度。也许我错误地实现了它。请看看是不是这样。也非常感谢您将我指向 jit。我会更多地了解它:)
  • 根据我的经验,vectorize 总是比等效循环慢。在这里,您循环位于hc 的深处,评估quad(仅评估标量函数)。但是你vectorize 全部hc,有效地围绕一个更大的计算循环。你确定它们是等价的吗?
猜你喜欢
  • 2021-10-30
  • 2013-07-02
  • 1970-01-01
  • 2023-03-12
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
  • 2010-10-31
  • 2019-09-16
相关资源
最近更新 更多