如何使用Numpy来计算导数?
例如,如何计算函数的导数
y = x 2 +1
使用numpy
?
假设我想要x = 5时的导数值
你有四个选项
- 您可以使用有限差异
- 您可以使用自动衍生工具
- 您可以使用符号差异化
- 你可以手工计算衍生物。
有限差异不需要外部工具,但容易出现数值错误,如果处于多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