Comment calculer un dérivé à l'aide de Numpy?

92

Comment calculer la dérivée d'une fonction, par exemple

y = x 2 +1

en utilisant numpy?

Disons que je veux la valeur de la dérivée à x = 5 ...

DrStrangeLove
la source
5
Vous devez utiliser Sympy: sympy.org/en/index.html Numpy est une bibliothèque de calcul numérique pour Python
prrao
Ou voulez-vous une méthode pour estimer la valeur numérique de la dérivée? Pour cela, vous pouvez utiliser une méthode des différences finies, mais gardez à l'esprit qu'elles ont tendance à être horriblement bruyantes.
Henry Gomersall

Réponses:

143

Vous avez quatre options

  1. Différences finies
  2. Dérivés automatiques
  3. Différenciation symbolique
  4. Calculez les dérivés à la main.

Les différences finies ne nécessitent aucun outil externe mais sont sujettes à des erreurs numériques et, si vous êtes dans une situation à plusieurs variables, peuvent prendre un certain temps.

La différenciation symbolique est idéale si votre problème est assez simple. Les méthodes symboliques deviennent assez robustes de nos jours. SymPy est un excellent projet pour cela qui s'intègre bien avec NumPy. Regardez les fonctions autowrap ou lambdify ou consultez le blog de Jensen sur une question similaire .

Les dérivés automatiques sont très cool, ne sont pas sujets aux erreurs numériques, mais nécessitent des bibliothèques supplémentaires (google pour cela, il y a quelques bonnes options). C'est le choix le plus robuste mais aussi le plus sophistiqué / difficile à mettre en place. Si vous vous limitez à la numpysyntaxe, Theano pourrait être un bon choix.

Voici un exemple utilisant 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]: 2x

In [7]: f = lambdify(x, yprime, 'numpy')
In [8]: f(np.ones(5))
Out[8]: [ 2.  2.  2.  2.  2.]
MRocklin
la source
Désolé, si cela semble stupide, quelles sont les différences entre 3. différenciation symbolique et 4. différenciation manuelle ??
DrStrangeLove
11
Quand j'ai dit «différenciation symbolique», j'ai voulu laisser entendre que le processus était géré par un ordinateur. En principe 3 et 4 ne diffèrent que par qui fait le travail, l'ordinateur ou le programmeur. 3 est préféré à 4 en raison de la cohérence, de l'évolutivité et de la paresse. 4 est nécessaire si 3 ne parvient pas à trouver une solution.
MRocklin
4
À la ligne 7, nous avons créé f, une fonction qui calcule la dérivée de y par rapport à x. En 8, nous appliquons cette fonction dérivée à un vecteur de tous les uns et obtenons le vecteur de tous les deux. C'est parce que, comme indiqué à la ligne 6, yprime = 2 * x.
MRocklin
Par souci d'exhaustivité, vous pouvez également faire la différenciation par intégration (voir la formule intégrale de Cauchy), elle est implémentée par exemple dans mpmath(pas sûr cependant de ce qu'ils font exactement).
DerWeh
Existe-t-il un moyen simple de faire des différences finies dans numpy sans l'implémenter vous-même? par exemple, je veux trouver le gradient d'une fonction à des points prédéfinis.
Alex
41

Le moyen le plus simple auquel je puisse penser est d'utiliser la fonction de dégradé de numpy :

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

De cette façon, dydx sera calculé en utilisant des différences centrales et aura la même longueur que y, contrairement à numpy.diff, qui utilise des différences avant et retournera un vecteur de taille (n-1).

Cierge magique
la source
2
Et si dx n'est pas constant?
weberc2
3
@ weberc2, dans ce cas, vous devez diviser un vecteur par un autre, mais traiter les arêtes séparément avec des dérivées avant et arrière manuellement.
Sparkler
2
Ou vous pouvez interpoler y avec une constante dx, puis calculer le gradient.
IceArdor
@Sparkler Merci pour votre suggestion. Si je peux poser 2 petites questions, (i) pourquoi passons-nous à dxau numpy.gradientlieu de x? (ii) Pouvons-nous également faire la dernière ligne de la vôtre comme suit dydx = numpy.gradient(y, numpy.gradient(x)):?
user929304
2
Depuis la v1.13, un espacement non uniforme peut être spécifié en utilisant un tableau comme second argument. Consultez la section Exemples de cette page .
Nathaniel Jones
26

NumPy ne fournit pas de fonctionnalités générales pour calculer les dérivés. Cependant, il peut gérer le cas particulier simple des polynômes:

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

