如何在python中计算矩生成函数的导数?

时间:2015-07-08 18:23:46

标签: python statistics scipy sympy

到目前为止,这是我的代码,我认为我可以使用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时进行评估,更重要的部分是区分是正确的。

3 个答案:

答案 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进行符号化处理,并以数字方式评估特定musigmas

的结果
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是实际的二阶导数。