如何使用Numpy计算导数?

时间:2012-03-26 16:50:34

标签: python math numpy

如何计算函数的导数,例如

  

y = x 2 +1

使用numpy

让我们说,我希望衍生物的值在x = 5 ......

8 个答案:

答案 0 :(得分:118)

您有四个选项

  1. Finite Differences
  2. Automatic Derivatives
  3. Symbolic Differentiation
  4. 手工计算衍生物。
  5. 有限差异不需要外部工具,但容易出现数字错误,如果您处于多变量情况,可能需要一段时间。

    如果问题很简单,符号差异化是理想的选择。如今,符号方法变得相当强大。 SymPy是一个很好的项目,可以很好地与NumPy集成。查看autowrap或lambdify函数或查看Jensen's blogpost about a similar question

    自动衍生品非常酷,不容易出现数字错误,但确实需要一些额外的库(谷歌为此,有一些不错的选择)。这是最强大但也是最复杂/最难设置的选择。如果您可以将自己限制为numpy语法,那么Theano可能是一个不错的选择。

    以下是使用SymPy

    的示例
    In [1]: from sympy import *
    In [2]: import numpy as np
    In [3]: x = Symbol('x')
    In [4]: y = x**2 + 1
    In [5]: yprime = y.diff(x)
    In [6]: yprime
    Out[6]: 2⋅x
    
    In [7]: f = lambdify(x, yprime, 'numpy')
    In [8]: f(np.ones(5))
    Out[8]: [ 2.  2.  2.  2.  2.]
    

答案 1 :(得分:32)

我能想到的最直接的方法是使用numpy's gradient function

x = numpy.linspace(0,10,1000)
dx = x[1]-x[0]
y = x**2 + 1
dydx = numpy.gradient(y, dx)

这样,dydx将使用中心差异计算,并且与y具有相同的长度,这与numpy.diff不同,numpy.diff使用向前差异并将返回(n-1)大小向量。

答案 2 :(得分:26)

NumPy不提供计算衍生产品的一般功能。它可以处理多项式的简单特例:

>>> p = numpy.poly1d([1, 0, 1])
>>> print p
   2
1 x + 1
>>> q = p.deriv()
>>> print q
2 x
>>> q(5)
10

如果要以数字方式计算导数,可以使用中心差异商来完成绝大多数应用程序。对于单个点的导数,公式将类似于

x = 5.0
eps = numpy.sqrt(numpy.finfo(float).eps) * (1.0 + x)
print (p(x + eps) - p(x - eps)) / (2.0 * eps * x)

如果你有一个abscissae的数组x和一个相应的函数值数组y,你可以用

计算导数的近似值
numpy.diff(y) / numpy.diff(x)

答案 3 :(得分:10)

假设你想使用numpy,你可以使用Rigorous definition在任何点数字计算函数的导数:

def d_fun(x):
    h = 1e-5 #in theory h is an infinitesimal
    return (fun(x+h)-fun(x))/h

您还可以使用Symmetric derivative获得更好的结果:

def d_fun(x):
    h = 1e-5
    return (fun(x+h)-fun(x-h))/(2*h)

使用您的示例,完整代码应如下所示:

def fun(x):
    return x**2 + 1

def d_fun(x):
    h = 1e-5
    return (fun(x+h)-fun(x-h))/(2*h)

现在,您可以数字x=5找到衍生品:

In [1]: d_fun(5)
Out[1]: 9.999999999621423

答案 4 :(得分:6)

我会在堆上扔另一种方法......

scipy.interpolate许多插值样条都能够提供衍生物。因此,使用线性样条曲线(k=1),样条曲线的导数(使用derivative()方法)应等于前向差异。我不完全确定,但我相信使用三次样条导数与中心差导数类似,因为它使用前后的值来构造三次样条。

from scipy.interpolate import InterpolatedUnivariateSpline

# Get a function that evaluates the linear spline at any x
f = InterpolatedUnivariateSpline(x, y, k=1)

# Get a function that evaluates the derivative of the linear spline at any x
dfdx = f.derivative()

# Evaluate the derivative dydx at each x location...
dydx = dfdx(x)

答案 5 :(得分:2)

根据您所需的精确程度,您可以使用简单的区分证据自行解决:

>>> (((5 + 0.1) ** 2 + 1) - ((5) ** 2 + 1)) / 0.1
10.09999999999998
>>> (((5 + 0.01) ** 2 + 1) - ((5) ** 2 + 1)) / 0.01
10.009999999999764
>>> (((5 + 0.0000000001) ** 2 + 1) - ((5) ** 2 + 1)) / 0.0000000001
10.00000082740371

我们实际上不能采用渐变的限制,但它有点乐趣。 你必须小心,因为

>>> (((5+0.0000000000000001)**2+1)-((5)**2+1))/0.0000000000000001
0.0

答案 6 :(得分:2)

您可以使用scipy,这很简单:

scipy.misc.derivative(func, x0, dx=1.0, n=1, args=(), order=3)

在某个点上找到函数的n阶导数。

在您的情况下:

from scipy.misc import derivative

def f(x):
    return x**2 + 1

derivative(f, 5, dx=1e-6)
# 10.00000000139778

答案 7 :(得分:1)

为了计算梯度,机器学习社区使用Autograd:

  

Efficiently computes derivatives of numpy code.

要安装:

pip install autograd

这里是一个例子:

import autograd.numpy as np
from autograd import grad

def fct(x):
    y = x**2+1
    return y

grad_fct = grad(fct)
print(grad_fct(1.0))

它也可以计算复杂函数的梯度,例如多元函数。