【问题标题】:Python: Timing with numpy and listsPython:使用 numpy 和列表​​计时
【发布时间】:2017-09-28 10:35:45
【问题描述】:

我正在为学校做作业,我应该安排一个集成函数的 python 实现和一个相同的 numpy 实现。我通常希望 numpy 比 python 实现执行得更好,但事实并非如此。与 numpy 数组相比,我在 python 中使用列表理解的速度大约是 4 倍。从 N=1000 到 N=100 000 都是如此。还没有测试过更高的值,因为 N=100 000 是我需要达到的估计误差。

常规python代码:
f 是要积分的函数,a 和 b 是极限,N 是要积分的点数

def integrate(f, a, b, N):
    x_val = [a + (i*b) / N for i in range(N+1)]
    return sum([f(x_val[i]) * (x_val[i] - x_val[i-1]) for i in range(1, len(x_val))])

Numpy 代码:

def numpy_integrate(f, a, b, N):
    x_val = numpy.zeros(N+1)
    x_val[0] = a
    res = 0
    for i in numpy.arange(1, len(x_val)):
        x_val[i] = a + (i*b)/N
        res += f(x_val[i]) * (x_val[i] - x_val[i - 1])

    return res

可能是我的 numpy 实现出现了严重错误,或者在这种规模下,常规的列表理解速度快得多?

【问题讨论】:

  • 在使用 numpy 时不应该使用循环。
  • 好的,那么你将如何重写计算以不使用循环?

标签: python list numpy


【解决方案1】:

首先,您的代码中有一个错误,它只为a=0 提供了正确的结果。您需要将a + (i*b)/N 替换为a + i*(b - a)/N

正如 COLDSPEED 在 cmets 中所说,您没有通过使用 for 循环充分利用 numpy 功能。这是使用数组切片的更高效版本:

def numpy_integrate2(f, a, b, N):
    x_val = a + numpy.arange(N+1)*(b - a)/N
    return (f(x_val[1:]) * (x_val[1:] - x_val[:-1])).sum()

当我使用 square 函数 a = 1、b = 2 和 N = 100000 进行测试时,此版本比您的 intergrate 函数快 50 倍。

编辑:我注意到定义x_val 更快:

x_val = numpy.arange(a, b + (b - a)/N, (b - a)/N)

备注:只有当函数f 可以应用于数组时,此答案才有效。

【讨论】:

    【解决方案2】:

    这有点取决于您的f,如果允许处理数组,那么您可以使用:

    import numpy as np
    
    def integrate(f, a, b, N):
        x_val = a + b / N * np.arange(N+1)
        return (f(x_val[1:]) * np.diff(x_val)).sum()
    

    这是使用矢量化和广播操作来使其(大大)更快。

    如果您的 f 无法按元素处理数组,您应该让它处理数组或者您需要在那里创建另一个数组:

    def integrate(f, a, b, N):
        x_val = a + b / N * np.arange(N+1)
        return (np.array([f(val) for val in x_val[1:].tolist()]) * np.diff(x_val)).sum()
    

    请注意,您还可以使您的列表方法更快。这是因为迭代元素通常比迭代元素更快,并且您不需要对sum 进行列表理解,生成器也可以做到这一点(并且更节省内存):

    from itertools import tee
    
    def pairwise(iterable):  
        # taken from https://docs.python.org/3/library/itertools.html#itertools-recipes 
        a, b = tee(iterable)
        next(b, None)
        return zip(a, b)
    
    def integrate(f, a, b, N):
        x_val = [a + (i*b) / N for i in range(N+1)]
        return sum(f(nxt) * (nxt - prev) for prev, nxt in pairwise(x_val))
    

    【讨论】:

      猜你喜欢
      • 2020-09-06
      • 2020-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多