Wie berechne ich ein Derivat mit Numpy?

89

Wie berechne ich zum Beispiel die Ableitung einer Funktion?

y = x 2 +1

mit numpy?

Angenommen, ich möchte den Wert der Ableitung bei x = 5 ...

DrStrangeLove
quelle
5
Sie müssen Sympy verwenden: sympy.org/en/index.html Numpy ist eine numerische Berechnungsbibliothek für Python
prrao
Möchten Sie alternativ eine Methode zur Schätzung des numerischen Werts der Ableitung? Hierfür können Sie eine Finite-Differenzen-Methode verwenden, aber denken Sie daran, dass sie dazu neigen, schrecklich laut zu sein.
Henry Gomersall

Antworten:

138

Sie haben vier Möglichkeiten

  1. Endliche Unterschiede
  2. Automatische Derivate
  3. Symbolische Differenzierung
  4. Berechnen Sie Derivate von Hand.

Endliche Unterschiede erfordern keine externen Tools, sind jedoch anfällig für numerische Fehler und können in einer multivariaten Situation eine Weile dauern.

Die symbolische Differenzierung ist ideal, wenn Ihr Problem einfach genug ist. Symbolische Methoden werden heutzutage ziemlich robust. SymPy ist hierfür ein hervorragendes Projekt, das sich gut in NumPy integrieren lässt. Schauen Sie sich die Autowrap- oder Lambdify-Funktionen an oder lesen Sie Jensens Blogpost über eine ähnliche Frage .

Automatische Ableitungen sind sehr cool, nicht anfällig für numerische Fehler, erfordern jedoch einige zusätzliche Bibliotheken (Google gibt dafür einige gute Optionen). Dies ist die robusteste, aber auch die raffinierteste / am schwierigsten einzurichtende Wahl. Wenn Sie sich auf die numpySyntax beschränken möchten, ist Theano möglicherweise eine gute Wahl.

Hier ist ein Beispiel mit 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
quelle
Entschuldigung, wenn dies dumm erscheint, was sind die Unterschiede zwischen 3.Symbolic Differentiation und 4.by Hand Differentiation?
DrStrangeLove
10
Als ich "symbolische Differenzierung" sagte, wollte ich implizieren, dass der Prozess von einem Computer abgewickelt wurde. Grundsätzlich unterscheiden sich 3 und 4 nur dadurch, wer die Arbeit erledigt, der Computer oder der Programmierer. Aufgrund der Konsistenz, Skalierbarkeit und Faulheit wird 3 gegenüber 4 bevorzugt. 4 ist notwendig, wenn 3 keine Lösung findet.
MRocklin
4
In Zeile 7 haben wir f gemacht, eine Funktion, die die Ableitung von y wrt x berechnet. In 8 wenden wir diese Ableitungsfunktion auf einen Vektor aller Einsen an und erhalten den Vektor aller Zweien. Dies liegt daran, dass, wie in Zeile 6 angegeben, yprime = 2 * x ist.
MRocklin
Der Vollständigkeit halber können Sie auch eine Differenzierung durch Integration vornehmen (siehe Cauchys Integralformel), die zB in implementiert ist mpmath(nicht sicher, aber was genau sie tun).
DerWeh
41

Der einfachste Weg, den ich mir vorstellen kann, ist die Verwendung der Gradientenfunktion von numpy :

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

Auf diese Weise wird dydx unter Verwendung zentraler Differenzen berechnet und hat die gleiche Länge wie y, im Gegensatz zu numpy.diff, das Vorwärtsdifferenzen verwendet und einen Größenvektor (n-1) zurückgibt.

Wunderkerze
quelle
2
Was ist, wenn dx nicht konstant ist?
weberc2
3
@ weberc2, in diesem Fall sollten Sie einen Vektor durch einen anderen teilen, aber die Kanten getrennt manuell mit Vorwärts- und Rückwärtsableitungen behandeln.
Wunderkerze
2
Oder Sie interpolieren y mit einer Konstanten dx und berechnen dann den Gradienten.
IceArdor
@ Parkler Danke für deinen Vorschlag. Wenn ich 2 kleine Fragen stellen kann, (i) , warum geben wir dxan numpy.gradientstatt x? (ii) Können wir auch Ihre letzte Zeile wie folgt machen : dydx = numpy.gradient(y, numpy.gradient(x))?
user929304
2
Ab Version 1.13 kann ein ungleichmäßiger Abstand mithilfe eines Arrays als zweites Argument angegeben werden. Siehe den Abschnitt Beispiele auf dieser Seite .
Nathaniel Jones
26

NumPy bietet keine allgemeine Funktionalität zum Berechnen von Derivaten. Es kann jedoch den einfachen Spezialfall von Polynomen behandeln:

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