Si vous souhaitez calculer la dérivée numériquement, vous pouvez utiliser les quotients de différence centrale pour la grande majorité des applications. Pour le dérivé en un seul point, la formule serait quelque chose comme

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 vous avez un tableau xd'abscisses avec un tableau correspondant yde valeurs de fonction, vous pouvez calculer des approximations de dérivées avec

numpy.diff(y) / numpy.diff(x)
Sven Marnach
la source
2
«Il est facile de calculer des dérivées numériques pour des cas plus généraux» - je ne suis pas d'accord, le calcul de dérivées numériques pour des cas généraux est assez difficile. Vous venez de choisir des fonctions qui se comportent bien.
High Performance Mark
que signifie 2 après >>> print p ?? (en 2e ligne)
DrStrangeLove
@DrStrangeLove: C'est l'exposant. Il est destiné à simuler la notation mathématique.
Sven Marnach
@SvenMarnach est-il l'exposant maximum ?? ou quoi?? Pourquoi pense-t-il que l'exposant est 2? Nous n'avons entré que des coefficients ...
DrStrangeLove
2
@DrStrangeLove: La sortie est censée être lue comme 1 * x**2 + 1. Ils mettent le 2dans la ligne ci-dessus parce que c'est un exposant. Regardez-le de loin.
Sven Marnach
14

En supposant que vous souhaitiez utiliser numpy, vous pouvez calculer numériquement la dérivée d'une fonction à tout moment en utilisant la définition rigoureuse :

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

Vous pouvez également utiliser le dérivé symétrique pour de meilleurs résultats:

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

En utilisant votre exemple, le code complet devrait ressembler à quelque chose comme:

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

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

Maintenant, vous pouvez trouver numériquement la dérivée à x=5:

In [1]: d_fun(5)
Out[1]: 9.999999999621423
jaune01
la source
8

Je vais jeter une autre méthode sur la pile ...

scipy.interpolateDe nombreuses splines interpolantes sont capables de fournir des dérivés. Ainsi, en utilisant une spline linéaire ( k=1), la dérivée de la spline (en utilisant la derivative()méthode) devrait être équivalente à une différence directe. Je ne suis pas tout à fait sûr, mais je pense que l'utilisation d'un dérivé de spline cubique serait similaire à une dérivée de différence centrée car elle utilise des valeurs d'avant et d'après pour construire la spline cubique.

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)
flutefreak7
la source
juste essayé ceci, je continue à recevoir des erreurs de cette fonction AxisError: l'axe -1 est hors limites pour le tableau de dimension 0 et je ne vois pas non plus de réponses à cela sur la communauté, aucune aide?
Ayan Mitra
Postez votre problème sous forme de nouvelle question et créez un lien vers celui-ci ici. Il sera probablement nécessaire de fournir un exemple qui provoque votre erreur. Les erreurs que j'ai avec les fonctions interp sont généralement dues au fait que les données ne sont pas bien formées - comme les valeurs répétées, le mauvais nombre de dimensions, l'un des tableaux est accidentellement vide, les données ne sont pas triées par rapport à x ou lorsqu'elles sont triées, ce n'est pas un fonction valide, etc. Il est possible que scipy appelle numpy incorrectement, mais très peu probable. Vérifiez la forme x et la forme y. Voyez si np.interp () fonctionne - il peut fournir une erreur plus utile sinon.
flutefreak7
5

Pour calculer les dégradés, la communauté d'apprentissage automatique utilise Autograd:

" Calcule efficacement les dérivés du code numpy. "

À installer:

pip install autograd

Voici un exemple:

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

Il peut également calculer des gradients de fonctions complexes, par exemple des fonctions multivariées.

Gordon Schücker
la source
Salut cette fonction peut-elle être utilisée pour différencier numériquement deux colonnes de données en fournissant la longueur du pas? merci
Ayan Mitra
3

Selon le niveau de précision dont vous avez besoin, vous pouvez le déterminer vous-même, en utilisant la simple preuve de différenciation:

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

nous ne pouvons pas vraiment prendre la limite du gradient, mais c'est plutôt amusant. Tu dois faire attention parce que

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

Vous pouvez utiliser scipy, ce qui est assez simple:

scipy.misc.derivative(func, x0, dx=1.0, n=1, args=(), order=3)

Trouvez la nième dérivée d'une fonction en un point.

Dans ton cas:

from scipy.misc import derivative

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

derivative(f, 5, dx=1e-6)
# 10.00000000139778
Johnson
la source