简体   繁体   English

numpy有效地计算多项式

[英]numpy calculate polynom efficiently

I'm trying to evaluate polynomial (3'd degree) using numpy. 我正在尝试使用numpy来评估多项式(3度)。 I found that doing it by simpler python code will be much more efficient. 我发现通过更简单的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

Did I miss something? 我错过了什么?

Is there another way in numpy to evaluate a polynomial? numpy中还有另一种评估多项式的​​方法吗?

Something like 23 years ago I checked out a copy of Press et al Numerical Recipes in C from the university's library. 像23年前的事情,我从大学的图书馆查看了一份Press et al Numerical Recipes in C的副本。 There was a lot of cool stuff in that book, but there's a passage that has stuck with me over the years, page 173 here : 那本书中有很多很酷的东西,但这里有一段多年来一直困扰着我的文章, 第173页

We assume that you know enough never to evaluate a polynomial this way: 我们假设你知道永远不会以这种方式评估多项式:

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

or (even worse!), 或者(甚至更糟!),

  p=c[0]+c[1]*x+c[2]*pow(x,2.0)+c[3]*pow(x,3.0)+c[4]*pow(x,4.0); 

Come the (computer) revolution, all persons found guilty of such criminal behavior will be summarily executed, and their programs won't be! 来(计算机)革命,所有被认定犯有此类犯罪行为的人将被即决处决,他们的计划将不会! It is a matter of taste, however, whether to write 然而,这是一个品味问题,是否写作

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

or 要么

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

So if you are really worried about performance, you want to try that, the differences will be huge for higher degree polynomials: 因此,如果您真的担心性能,那么您希望尝试这一点,对于更高次多项式,差异将是巨大的:

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

If you want to stick with numpy, there is a newer polynomial class that runs 2x faster than poly1d on my system, but is still much slower than the previous loops: 如果你想坚持numpy,有一个更新的多项式poly1d我的系统上的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

Well, looking at the implementation of polyval (which is the function eventually being called when you eval a poly1d), it seems weird the implementor decided to include an explicit loop... From the source of numpy 1.6.2: 那么,看看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

On one hand, avoiding the power operation should be advantageous speed-wise, on the other hand, the python-level loop pretty much screws things up. 一方面,避免电源操作应该是速度方面的优势,另一方面,python级别的循环几乎搞砸了。

Here's an alternative numpy-ish implemenation: 这是一个替代的numpy-ish实现:

POW = np.arange(100)[::-1]
def g(m, x):
    return np.dot(m, x ** POW[m.size : ])

For speed, I avoid recreating the power array on each call. 为了提高速度,我避免在每次通话时重新创建电源阵列。 Also, to be fair when benchmarking against numpy, you should start with numpy arrays, not lists, to avoid the penalty of converting the list to numpy on each call. 另外,为了公平地对numpy进行基准测试时,你应该从numpy数组开始,而不是列表,以避免在每次调用时将列表转换为numpy的惩罚。

So, when adding m = np.array(m) , my g above only runs about 50% slower than your f . 因此,当添加m = np.array(m) ,我的g仅比你的f慢约50%。

Despite being slower on the example you posted, for evaluating a low-degree polynomial on a scalar x , you really can't do much faster than an explict implemenation (like your f ) (of course you can , but probably not by much without resorting to writing lower-level code). 尽管你发布的例子比较慢,但是为了评估标量x上的低次多项式,你真的不能比一个明确的实现(比如你的f )快得多(当然你可以 ,但可能没那么多没有求助于编写低级代码)。 However, for higher degrees (where you have to replace you explict expression with some sort of a loop), the numpy approach (eg g ) would prove much faster as the degree increases, and also for vectorized evaluation, ie when x is a vector. 然而,对于更高的度数(你必须用某种循环替换你的explict表达式),numpy方法(例如g )随着度数的增加会更快,并且对于矢量化评估也是如此,即当x是向量时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM