2012-03-26 109 views
47

如何使用numpy计算函数的导数,例如如何使用Numpy计算导数?

Y = X 2 +1

比方说,我想在x = 5的衍生价值...

+3

您需要使用Sympy:http://sympy.org/en/index.html numpy的是一个数值计算Python的库 – prrao 2012-03-26 16:55:33

+0

或者,您是否需要一种估算导数数值的方法?为此,您可以使用有限差分方法,但请记住它们往往是非常嘈杂的。 – 2012-03-26 17:11:12

回答

88

您有四个选项

  1. 您可以使用Finite Differences
  2. 您可以使用Automatic Derivatives
  3. 您可以使用Symbolic Differentiation
  4. 您可以通过计算衍生品手。

有限差分无需外部工具,但容易出现数值误差,如果你在一个多元的情况是,可能需要一段时间。

如果问题很简单,符号区分是最理想的。现在符号方法变得相当强大。 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.] 
+0

对不起,如果这看起来很蠢,3之间有什么区别。符号分化和4.手分化? – DrStrangeLove 2012-04-12 16:55:03

+8

当我说“象征性区分”时,我打算暗示该过程是由计算机处理的。原则3和4的区别仅在于工作人员,计算机或程序员。由于一致性,可扩展性和懒惰,3优于4。如果3找不到解决方案,则4是必要的。 – MRocklin 2012-04-13 16:51:04

+1

非常感谢!但最后一行是[2. 2. 2. 2. 2.]? – DrStrangeLove 2012-04-14 02:18:36

22

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) 

,如果你有横坐标的阵列x与相应的数组函数值的y,可以COMPUT衍生物的近似值与

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

'计算更一般情况下的数值导数很容易' - 我要求不同,计算一般情况下的数值导数是相当困难的。你只是选择了很好的表现功能。 – 2012-03-26 17:18:37

+0

>>> print p ??之后的意思是什么? (在第二行) – DrStrangeLove 2012-03-26 17:23:33

+0

@DrStrangeLove:这是指数。它意在模拟数学符号。 – 2012-03-26 17:26:31

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 
18

我能想到的最直接的方法是使用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,它使用前向差异并返回(n-1)大小的向量。

+0

如果dx不恒定会怎样? – weberc2 2015-07-01 21:22:12

+2

@ weberc2,在这种情况下,您应该将一个向量除以另一个向量,但是需要手动分别用向前和向后导数来处理边。 – Sparkler 2015-07-02 22:06:26

+1

或者您可以用常数dx插值y,然后计算梯度。 – IceArdor 2016-11-16 03:43:47

3

我会扔另一种方法对桩...

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

假设你想使用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