¿Cómo calculo la derivada usando Numpy?


97

¿Cómo calculo la derivada de una función, por ejemplo?

y = x 2 +1

usando numpy?

Digamos, quiero el valor de la derivada en x = 5 ...


5
Necesita usar Sympy: sympy.org/en/index.html Numpy es una biblioteca de cálculo numérico para Python
prrao

Alternativamente, ¿desea un método para estimar el valor numérico de la derivada? Para ello, puede utilizar un método de diferencias finitas, pero tenga en cuenta que suelen ser terriblemente ruidosos.
Henry Gomersall

Respuestas:


148

Tienes cuatro opciones

  1. Diferencias finitas
  2. Derivados automáticos
  3. Diferenciación simbólica
  4. Calcule las derivadas a mano.

Las diferencias finitas no requieren herramientas externas, pero son propensas a errores numéricos y, si se encuentra en una situación multivariante, pueden tardar un tiempo.

La diferenciación simbólica es ideal si su problema es lo suficientemente simple. Los métodos simbólicos se están volviendo bastante sólidos en estos días. SymPy es un proyecto excelente para esto que se integra bien con NumPy. Mire las funciones autowrap o lambdify o consulte la publicación de blog de Jensen sobre una pregunta similar .

Los derivados automáticos son muy interesantes, no son propensos a errores numéricos, pero requieren algunas bibliotecas adicionales (google para esto, hay algunas buenas opciones). Esta es la opción más robusta pero también la más sofisticada / difícil de configurar. Si está bien restringiéndose a la numpysintaxis, entonces Theano podría ser una buena opción.

Aquí hay un ejemplo usando 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.]

Lo siento, si esto parece una estupidez, ¿Cuáles son las diferencias entre la diferenciación simbólica y la diferenciación manual?
DrStrangeLove

11
Cuando dije "diferenciación simbólica", quise dar a entender que el proceso fue manejado por una computadora. En principio, el 3 y el 4 se diferencian únicamente por quién hace el trabajo, la computadora o el programador. Se prefiere 3 sobre 4 debido a la consistencia, escalabilidad y pereza. 4 es necesario si 3 no logra encontrar una solución.
MRocklin

4
En la línea 7 hicimos f, una función que calcula la derivada de y wrt x. En 8 aplicamos esta función derivada a un vector de todos unos y obtenemos el vector de todos los dos. Esto se debe a que, como se indica en la línea 6, yprime = 2 * x.
MRocklin

En aras de la completitud, también puede hacer la diferenciación por integración (consulte la fórmula integral de Cauchy), se implementa, por ejemplo, en mpmath(sin embargo, no estoy seguro de qué hacen exactamente).
DerWeh

¿Existe una manera fácil de hacer diferencias finitas en numpy sin implementarlo usted mismo? por ejemplo, quiero encontrar el gradiente de una función en puntos predefinidos.
Alex

44

La forma más sencilla que se me ocurre es usar la función de gradiente de numpy :

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

De esta manera, dydx se calculará usando diferencias centrales y tendrá la misma longitud que y, a diferencia de numpy.diff, que usa diferencias hacia adelante y devolverá (n-1) el tamaño del vector.


2
¿Y si dx no es constante?
weberc2

3
@ weberc2, en ese caso debe dividir un vector por otro, pero tratar los bordes por separado con derivadas hacia adelante y hacia atrás manualmente.
Sparkler

2
O puede interpolar y con una constante dx, luego calcular el gradiente.
IceArdor

@Sparkler Gracias por tu sugerencia. Si puedo hacer 2 pequeñas preguntas, (i) ¿por qué pasamos dxa en numpy.gradientlugar de x? (ii) ¿Podemos también hacer la última línea tuya de la siguiente manera dydx = numpy.gradient(y, numpy.gradient(x)):?
user929304

2
A partir de v1.13, se puede especificar un espaciado no uniforme utilizando una matriz como segundo argumento. Vea la sección de Ejemplos de esta página .
Nathaniel Jones

28

NumPy no proporciona funcionalidad general para calcular derivadas. Sin embargo, puede manejar el caso especial simple de polinomios:

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

Si desea calcular la derivada numéricamente, puede utilizar cocientes de diferencia central para la gran mayoría de aplicaciones. Para la derivada en un solo punto, la fórmula sería algo como

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

Si tiene una matriz xde abscisas con una matriz correspondiente yde valores de función, puede calcular aproximaciones de derivadas con

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

2
"Calcular derivadas numéricas para casos más generales es fácil". Lamento diferir, calcular derivadas numéricas para casos generales es bastante difícil. Simplemente eligió funciones con buen comportamiento.
High Performance Mark

¿Qué significa 2 después de >>> imprimir p ?? (en la segunda línea)
DrStrangeLove

@DrStrangeLove: Ese es el exponente. Está destinado a simular la notación matemática.
Sven Marnach

@SvenMarnach es su máximo exponente ?? ¿¿o que?? ¿Por qué cree que el exponente es 2? Ingresamos solo coeficientes ...
DrStrangeLove

2
@DrStrangeLove: se supone que la salida debe leerse como 1 * x**2 + 1. Pusieron el 2en la línea de arriba porque es un exponente. Míralo desde la distancia.
Sven Marnach

15

Suponiendo que quiera usar numpy, puede calcular numéricamente la derivada de una función en cualquier punto usando la definición rigurosa :

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

También puede utilizar la derivada simétrica para obtener mejores resultados:

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

Usando su ejemplo, el código completo debería verse así:

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

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

Ahora, puede encontrar numéricamente la derivada en x=5:

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

8

Lanzaré otro método a la pila ...

scipy.interpolateLos numerosos splines de interpolación son capaces de proporcionar derivados. Entonces, usando una spline lineal ( k=1), la derivada de la spline (usando el derivative()método) debería ser equivalente a una diferencia hacia adelante. No estoy del todo seguro, pero creo que usar una derivada de spline cúbica sería similar a una derivada de diferencia centrada, ya que usa valores de antes y después para construir la spline cúbica.

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)

acabo de intentar esto, sigo recibiendo errores de esta función AxisError: el eje -1 está fuera de los límites para la matriz de dimensión 0 y tampoco veo ninguna respuesta a esto en la comunidad, ¿alguna ayuda?
Ayan Mitra

Publique su problema como una nueva pregunta y vincúlelo aquí. Probablemente sea necesario proporcionar un ejemplo que provoque su error. Los errores que tengo con las funciones de interp suelen deberse a que los datos no están bien formados al entrar, como valores repetidos, número incorrecto de dimensiones, una de las matrices está vacía accidentalmente, los datos no se ordenan según xo cuando se ordenan no es un función válida, etc. Es posible que scipy esté llamando a numpy incorrectamente, pero es muy poco probable. Compruebe la forma x y la forma y. Vea si np.interp () funciona; de lo contrario, puede proporcionar un error más útil.
flutefreak7

6

Para calcular gradientes, la comunidad de aprendizaje automático usa Autograd:

" Calcula de manera eficiente las derivadas de numerosos códigos " .

Instalar:

pip install autograd

Aquí hay un ejemplo:

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

También puede calcular gradientes de funciones complejas, por ejemplo, funciones multivariadas.


Hola, ¿se puede usar esta función para diferenciar entre dos columnas de datos numéricamente proporcionando la longitud del paso? gracias
Ayan Mitra

3

Dependiendo del nivel de precisión que requiera, puede resolverlo usted mismo, utilizando la sencilla prueba de diferenciación:

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

en realidad no podemos tomar el límite del gradiente, pero es un poco divertido. Debes tener cuidado porque

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.