为什么Python的numpy.polyval()这么慢?

qua*_*pka 6 python numpy

更新脚本中存在错误.

我正在研究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
Run Code Online (Sandbox Code Playgroud)

基本上这个脚本计算多项式g(C)= C**2 的许多值.时间结果是(程序的实际输出):

Polyval: 2.34903216362
0j
Standard: 0.0198249816895
0j
Run Code Online (Sandbox Code Playgroud)

我可能没有以最好的方式设置这个测试,第一次做这样的事情.但即使出现任何错误,运行我的其他脚本也会显示出很大的差异.

有没有办法让它更快?我理解调用另一个函数是耗时的,但仍然.我是否应该重新考虑能够仅在一个地方改变多项式系数以及时间上的劣势的优势?关于如何处理此类问题的任何其他建议?

nbr*_*n12 2

本身不是答案,但我编写了一个函数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
Run Code Online (Sandbox Code Playgroud)

输出是:

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
Run Code Online (Sandbox Code Playgroud)

编辑: 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"
Run Code Online (Sandbox Code Playgroud)