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))
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.
DerivativeOfF = sym.lambdify((x,y),fprime(x,y),"numpy")
print(DerivativeOfF(1,1))
正如你所看到的,我克服了无法通过创建一个新的函数DerivativeOfF来评估衍生的fprime,这个函数是" lambdified" fprime的版本。从那里,我能够评估DerivativeOfF,并将其绘制在其中一个变量中。
我的问题是:为什么这样做?我究竟做了什么?这种方法有哪些缺点?我曾尝试阅读lambdify文档,但这对我来说非常困惑(我是Python的初学者)。我的猜测是我将Python函数fprime转换为Sympy表达式DerivativeOfF,或类似的东西。任何帮助解释发生了什么以及为什么,以及lambdify究竟做了什么(用外行人的术语),将不胜感激。
答案 0 :(得分:2)
让我们看看我是否可以说明这一行动。我很熟悉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函数;返回的内容取决于输入如何处理*
,**
和+
等操作。标量和数组工作。列表处理+
和*
(连接,复制)但不处理**
。
In [4]: import sympy as sym
In [5]: x, y = sym.symbols('x y')
In [6]: type(x)
Out[6]: sympy.core.symbol.Symbol
In [7]: x+y
Out[7]: x + y
In [8]: type(_)
Out[8]: sympy.core.add.Add
定义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
和fprime
都不可调用。它们不是Python函数。 fsym(1,2)
不起作用。
但fsym.subs
可用于将x
或/和y
替换为其他值,无论是数字还是其他符号:
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
表达式。
lambdify
的 fprime
执行相同的操作,但使用了不同的符号表达式:
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.sin
,numpy.sin
和sym.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函数的一种方式。
在讨论中提出其他答案的例子
定义一个使用sin / cos的sym
版本的函数:
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)
这些功能都不是。必须使用subs
或lambdify
进行评估。
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
。大概sympy
代替np.sin
代替sym.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'
答案 1 :(得分:1)
在您的示例sym.lambdify
中创建了一个类似于
def DerivativeOff(x,y):
return 2*x + y**2
这里的numpy后端没有任何作用,因为乘法,加法和取力是原始的python函数。因此,您可以将任何参数传递给DerivativeOff
,尤其是同情符号。在代码末尾尝试DeravativeOff(x,y)
。
如果你的函数包含python本身无法处理的更复杂的表达式,情况会发生变化。请看以下示例:
def f2(x,y):
return sym.sin(x)*y
def fprime2(x,y):
return sym.diff(f2(x,y),x)
DerivativeOff2 = sym.lambdify((x,y), fprime2(x,y), "numpy")
print(DerivativeOff2(1,2)) #will return a number
print(DerivativeOff2(x,y)) #will give an error
在这个例子中,lambdify需要用一些非标准的python替换sin函数。要做到这一点,它将采用numpy(你指定&#34; numpy&#34;正是这种情况)。因此DerivatifeOff2看起来像
def DerivativeOff2(x,y):
return numpy.cos(x)*y
显然numpy无法处理同情符号......
现在,如果你只是想绘图,那么sympy有一些绘图模块(依赖于matplotlib):http://docs.sympy.org/latest/modules/plotting.html
你甚至可以制作三维图。
编辑: 以下作品也是如此:
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
答案 2 :(得分:0)
lambdify
。由于您对此感兴趣的是进行符号计算(区分),因此您不应该使用lambdify(无论如何,在计算的这一点上)。
问题在于此代码
x, y = sym.symbols('x y')
def fprime(x,y):
return sym.diff(f(x,y),x)
当您将变量名称设置为函数时,例如&#34; def fprime( x , y )&#34;,这些变量名有效地覆盖变量函数内部任何代码的函数上方定义的x
和y
的名称。因此,代码sym.diff(f(x,y),x)
不会对从symbols('x y')
返回的Symbol对象进行操作,而是对传递给fprime
的任何值进行操作。当然,如果你将这些对象作为参数传递,它将是相同的,但你可以传入任何东西。 f(x, y)
完全相同。
相反,我会避免使用任何功能。相反,创建两个符号表达式。
x, y = sym.symbols('x y')
expr = x**2 + x*y**2
fprime = diff(expr, x)
现在,要评估某个号码的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函数的参数)