我正在使用sympy为数值计算生成一些函数。因此,我将一个表达式lambdify,并将其与numpy数组一起使用。这是一个例子:
import numpy as np
import sympy as sp
def numpy_function():
x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j]
T = (1 - np.cos(2*np.pi*x))*(1 - np.cos(2*np.pi*y))*np.sin(np.pi*z)*0.1
return T
def sympy_function():
x, y, z = sp.Symbol("x"), sp.Symbol("y"), sp.Symbol("z")
T = (1 - sp.cos(2*sp.pi*x))*(1 - sp.cos(2*sp.pi*y))*sp.sin(sp.pi*z)*0.1
lambda_function = np.vectorize(sp.lambdify((x, y, z), T, "numpy"))
x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j]
T = lambda_function(x,y,z)
return T
sympy版本与纯粹numpy版本之间的问题是速度,即
In [3]: timeit test.numpy_function()
100 loops, best of 3: 11.9 ms per loop
VS
In [4]: timeit test.sympy_function()
1 loops, best of 3: 634 ms per loop
那么有没有办法更接近numpy版本的速度? 我认为np.vectorize非常慢,但不知怎的,如果没有它,我的代码中的某些部分就无法运行。感谢您的任何建议。
修改: 所以我找到了为什么vectorize函数是必要的,即:
In [35]: y = np.arange(10)
In [36]: f = sp.lambdify(x,sin(x),"numpy")
In [37]: f(y)
Out[37]:
array([ 0. , 0.84147098, 0.90929743, 0.14112001, -0.7568025 ,
-0.95892427, -0.2794155 , 0.6569866 , 0.98935825, 0.41211849])
然而这似乎工作正常:
In [38]: y = np.arange(10)
In [39]: f = sp.lambdify(x,1,"numpy")
In [40]: f(y)
Out[40]: 1
因此,对于像1
这样的简单表达式,此函数不会返回数组。
有没有办法解决这个问题,这不是某种错误或至少是不一致的设计吗?
答案 0 :(得分:3)
在这种情况下使用np.vectorize()
就像循环x
,y
和z
的第一维,以及它变慢的原因。您不需要np.vectorize()
IF ,您告诉lambdify()
使用NumPy的功能,这正是您正在做的事情。然后,使用:
def sympy_function():
x, y, z = sp.Symbol("x"), sp.Symbol("y"), sp.Symbol("z")
T = (1 - sp.cos(2*sp.pi*x))*(1 - sp.cos(2*sp.pi*y))*sp.sin(sp.pi*z)*0.1
lambda_function = sp.lambdify((x, y, z), T, "numpy")
x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j]
T = lambda_function(x,y,z)
return T
使性能具有可比性:
In [26]: np.allclose(numpy_function(), sympy_function())
Out[26]: True
In [27]: timeit numpy_function()
100 loops, best of 3: 4.08 ms per loop
In [28]: timeit sympy_function()
100 loops, best of 3: 5.52 ms per loop
答案 1 :(得分:3)
lambdify
返回常量的单个值,因为不涉及任何numpy函数。这是因为lambdify
的工作方式(参见https://stackoverflow.com/a/25514007/161801)。
但这通常不是问题,因为常量会在您使用数组的任何操作中自动广播到正确的形状。另一方面,如果您明确使用相同常量的数组,那么效率会低得多,因为您会多次计算相同的操作。