Wenn Sie die Ableitung numerisch berechnen möchten, können Sie für die überwiegende Mehrheit der Anwendungen die Verwendung zentraler Differenzquotienten vermeiden. Für die Ableitung in einem einzelnen Punkt wäre die Formel ungefähr so

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

Wenn Sie ein Array xvon Abszissen mit einem entsprechenden Array yvon Funktionswerten haben, können Sie Approximationen von Ableitungen mit berechnen

numpy.diff(y) / numpy.diff(x)
Sven Marnach
quelle
2
'Die Berechnung numerischer Ableitungen für allgemeinere Fälle ist einfach' - Ich bin anderer Meinung, die Berechnung numerischer Ableitungen für allgemeine Fälle ist ziemlich schwierig. Sie haben gerade gut benommene Funktionen gewählt.
High Performance Mark
Was bedeutet 2 nach >>> Drucken von p? (in der 2. Zeile)
DrStrangeLove
@ DrStrangeLove: Das ist der Exponent. Es soll die mathematische Notation simulieren.
Sven Marnach
@SvenMarnach ist es maximaler Exponent? oder was?? Warum glaubt es, dass der Exponent 2 ist? Wir haben nur Koeffizienten eingegeben ...
DrStrangeLove
2
@DrStrangeLove: Die Ausgabe soll gelesen werden als 1 * x**2 + 1. Sie setzen das 2in die obige Zeile, weil es ein Exponent ist. Schau es dir aus der Ferne an.
Sven Marnach
13

Angenommen, Sie möchten verwenden numpy, können Sie die Ableitung einer Funktion an jedem Punkt mithilfe der rigorosen Definition numerisch berechnen :

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

Sie können auch die symmetrische Ableitung verwenden, um bessere Ergebnisse zu erzielen:

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

In Ihrem Beispiel sollte der vollständige Code ungefähr so ​​aussehen:

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

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

Jetzt können Sie die Ableitung numerisch finden unter x=5:

In [1]: d_fun(5)
Out[1]: 9.999999999621423
gelb01
quelle
8

Ich werde eine andere Methode auf den Stapel werfen ...

scipy.interpolateDie vielen interpolierenden Splines können Ableitungen bereitstellen. Bei Verwendung eines linearen Splines ( k=1) sollte die Ableitung des Splines (unter Verwendung der derivative()Methode) einer Vorwärtsdifferenz entsprechen. Ich bin nicht ganz sicher, aber ich glaube, dass die Verwendung einer kubischen Spline-Ableitung einer zentrierten Differenzableitung ähnlich wäre, da sie Werte von vorher und nachher verwendet, um den kubischen Spline zu konstruieren.

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)
Flötenbruch7
quelle
Ich habe es gerade versucht, ich bekomme immer wieder Fehler von dieser Funktion. AxisError: Achse -1 ist für ein Array der Dimension 0 außerhalb der Grenzen und ich sehe auch keine Antworten darauf in der Community, irgendeine Hilfe?
Ayan Mitra
Stellen Sie Ihr Problem als neue Frage und verlinken Sie hier. Es ist wahrscheinlich erforderlich, ein Beispiel anzugeben, das dazu führt, dass Ihr Fehler auftritt. Fehler, die ich bei Interp-Funktionen habe, sind normalerweise darauf zurückzuführen, dass die Daten nicht gut geformt sind - wie wiederholte Werte, falsche Anzahl von Dimensionen, eines der Arrays ist versehentlich leer, Daten werden nicht nach x sortiert oder wenn sortiert nicht a gültige Funktion usw. Es ist möglich, dass scipy numpy falsch aufruft, aber sehr unwahrscheinlich. Überprüfen Sie x.shape und y.shape. Überprüfen Sie, ob np.interp () funktioniert. Andernfalls wird möglicherweise ein hilfreicherer Fehler angezeigt.
Flutefreak7
5

Zur Berechnung von Verläufen verwendet die Community für maschinelles Lernen Autograd:

" Berechnet effizient Ableitungen von Numpy-Code. "

Installieren:

pip install autograd

Hier ist ein Beispiel:

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

Es kann auch Gradienten komplexer Funktionen berechnen, z. B. multivariate Funktionen.

Gordon Schücker
quelle
Hallo, kann diese Funktion verwendet werden, um zwischen zwei Datenspalten numerisch zu unterscheiden, indem die Schrittlänge angegeben wird? danke
Ayan Mitra
3

Abhängig von der Präzision, die Sie benötigen, können Sie dies anhand des einfachen Differenzierungsnachweises selbst herausfinden:

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

Wir können die Grenze des Gefälles nicht wirklich überschreiten, aber es macht irgendwie Spaß. Du musst aber aufpassen, weil

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

Sie können verwenden scipy, was ziemlich einfach ist:

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

Finden Sie die n-te Ableitung einer Funktion an einem Punkt.

In deinem Fall:

from scipy.misc import derivative

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

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