Come posso calcolare la derivata usando Numpy?


92

Come calcolo la derivata di una funzione, ad esempio

y = x 2 +1

usando numpy?

Diciamo, voglio il valore della derivata in x = 5 ...


5
Devi usare Sympy: sympy.org/en/index.html Numpy è una libreria di calcolo numerico per Python
prrao

In alternativa, vuoi un metodo per stimare il valore numerico della derivata? Per questo puoi usare un metodo di differenza finita, ma tieni presente che tendono ad essere orribilmente rumorosi.
Henry Gomersall

Risposte:


143

Hai quattro opzioni

  1. Differenze finite
  2. Derivati ​​automatici
  3. Differenziazione simbolica
  4. Calcola i derivati ​​a mano.

Le differenze finite non richiedono strumenti esterni ma sono soggette a errori numerici e, se ti trovi in ​​una situazione multivariata, può richiedere del tempo.

La differenziazione simbolica è l'ideale se il tuo problema è abbastanza semplice. I metodi simbolici stanno diventando piuttosto robusti in questi giorni. SymPy è un ottimo progetto per questo che si integra bene con NumPy. Guarda le funzioni autowrap o lambdify o dai un'occhiata al blogpost di Jensen su una domanda simile .

Le derivate automatiche sono molto interessanti, non sono soggette a errori numerici, ma richiedono alcune librerie aggiuntive (google per questo, ci sono alcune buone opzioni). Questa è la scelta più robusta ma anche la più sofisticata / difficile da configurare. Se stai bene limitandoti alla numpysintassi, Theano potrebbe essere una buona scelta.

Ecco un esempio che utilizza 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.]

Scusa, se questo sembra stupido, quali sono le differenze tra 3.Differenziazione simbolica e 4.Differenziazione manuale?
DrStrangeLove

11
Quando ho detto "differenziazione simbolica", intendevo implicare che il processo fosse gestito da un computer. In linea di principio 3 e 4 differiscono solo da chi fa il lavoro, dal computer o dal programmatore. 3 è preferito rispetto a 4 per coerenza, scalabilità e pigrizia. 4 è necessario se 3 non riesce a trovare una soluzione.
MRocklin

4
Nella riga 7 abbiamo creato f, una funzione che calcola la derivata di y rispetto a x. In 8 applichiamo questa funzione derivativa a un vettore di tutti e otteniamo il vettore di tutti i due. Questo perché, come indicato nella riga 6, yprime = 2 * x.
MRocklin

Solo per amor di completezza, puoi anche fare la differenziazione per integrazione (vedi la formula integrale di Cauchy), è implementata ad esempio in mpmath(non sono sicuro però cosa fanno esattamente).
DerWeh

C'è un modo semplice per fare differenze finite in numpy senza implementarlo tu stesso? ad esempio, voglio trovare il gradiente di una funzione in punti predefiniti.
Alex

41

Il modo più diretto a cui posso pensare è usare la funzione gradiente di numpy :

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

In questo modo, dydx verrà calcolato utilizzando differenze centrali e avrà la stessa lunghezza di y, a differenza di numpy.diff, che utilizza differenze dirette e restituirà il vettore di dimensione (n-1).


2
E se dx non fosse costante?
weberc2

3
@ weberc2, in questo caso dovresti dividere un vettore per un altro, ma tratta i bordi separatamente con le derivate in avanti e all'indietro manualmente.
Sparkler

2
Oppure puoi interpolare y con una costante dx, quindi calcolare il gradiente.
IceArdor

@Sparkler Grazie per il tuo suggerimento. Se posso fare 2 piccole domande, (i) perché passiamo dxa numpy.gradientinvece di x? (ii) Possiamo anche fare l'ultima tua riga come segue dydx = numpy.gradient(y, numpy.gradient(x)):?
user929304

2
A partire dalla v1.13, è possibile specificare una spaziatura non uniforme utilizzando un array come secondo argomento. Vedere la sezione Esempi di questa pagina .
Nathaniel Jones

