如何使用Numpy来计算导数?

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

y = x 2 +1

使用numpy

假设我想要x = 5时的导数值

你有四个选项

  1. 您可以使用有限差异
  2. 您可以使用自动衍生工具
  3. 您可以使用符号差异化
  4. 你可以手工计算衍生物。

有限差异不需要外部工具,但容易出现数值错误,如果处于多variables状态,可能需要一段时间。

如果问题很简单,符号分化是理想的。 符号方法现在越来越强大。 SymPy是一个非常好的项目,与NumPy很好地结合在一起。 看看autowrap或lambdify函数,或查看Jensen关于类似问题的博文。

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

这里是一个使用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.] 

NumPy不提供通用function来计算衍生工具。 它可以处理多项式的简单特例:

 >>> 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) 

如果有一个具有相应的函数值数组y的横坐标的数组x ,则可以用下式来计算导数的近似值

 numpy.diff(y) / numpy.diff(x) 

我能想到的最直接的方法是使用numpy的渐变函数 :

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

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

我会在堆上扔另一种方法

scipy.interpolate的许多插值样条都可以提供派生。 因此,使用线性样条( k=1 ),样条的derivative()使用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) 

根据你所要求的精度水平,你可以使用简单的差异性certificate自己来解决:

 >>> (((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 

假设你想使用numpy ,你可以使用严格的定义在任何点数值计算函数的导数:

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

您也可以使用对称导数来获得更好的结果:

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

使用你的例子,完整的代码应该是这样的:

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

现在,您可以在x=5数值地find导数:

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