[英]Why is Python's numpy.polyval() so slow?
更新脚本中存在错误。
我正在研究Julia&Mandelbrot集以及牛顿分形的可视化 - 为此我需要在复杂平面中计算很多值。 我可以使用我想要的任何类型的数学函数,但它足以用于多项式。
我需要计算函数/多项式的导数和值,所以我查看了numpy
模块并找到了numpy.polyder()
和numpy.polyval()
。 它看起来就像我需要的东西,但突然间我的脚本变得很慢。
我试着想一些简单的测试来显示时间上的差异。 为此,我编写了以下脚本:
import numpy as np
import cmath
import time
from itertools import product
C = 0.37 + 0.45j
pol = [1,0,0]
start_time = time.time()
for i in xrange(100000):
C = np.polyval(pol, C)
print "Polyval: {}".format( time.time() - start_time )
print C
C = 0.37 + 0.45j # forgot to reassign the initial value of C
start_time = time.time()
for i in xrange(100000):
C = C**2
print "Standard: {}".format( time.time() - start_time )
print C
基本上这个脚本计算了多项式g(C)= C ** 2 的许多值。 时间结果是(程序的实际输出):
Polyval: 2.34903216362
0j
Standard: 0.0198249816895
0j
我可能没有以最好的方式设置这个测试,第一次做这样的事情。 但即使出现任何错误,运行我的其他脚本也会显示出很大的差异。
有没有办法让它更快? 我理解调用另一个函数是耗时的,但仍然。 我是否应该重新考虑能够仅在一个地方改变多项式系数的优势,以及时间上的劣势? 关于如何处理此类问题的任何其他建议?
本身不是答案,但我写了一个函数polyval_factory
来生成一个mypolyval
函数,给出一个像pol
这样的系数数组。 它以字符串形式生成快速表达式,如C*C + 1.0 * C *C*C + 2.0
,然后将它们装入lambda函数中。 基本上它使用字符串代替完整的符号代数库,如sympy
。 在下面的示例中定义并测试了此函数,其工作速度几乎与C*C
一样快:
import numpy as np
import cmath
import time
from itertools import product
def polyval_factory(pol):
"""
Generate a lambda function for evaluating a given polynomial
pol : a list of coefficients with highest degree first
Note: this function basically uses strings in lieu of a
fully symbolic algebra package like sympy
"""
poly_string_list = []
for i, coeff in enumerate(pol[::-1]):
if np.abs(coeff) > 1e-10:
if i > 1:
poly_string_list.append( repr(coeff) + '*' + '*'.join(['x']*i))
elif i == 1:
poly_string_list.append(repr(coeff)+'*x')
elif i ==0:
poly_string_list.append(repr(coeff))
lambda_str = 'lambda x :' + '+'.join(poly_string_list)
print "The prepared lambda function is: \""+lambda_str + "\""
return eval(lambda_str)
C = 0.37 + 0.45j
pol = [1,0,0]
numiter = 30000
start_time = time.time()
for i in xrange(numiter):
C = np.polyval(pol, C)
print "Polyval: {}".format( time.time() - start_time )
print C
C = 0.37 + 0.45j # forgot to reassign the initial value of C
print ""
print "Generating lambda function..."
mypolyval = polyval_factory(pol) # generate the lambda function
print ""
start_time = time.time()
for i in xrange(numiter):
C = mypolyval(C)
print "Polyval_factory: {}".format( time.time() - start_time )
print C
C = 0.37 + 0.45j # forgot to reassign the initial value of C
print ""
start_time = time.time()
for i in xrange(numiter):
C = C**2
print "Standard: {}".format( time.time() - start_time )
print C
输出是:
Polyval: 0.738290071487
0j
Generating lambda function...
The prepared lambda function is: "lambda x :1*x*x"
Polyval_factory: 0.013610124588
0j
Standard: 0.00678110122681
0j
编辑 : polyval_factory
:现在运行mypolyval = polyval_factory([2.0,3.0,1.0])
做适当的事情并打印:
The prepared lambda function is: "lambda x :1.0+3.0*x+2.0*x*x"
使用Horner方法时乘法顺序的奇怪性占速度的约5倍。 这在numpy 1.10中已修复,或者您可以使用已修复的numpy.polynomial.polynomial.polyval
。 有可能进一步矢量化,例如在numpy.polynomial.polynomial.polyval
版本中使用2d系数数组,但我不清楚你的要求是什么。 另请注意,您可以将多项式直接迭代为p(p)
,但在某些时候我预计会导致数值问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.