我可以用lambdify来计算python函数的导数吗?

2024-10-01 17:34:05 发布

您现在位置:Python中文网/ 问答频道 /正文

I asked a question yesterday关于区分一个python函数,然后当我发现发布的答案中没有一个能满足我求值(在某些变量中)并绘制导数的需求时,我就能够找到自己的解决方案。在

先前代码:

import sympy as sym
import math


def f(x,y):
    return x**2 + x*y**2


x, y = sym.symbols('x y')

def fprime(x,y):
    return sym.diff(f(x,y),x)

print(fprime(x,y)) #This works.

print(fprime(1,1)) 

新代码:

^{pr2}$

如您所见,我创建了一个新函数DerivativeOfF,它是fprime的“lambdified”版本,克服了无法计算导数fprime的问题。从那里,我可以计算导数off,也可以在其中一个变量中绘制它。在

My question is: why did this work? What exactly have I done? And what are some downsides to this method? I have tried reading the lambdify documentation but it's extremely confusing to me (I'm a beginner in Python). My guess is that I converted the Python function fprime to a Sympy expression DerivativeOfF, or something like that. Any help explaining what happened and why, and what exactly lambdify does (in layman's terms), would be appreciated.


Tags: to函数代码importreturnmydef绘制
3条回答

如果要将SymPy表达式转换为可以数值计算的函数,则应使用lambdify。由于您在这里的兴趣是进行符号计算(微分),所以不应该使用lambdify(无论如何,在计算的这一点上)。在

问题出在这个代码上

x, y = sym.symbols('x y')

def fprime(x,y):
    return sym.diff(f(x,y),x)

当您将变量名设置为函数时,如“def fprime(xy)”,这些变量名会有效地覆盖函数上方为函数内的任何代码定义的x和{}的变量名。因此,代码sym.diff(f(x,y),x)不会对从symbols('x y')返回的符号对象进行操作,而是对传入fprime的任何值进行操作。当然,如果你把这些对象作为参数传入,它将是相同的,但是你可以传入任何东西。对于f(x, y),它是完全相同的。在

相反,我会完全避免使用函数。相反,创建两个符号表达式。在

^{pr2}$

现在,要对fprime求值,可以使用subs。在

fprime.subs({x: 1, y: 1})

如果此时要创建一个快速函数,该函数使用NumPy将表达式求值为一个数字或一个数字数组,则可以在此处使用lambdify。在

f = lambdify((x, y), expr, 'numpy')
import numpy as np
f(np.array([1]), np.array([2]))

(另外,作为一般规则,如果lambdify一个带有'numpy'的表达式,则应该将NumPy数组作为lambdified函数的参数传入)

在您的示例中,sym.lambdify创建了一个python函数,它看起来像

def DerivativeOff(x,y):
    return 2*x + y**2

这里的numpy后端不起任何作用,因为乘法、加法和乘幂都是python的原始函数。因此,您可以将任何参数传递给DerivativeOff,尤其是sympy符号。在代码末尾尝试DeravativeOff(x,y)。在

现在,如果函数包含python本身无法处理的更复杂的表达式,情况就会发生变化。以下面的例子为例:

^{pr2}$

在本例中,lambdify需要用一些非标准python替换sin函数。为此,它将求助于numpy(您为本例指定了“numpy”)。因此,DerivateOff2看起来像

def DerivativeOff2(x,y):
    return numpy.cos(x)*y

很明显,纽比不能处理交响乐符号。。。在

现在如果您只想绘图,sympy有一些绘图模块(依赖matplotlib):http://docs.sympy.org/latest/modules/plotting.html

你甚至可以用它来制作3d绘图。在

编辑: 以下方法也能起作用:

import sympy as sym
def f(x,y):
    return sym.sin(x) + x*sym.sin(y)
def fprime(x,y):
    return sym.diff(f(x,y),y)
x, y = sym.symbols('x y')
print(fprime(1,y)) #works perfectly fine
print(fprime(x,1)) #does not work because it would mean to derive with respect to 1
print(fprime(x,y).subs(y,1)) #works, derives with respect to y, then substitutes 1 for y

让我们看看我能不能举例说明这个动作。我对Python和numpy很熟悉,但是没有用过sympy(但是使用过其他符号代数包,比如macsyma)。在

在ipython numpy会话中:

In [1]: def f(x,y):
   ...:     return x**2 + x*y**2
   ...: 
In [2]: f(1,3)
Out[2]: 10
In [3]: f(np.arange(1,4), np.arange(10,13))
Out[3]: array([101, 246, 441])

f是一个python函数;它返回什么取决于输入如何处理***和{}等操作。标量和数组有效。列出句柄+*(连接、复制),但不列出**。在

^{pr2}$

定义symbols将创建两个新对象。它们以自己的符号方式处理+等。在

In [9]: fsym = f(x,y)
In [10]: type(fsym)
Out[10]: sympy.core.add.Add
In [11]: print(fsym)
x**2 + x*y**2

用这两个符号对象调用f将创建一个新的sym对象。我也可以用其他符号和数字甚至数组的组合来调用它。在

In [12]: f(x,0)
Out[12]: x**2
In [13]: f(1,x)
Out[13]: x**2 + 1
In [14]: f(np.arange(3), x)
Out[14]: array([0, x**2 + 1, 2*x**2 + 4], dtype=object)

如果我把这个Add对象传递给sym.diff,我得到一个新的Add对象

In [15]: fprime = sym.diff(fsym,x)
In [16]: fprime
Out[16]: 2*x + y**2

fsym和{}都不可调用。它们不是Python函数。fsym(1,2)不工作。在

但是fsym.subs可用于将x或/和{}替换为其他值,无论是数字还是其他符号:

In [19]: fsym.subs(x,1)
Out[19]: y**2 + 1
In [20]: fsym.subs(y,2*x)
Out[20]: 4*x**3 + x**2
In [21]: fsym.subs([(x,1),(y,2)])
Out[21]: 5
In [22]: fprime.subs([(x,1),(y,2)])
Out[22]: 6

lambdify是一个sympy函数,它接受一个sympy对象并返回一个Python函数,可能与numpy兼容`。在

In [24]: fl = sym.lambdify((x,y), fsym, "numpy")
In [25]: fl
Out[25]: <function numpy.<lambda>>
In [26]: fl(1,2)
Out[26]: 5
In [27]: fl(np.arange(1,4), np.arange(10,13))   # cf with f(same) above
Out[27]: array([101, 246, 441])

这个fl函数与原始的f相似。它不完全相同,例如它有一个help/doc表达式。在

应用于lambdifylambdify执行相同的操作,但使用了不同的符号表达式:

In [28]: fpl = sym.lambdify((x,y), fprime, "numpy")
In [29]: fpl(1,2)
Out[29]: 6
In [30]: fpl(np.arange(1,4), np.arange(10,13))
Out[30]: array([102, 125, 150])

python/numpy函数或表达式与sympy函数或表达式之间的这种透明性是有限度的。另一个(删除的)答案试图探究这些问题。例如,math.sinnumpy.sin和{}之间有区别。在

在这些例子中,微分是由sym.diff函数象征性地完成的。在

In [35]: fsym
Out[35]: x**2 + x*y**2
In [36]: fprime
Out[36]: 2*x + y**2

sym.lambdify只是将这些sympy对象之一转换为Python函数的一种方法。在

trig示例

从讨论中找出另一个答案

定义使用sym版本sin/cos的函数:

In [53]: def f1(x,y):
    ...:     return sym.sin(x) + x*sym.sin(y)
    ...: 
In [54]: f1(x,y)
Out[54]: x*sin(y) + sin(x)
In [55]: f1(1,2)
Out[55]: sin(1) + sin(2)
In [56]: f1(1, np.arange(3)
...
SympifyError: Sympify of expression 'could not parse '[0 1 2]'' failed, because of exception being raised:
SyntaxError: invalid syntax (<string>, line 1)

我认为这是因为sym.sin(<array>)不起作用;它必须是np.sin(...),但这对符号无效。在

我们可以用符号导数:

In [57]: sym.diff(f1(x,y),x)
Out[57]: sin(y) + cos(x)
In [58]: sym.diff(f1(x,y),y)
Out[58]: x*cos(y)
In [59]: sym.diff(sym.diff(f1(x,y),x),y)
Out[59]: cos(y)

再说一遍,这些a函数都没有。必须使用subs或{}进行评估。在

In [60]: f2 = sym.lambdify((x,y),f1(x,y),"numpy")
In [61]: f2
Out[61]: <function numpy.<lambda>>
In [62]: f2(1, np.arange(3))
Out[62]: array([ 0.84147098,  1.68294197,  1.75076841])

我可以用数组输入计算f2,而我不能用f1。推测sympynp.sin代替{}。在

事实上,当我试图用一个符号来计算f2时,numpy会抱怨:

In [63]: f2(1,y)
...
/usr/local/lib/python3.5/dist-packages/numpy/__init__.py in <lambda>(_Dummy_30, _Dummy_31)
AttributeError: 'Symbol' object has no attribute 'sin'

In [66]: sym.diff(f2(x,y),x)
 ....
AttributeError: 'Symbol' object has no attribute 'sin'

相关问题 更多 >

    热门问题