Python numpy高效计算多项式

Python numpy高效计算多项式,python,numpy,performance,polynomials,Python,Numpy,Performance,Polynomials,我试图用numpy计算多项式(3度)。 我发现,使用更简单的python代码将更有效 import numpy as np import timeit m = [3,7,1,2] f = lambda m,x: m[0]*x**3 + m[1]*x**2 + m[2]*x + m[3] np_poly = np.poly1d(m) np_polyval = lambda m,x: np.polyval(m,x) np_pow = lambda m,x: np.power(x,[3,2,1,0

我试图用numpy计算多项式(3度)。 我发现,使用更简单的python代码将更有效

import numpy as np
import timeit

m = [3,7,1,2]

f = lambda m,x: m[0]*x**3 + m[1]*x**2 + m[2]*x + m[3]
np_poly = np.poly1d(m)
np_polyval = lambda m,x: np.polyval(m,x)
np_pow = lambda m,x: np.power(x,[3,2,1,0]).dot(m)

print 'result={}, timeit={}'.format(f(m,12),timeit.Timer('f(m,12)', 'from __main__   import f,m').timeit(10000))
result=6206, timeit=0.0036780834198

print 'result={}, timeit={}'.format(np_poly(12),timeit.Timer('np_poly(12)', 'from __main__ import np_poly').timeit(10000))
result=6206, timeit=0.180546045303

print 'result={}, timeit={}'.format(np_polyval(m,12),timeit.Timer('np_polyval(m,12)', 'from __main__ import np_polyval,m').timeit(10000))
result=6206, timeit=0.227771043777

print 'result={}, timeit={}'.format(np_pow(m,12),timeit.Timer('np_pow(m,12)', 'from __main__ import np_pow,m').timeit(10000))
result=6206, timeit=0.168987989426
我错过什么了吗


numpy中还有其他方法计算多项式吗?

好吧,看看
polyval
的实现(这是在计算poly1d时最终调用的函数),实现者决定包含一个显式循环似乎很奇怪。。。来源于numpy 1.6.2:

def polyval(p, x):
    p = NX.asarray(p)
    if isinstance(x, poly1d):
        y = 0
    else:
        x = NX.asarray(x)
        y = NX.zeros_like(x)
    for i in range(len(p)):
        y = x * y + p[i]
    return y
一方面,避免power操作在速度方面应该是有利的,另一方面,python级别的循环几乎把事情搞砸了

这里有一个替代的numpy-ish实现:

POW = np.arange(100)[::-1]
def g(m, x):
    return np.dot(m, x ** POW[m.size : ])
为了提高速度,我避免在每次调用时重新创建电源阵列。另外,为了公平起见,在对numpy进行基准测试时,您应该从numpy数组开始,而不是从列表开始,以避免每次调用时将列表转换为numpy的惩罚

因此,当添加
m=np.array(m)
时,上面的
g
运行速度仅比
f
慢50%


尽管在您发布的示例中速度较慢,但对于在标量
x
上计算低次多项式,您真的不能比显式实现(如
f
)快很多(当然可以,但如果不编写较低级别的代码,可能不会太快)。但是,对于更高的阶数(必须用某种循环替换显式表达式),numpy方法(例如
g
)会随着阶数的增加而加快,对于矢量化计算也是如此,也就是说,当x是一个向量时。

大约23年前,我从大学图书馆借了一份Press等人的C数字食谱。那本书里有很多很酷的东西,但有一段话多年来一直萦绕在我心头:

我们假设你知道的足够多,永远不会计算这个多项式 方式:

或者(更糟!)

随着(计算机)革命的到来,所有人都被判犯有这种罪行 犯罪行为将被立即执行,他们的程序不会被执行 是然而,是否写作是一个品味的问题

    p = c[0]+x*(c[1]+x*(c[2]+x*(c[3]+x*c[4])));

    p = (((c[4]*x+c[3])*x+c[2])*x+c[1])*x+c[0];
因此,如果你真的担心性能,你想尝试一下,高次多项式的差异将是巨大的:

In [24]: fast_f = lambda m, x: m[3] + x*(m[1] + x*(m[2] + x*m[3]))

In [25]: %timeit f(m, 12)
1000000 loops, best of 3: 478 ns per loop

In [26]: %timeit fast_f(m, 12)
1000000 loops, best of 3: 374 ns per loop
如果您想继续使用numpy,有一个较新的多项式类在我的系统上运行速度比
poly1d
快2倍,但仍然比以前的循环慢得多:

In [27]: np_fast_poly = np.polynomial.polynomial.Polynomial(m[::-1])

In [28]: %timeit np_poly(12)
100000 loops, best of 3: 15.4 us per loop

In [29]: %timeit np_fast_poly(12)
100000 loops, best of 3: 8.01 us per loop

“实现者决定包含显式循环似乎很奇怪”如果您试图在一个块中完成所有操作,可能会导致内存错误?-1 numpy源代码以Horner形式进行评估,这可能不容易矢量化,但远远优于您编写的。(参见这个问题的另一个答案。)+1这被称为or,并对我的一些代码进行了巨大的改进;在很多情况下,霍纳形式也提高了结果的准确性。特别是,一个简单编写的多项式可能会涉及大量的对消,如果项的和远小于项的绝对值之和,则会导致数值错误。在霍纳状态下,这样的取消不会发生。@Mike,还有更好的方法。“对于一大类多项式,多项式求值的标准方法霍纳方法可能非常不准确。这里给出的替代方法平均比霍纳方法准确100到1000倍。”-多项式的准确求值,Sutin 2007
In [24]: fast_f = lambda m, x: m[3] + x*(m[1] + x*(m[2] + x*m[3]))

In [25]: %timeit f(m, 12)
1000000 loops, best of 3: 478 ns per loop

In [26]: %timeit fast_f(m, 12)
1000000 loops, best of 3: 374 ns per loop
In [27]: np_fast_poly = np.polynomial.polynomial.Polynomial(m[::-1])

In [28]: %timeit np_poly(12)
100000 loops, best of 3: 15.4 us per loop

In [29]: %timeit np_fast_poly(12)
100000 loops, best of 3: 8.01 us per loop