我可以使用 lambdify 计算 python 函数的导数吗?
Can I use lambdify to evaluate the derivative of a python function?
关于区分 python 函数然后当我发现 none 发布的答案满足我评估(在某些变量中)然后绘制的需要时导数,我能够找到自己的解决方案。
前一个代码:
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 的问题,该函数是 fprime 的 "lambdified" 版本。从那里,我能够评估 DerivativeOfF,并将其绘制在其中一个变量中。
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.
在您的示例中 sym.lambdify
创建了一个 python 看起来像
的函数
def DerivativeOff(x,y):
return 2*x + y**2
这里的numpy后端没有任何作用,因为乘法、加法和取电都是原始的python函数。因此,您可以将任何参数传递给 DerivativeOff
,尤其是 sympy 符号。在代码末尾尝试 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(您为这种情况指定了 "numpy")。因此 DerivatifeOff2 看起来像
def DerivativeOff2(x,y):
return numpy.cos(x)*y
显然 numpy 无法处理 sympy 符号...
现在如果你只想绘图,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 函数; returns 取决于输入如何处理 *
、**
和 +
等操作。标量和数组起作用。列表处理 +
和 *
(连接、复制)但不处理 **
.
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
用这 2 个符号对象调用 f
会创建一个新的符号对象。我也可以用符号和数字甚至数组的其他组合来调用它。
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
or/andy
替换成其他值,无论是数字还是其他符号:
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 对象和 returns 一个 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)
再次 none 这些功能。必须使用 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'
如果要将 SymPy 表达式转换为可以进行数值计算的函数,则应使用 lambdify
。由于您在这里的兴趣是进行符号计算(微分),因此您不应使用 lambdify(无论如何,此时在您的计算中)。
问题出在这段代码
x, y = sym.symbols('x y')
def fprime(x,y):
return sym.diff(f(x,y),x)
当您为函数设置变量名时,如 "def fprime(x, y)",这些变量名有效地覆盖了函数上方定义的 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 函数)
前一个代码:
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 的问题,该函数是 fprime 的 "lambdified" 版本。从那里,我能够评估 DerivativeOfF,并将其绘制在其中一个变量中。
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.
在您的示例中 sym.lambdify
创建了一个 python 看起来像
def DerivativeOff(x,y):
return 2*x + y**2
这里的numpy后端没有任何作用,因为乘法、加法和取电都是原始的python函数。因此,您可以将任何参数传递给 DerivativeOff
,尤其是 sympy 符号。在代码末尾尝试 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(您为这种情况指定了 "numpy")。因此 DerivatifeOff2 看起来像
def DerivativeOff2(x,y):
return numpy.cos(x)*y
显然 numpy 无法处理 sympy 符号...
现在如果你只想绘图,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 函数; returns 取决于输入如何处理 *
、**
和 +
等操作。标量和数组起作用。列表处理 +
和 *
(连接、复制)但不处理 **
.
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
用这 2 个符号对象调用 f
会创建一个新的符号对象。我也可以用符号和数字甚至数组的其他组合来调用它。
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
or/andy
替换成其他值,无论是数字还是其他符号:
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 对象和 returns 一个 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)
再次 none 这些功能。必须使用 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'
lambdify
。由于您在这里的兴趣是进行符号计算(微分),因此您不应使用 lambdify(无论如何,此时在您的计算中)。
问题出在这段代码
x, y = sym.symbols('x y')
def fprime(x,y):
return sym.diff(f(x,y),x)
当您为函数设置变量名时,如 "def fprime(x, y)",这些变量名有效地覆盖了函数上方定义的 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 函数)