26

NumPy non fornisce funzionalità generali per calcolare i derivati. Tuttavia, può gestire il semplice caso speciale dei polinomi:

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

Se vuoi calcolare la derivata numericamente, puoi cavartela usando i quozienti di differenza centrali per la stragrande maggioranza delle applicazioni. Per la derivata in un unico punto, la formula sarebbe qualcosa di simile

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

se hai un array xdi ascisse con un array corrispondente ydi valori di funzione, puoi calcolare approssimazioni di derivate con

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

2
"Calcolare derivate numeriche per casi più generali è facile" - Mi permetto di differire, calcolare derivate numeriche per casi generali è piuttosto difficile. Hai appena scelto funzioni ben educate.
High Performance Mark

cosa significa 2 dopo >>> print p ?? (sulla seconda linea)
DrStrangeLove

@DrStrangeLove: Questo è l'esponente. Ha lo scopo di simulare la notazione matematica.
Sven Marnach

@SvenMarnach è il massimo esponente ?? o cosa?? Perché pensa che l'esponente sia 2 ?? Abbiamo inserito solo i coefficienti ...
DrStrangeLove

2
@DrStrangeLove: l'output dovrebbe essere letto come 1 * x**2 + 1. Mettono il 2nella riga sopra perché è un esponente. Guardalo da lontano.
Sven Marnach

14

Supponendo che si desideri utilizzare numpy, è possibile calcolare numericamente la derivata di una funzione in qualsiasi punto utilizzando la definizione rigorosa :

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

Puoi anche utilizzare la derivata simmetrica per risultati migliori:

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

Usando il tuo esempio, il codice completo dovrebbe essere simile a:

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

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

Ora puoi trovare numericamente la derivata in x=5:

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

8

Metterò un altro metodo sul mucchio ...

scipy.interpolateLe numerose spline interpolanti sono in grado di fornire derivati. Quindi, usando una spline lineare ( k=1), la derivata della spline (usando il derivative()metodo) dovrebbe essere equivalente a una differenza diretta. Non sono del tutto sicuro, ma credo che l'utilizzo di una derivata spline cubica sarebbe simile a una derivata della differenza centrata poiché utilizza i valori di prima e dopo per costruire la spline cubica.

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)

ho appena provato, continuo a ricevere errori da questa funzione AxisError: l'asse -1 è fuori dai limiti per l'array di dimensione 0 e non vedo nessuna risposta nemmeno nella comunità, aiuto?
Ayan Mitra

Pubblica il tuo problema come nuova domanda e collegalo qui. Probabilmente sarà necessario fornire un esempio che causa l'errore. Gli errori che ho con le funzioni interp sono solitamente dovuti al fatto che i dati non sono ben formati in entrata - come valori ripetuti, numero errato di dimensioni, uno degli array è accidentalmente vuoto, i dati non sono ordinati rispetto a x o quando ordinato non è un funzione valida, ecc. È possibile che scipy stia chiamando numpy in modo errato, ma molto improbabile. Controlla x.shape e y.shape. Verifica se np.interp () funziona: in caso contrario potrebbe fornire un errore più utile.
flutefreak7

5

Per calcolare i gradienti, la comunità di machine learning utilizza Autograd:

" Calcola in modo efficiente i derivati ​​del codice numpy. "

Installare:

pip install autograd

Ecco un esempio:

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

Può anche calcolare gradienti di funzioni complesse, ad esempio funzioni multivariate.


Salve, questa funzione può essere utilizzata per differenziare numericamente tra due colonne di dati fornendo la lunghezza del passo? grazie
Ayan Mitra

3

A seconda del livello di precisione richiesto, puoi elaborarlo da solo, utilizzando la semplice prova di differenziazione:

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

non possiamo effettivamente prendere il limite del gradiente, ma è piuttosto divertente. Devi stare attento però perché

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.