到目前为止,这是我的代码,我认为我可以使用scipy,但它没有给出正确答案的二阶导数,时刻(0,2)。我的猜测是我没有正确地应用scipy.misc.derivative而且我应该使用sympy的diffs_exp,但是我无法使用它...
from scipy import misc
import numpy as np
def mgf(s):
mu = 2
sigma = 0.5
mgf = np.exp(mu*s + ((sigma**2)*(s**2))/2)
return mgf
def moment(s, i):
mo = misc.derivative(mgf, s, dx=0.000000001, n=i)
return mo
时刻(s,i)在i = 1时正确评估,但在i> 1时则不正确。 moment(0,2)应该等于sigma ^ 2或.25但函数当前返回0.0
该函数仅在s = 0时进行评估,更重要的部分是区分是正确的。
答案 0 :(得分:1)
为有限差分方案选择一个好的步长是一个棘手的业务。太小的步骤,你注定因为四舍五入错误(正如你所发现的那样)。太大的步骤,并且计划太粗糙(正如您所发现的那样)。 BTW,scipy.misc.derivative
的默认步骤不是很有用。有一些关于如何选择合理步骤的文献。例如,Numerical Recipes简要介绍了一个简单的方案。
在这种特殊情况下,找到合理的步骤相当容易:
In [41]: from scipy.misc import derivative
In [42]: def f(x):
....: arg = 2.*x + (0.5*x)**2 / 2.
....: return np.exp(arg)
....:
In [53]: derivative(f, 0., dx=1e-5, n=2)
Out[53]: 4.2499981312005266
另一种方法是使用一个更聪明的步长选择的包(互联网/文献搜索的一个关键字是Romberg外推)。例如,numdifftools:
In [57]: import numdifftools as nd
In [59]: fdd = nd.Derivative(f, n=2)
In [60]: fdd(0)
Out[60]: array([ 4.25])
答案 1 :(得分:1)
以下是如何使用sympy
进行符号化处理,并以数字方式评估特定mu
,sigma
和s
In [1]: from sympy import *
In [2]: mu, sigma, s = symbols("mu sigma s")
In [3]: expr = exp(mu*s+(sigma*s)**2/2)
In [4]: f = lambdify((mu, sigma, s), expr.diff(s, 2))
In [5]: f(2, 0.5, 0)
Out[5]: 4.25
答案 2 :(得分:0)
所以我在误读了早期答案中的问题(自删除后)后,在源代码中弄乱了。
Scipy misc.derivative默认计算二阶导数为
lim h-> 0(f(x + h)-2 * f(x)+ f(x-h))/ h ^ 2
这里出现的问题是因为np.exp()的输出是float64,它的精度有限,即尾数为52位,指数为11位。当我们减小dx时,术语之间的差异出现在更高阶的数字中,由于精度有限,因此不存在。在总结时,这消失为零。
作为参考,在上面的函数中,值是 对于f(x + h),f(x),f(x-h)分别为0.999999998,1,1000000002,其中x = 0且h = 1e-9。解决方案可能是使用具有更高精度的任一函数,但这将涉及更改scipy源代码并且不是一项小任务。(Python pow函数不是任意精度)
其他(实用)选项是为dx使用较小的值。 dx = 1e-2似乎实际上给出了足够接近的答案,即4.2501848996,而4.25是实际的二阶导数。