如何使用Numpy计算导数?

DrS*_*ove 82 python math numpy

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

y = x 2 +1

numpy

比方说,我希望x = 5时导数的值...

MRo*_*lin 126

你有四个选择

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

有限差异不需要外部工具,但容易出现数值误差,如果您处于多变量情况,可能需要一段时间.

如果您的问题足够简单,符号差异是理想的选择.如今,符号方法变得相当强大.SymPy是一个很好的项目,与NumPy很好地集成.查看autowrap或lambdify函数或查看Jensen关于类似问题的博文.

自动衍生品非常酷,不容易出现数字错误,但确实需要一些额外的库(谷歌为此,有一些不错的选择).这是最强大但也是最复杂/最难设置的选择.如果你很好地限制自己的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.]
Run Code Online (Sandbox Code Playgroud)

  • 当我说"象征性差异化"时,我打算暗示这个过程是由计算机处理的.原则上,3和4的区别仅在于工作人员,计算机或程序员.由于一致性,可扩展性和惰性,3优于4.如果3未能找到解决方案,则需要4. (10认同)
  • 在第7行中,我们创建了f,这是一个计算y wrt x的导数的函数.在8中,我们将这个导数函数应用于所有1的向量,并得到所有两个向量.这是因为,如第6行所述,yprime = 2*x. (4认同)
  • 抱歉,如果这看起来很愚蠢,3.符号微分和4.手动微分之间有什么区别? (2认同)

Spa*_*ler 35

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

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

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

  • @ weberc2,在这种情况下,你应该将一个向量除以另一个向量,但是手动分别用前向和后向导数处理边. (3认同)
  • 如果dx不是常数怎么办? (2认同)
  • 或者,您可以将y与常数dx插值,然后计算梯度。 (2认同)
  • 从 v1.13 开始,可以使用数组作为第二个参数来指定非均匀间距。请参阅 [此页面](https://docs.scipy.org/doc/numpy/reference/generated/numpy.gradient.html#numpy.gradient) 的示例部分。 (2认同)

Sve*_*ach 26

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

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

如果要以数字方式计算导数,可以使用中心差异商来完成绝大多数应用程序.对于单点的导数,公式就是这样的

x = 5.0
eps = numpy.sqrt(numpy.finfo(float).eps) * (1.0 + x)
print (p(x + eps) - p(x - eps)) / (2.0 * eps * x)
Run Code Online (Sandbox Code Playgroud)

如果你有一个x带有相应y函数值数组的abscissae数组,你可以计算导数的近似值

numpy.diff(y) / numpy.diff(x)
Run Code Online (Sandbox Code Playgroud)

  • "为更一般的情况计算数值导数很容易" - 我不同意,计算一般情况下的数值导数是相当困难的.你刚刚选择了很好的功能. (2认同)
  • @DrStrangeLove:输出应该被读作`1*x**2 + 1`.他们把'2`放在上面的行中,因为它是一个指数.从远处看它. (2认同)

yel*_*w01 11

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

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

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

def d_fun(x):
    h = 1e-5
    return (fun(x+h)-fun(x-h))/(2*h)
Run Code Online (Sandbox Code Playgroud)

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

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

def d_fun(x):
    h = 1e-5
    return (fun(x+h)-fun(x-h))/(2*h)
Run Code Online (Sandbox Code Playgroud)

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

In [1]: d_fun(5)
Out[1]: 9.999999999621423
Run Code Online (Sandbox Code Playgroud)

  • 我会添加该函数作为参数:`def d_func(func, x):` (3认同)

joh*_*son 9

您可以使用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
Run Code Online (Sandbox Code Playgroud)


flu*_*ak7 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)
Run Code Online (Sandbox Code Playgroud)


Gor*_*ker 6

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

"高效计算 numpy 代码的导数。 "

安装:

pip install autograd
Run Code Online (Sandbox Code Playgroud)

下面是一个例子:

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))
Run Code Online (Sandbox Code Playgroud)

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