用Scipy进行数值微分

时间:2012-08-28 22:53:04

标签: numerical derivative

我正在尝试学习Scipy,将其用于混合集成和差异化,但在最初的步骤中我遇到了以下问题。

对于数值微分,似乎唯一适用于可调用函数的Scipy函数是scipy.derivative()如果我是对的!?但是,我无法使用它:

1st)当我不打算指定区分点时,例如当微分在积分下时,它是积分,应该将数值赋给其被积函数的变量,而不是我。作为一个简单的例子,我在Sage的笔记本中尝试了这段代码:

import scipy as sp
from scipy import integrate, derivative
var('y')
f=lambda x: 10^10*sin(x)
g=lambda x,y: f(x+y^2)
I=integrate.quad( sp.derivative(f(y),y, dx=0.00001, n=1, order=7) , 0, pi)[0]; show(I)
show( integral(diff(f(y),y),y,0,1).n() )

它还会发出警告“警告:检测到出现舍入错误,这会阻止实现所要求的容差。错误可能会被低估。”而且我不知道这个警告代表什么,因为它会持续存在,即使增加“dx”并减少“顺序”。

2nd)当我想在上面的例子中找到像g(x,y)这样的多变量函数的导数时,像sp.derivative(g(x,y),(x) ,0.5),dx = 0.01,n = 1,order = 3)给出误差,这是容易预料的。

期待听到您如何通过数值区分解决上述问题。 最诚挚的问候

1 个答案:

答案 0 :(得分:0)

你的代码有一些奇怪的问题,建议你需要刷一些python!我不知道你是如何在python中制作这些定义的,因为它们不是合法的语法。

首先,我认为您使用的是旧版本的scipy。在最近的版本中(至少从0.12 +开始),您需要from scipy.misc import derivativederivative不在scipy全局命名空间中。

其次,var未定义,但无论如何都没有必要(我认为你的意思是首先输入sympy并使用sympy.var('y'))。 sin也没有从数学中导入(如果你愿意,也可以是numpy)。 show在sympy或scipy中不是一个有效的函数。

^不是python中的幂运算符。你的意思是**

您似乎在这里混淆了符号和数字微积分操作的想法。 scipy不会在数字上区分涉及符号对象的表达式 - 导数的第二个参数应该是你希望得到导数(即数字)的点。正如您所说,您正在尝试进行数字区分,我将为此目的解决问题。

from scipy import integrate
from scipy.misc import derivative
from math import *

f = lambda x: 10**10*sin(x)
df = lambda x: derivative(f, x, dx=0.00001, n=1, order=7)
I = integrate.quad( df, 0, pi)[0]

现在,这个最后一个表达式生成了你提到的警告,并且绝对值中返回的值在-0.0731642869874073处并非非常接近于零,尽管相对于f的比例来说这并不坏。您必须了解有限差分中的舍入误差问题。您的函数f在0到10 ^ 10之间的间隔内有所不同!这可能看似矛盾,但是使微分的dx值太小实际上可以放大舍入误差并导致数值不稳定。请参阅此处的第二个图表("显示由于舍入误差和公式错误而选择h的难度的示例")以获得解释:http://en.wikipedia.org/wiki/Numerical_differentiation

事实上,在这种情况下,你需要增加,比如0.001:df = lambda x: derivative(f, x, dx=0.001, n=1, order=7)

然后,你可以安全地整合,没有可怕的结果。

I=integrate.quad( df, 0, pi)[0]

我不建议丢弃quad的第二个返回值。它是对所发生事件的重要验证,因为它是对结果中绝对误差的估计"。在这种情况下,I == 0.0012846582250212652,绝对误差为~0.00022,这也不错(暗示的间隔仍然不包括零)。也许更多摆弄四核的dx和绝对公差会让你获得更好的解决方案,但希望你能得到这个想法。

对于你的第二个问题,你只需要创建一个适当的标量函数(称之为gx),它代表y = 0.5的g(x,y)(这称为计算机科学中的Currying)。

g = lambda x, y: f(x+y**2)
gx = lambda x: g(x, 0.5)

derivative(gx, 0.2, dx=0.01, n=1, order=3)

给出了x = 0.2时的导数值。当然,鉴于f的规模,价值是巨大的。您可以像我上面展示的那样使用四元组进行集成。

如果你想区分g本身,你需要一个不同的数值微分函数。我不认为scipy或numpy支持这一点,虽然你可以通过制作2D精细网格(大小dx)并使用numpy.gradient来破解中心差异计算。可能还有其他我不了解的库解决方案,但我知道我的PyDSTool软件包含一个函数diff,它会执行该操作(如果你重写g来代替一个数组参数)。它使用Ridder的方法,灵感来自Numerical Recipes伪代码。