Jak obliczyć pochodną za pomocą Numpy?


96

Na przykład, jak obliczyć pochodną funkcji

y = x 2 +1

używając numpy?

Powiedzmy, że chcę mieć wartość pochodnej przy x = 5 ...


5
Musisz użyć Sympy: sympy.org/en/index.html Numpy to biblioteka obliczeń numerycznych dla Pythona
prrao

Alternatywnie, czy potrzebujesz metody szacowania wartości liczbowej instrumentu pochodnego? W tym celu możesz użyć metody różnic skończonych, ale pamiętaj, że zwykle są one strasznie hałaśliwe.
Henry Gomersall

Odpowiedzi:


148

Masz cztery opcje

  1. Skończone różnice
  2. Automatyczne instrumenty pochodne
  3. Zróżnicowanie symboliczne
  4. Ręczne obliczanie pochodnych.

Skończone różnice nie wymagają zewnętrznych narzędzi, ale są podatne na błędy numeryczne, a jeśli jesteś w sytuacji wielowymiarowej, może to chwilę potrwać.

Zróżnicowanie symboliczne jest idealne, jeśli problem jest wystarczająco prosty. W dzisiejszych czasach metody symboliczne stają się coraz mocniejsze. SymPy to doskonały projekt do tego, który dobrze integruje się z NumPy. Spójrz na funkcje autowrap lub lambdify lub przeczytaj wpis na blogu Jensena dotyczący podobnego pytania .

Automatyczne pochodne są bardzo fajne, nie są podatne na błędy numeryczne, ale wymagają dodatkowych bibliotek (Google do tego jest kilka dobrych opcji). Jest to najbardziej solidny, ale także najbardziej wyrafinowany / trudny do skonfigurowania wybór. Jeśli możesz ograniczyć się do numpyskładni, Theano może być dobrym wyborem.

Oto przykład użycia 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.]

Przepraszam, jeśli wydaje się to głupie, jakie są różnice między 3. różnicowaniem symbolicznym a różnicowaniem 4. ręcznym?
DrStrangeLove

11
Kiedy powiedziałem „symboliczne zróżnicowanie”, zamierzałem zasugerować, że procesem zajmuje się komputer. W zasadzie 3 i 4 różnią się tylko tym, kto wykonuje pracę, komputerem czy programistą. 3 jest preferowane zamiast 4 ze względu na spójność, skalowalność i lenistwo. 4 jest konieczne, jeśli 3 nie znajdzie rozwiązania.
MRocklin

4
W linii 7. utworzyliśmy funkcję f, która oblicza pochodną y wrt x. W 8 stosujemy tę pochodną funkcję do wektora wszystkich jedynek i otrzymujemy wektor wszystkich dwójek. Dzieje się tak, ponieważ, jak stwierdzono w wierszu 6, yprime = 2 * x.
MRocklin,

Dla zupełności można też dokonać różniczkowania przez całkowanie (patrz wzór całkowy Cauchy'ego), jest ono realizowane np. W mpmath(nie wiem jednak, co dokładnie robią).
DerWeh

Czy istnieje łatwy sposób na zrobienie skończonych różnic w numpy bez jego samodzielnego wdrażania? np. chcę znaleźć gradient funkcji w określonych punktach.
Alex

43

Najprostszym sposobem, jaki przychodzi mi do głowy, jest użycie funkcji gradientu numpy :

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

W ten sposób dydx zostanie obliczony przy użyciu różnic centralnych i będzie miał taką samą długość jak y, w przeciwieństwie do numpy.diff, który używa różnic do przodu i zwróci wektor rozmiaru (n-1).


2
A co jeśli dx nie jest stałe?
weberc2

3
@ weberc2, w takim przypadku powinieneś podzielić jeden wektor przez drugi, ale ręcznie traktować krawędzie osobno za pomocą pochodnych do przodu i do tyłu.
Sparkler

2
Lub możesz interpolować y ze stałą dx, a następnie obliczyć gradient.
IceArdor

@Sparkler Dzięki za sugestię. Jeśli mogę zadać 2 małe pytania, (i) dlaczego przechodzimy dxdo numpy.gradientzamiast x? (ii) Czy możemy również wykonać ostatnią linię w następujący sposób dydx = numpy.gradient(y, numpy.gradient(x)):?
user929304

2
Od wersji 1.13 niejednolite odstępy można określić, używając tablicy jako drugiego argumentu. Zobacz sekcję Przykłady na tej stronie .
Nathaniel Jones

28

NumPy nie zapewnia ogólnej funkcjonalności obliczania pochodnych. Może jednak obsługiwać prosty, specjalny przypadek wielomianów:

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

Jeśli chcesz obliczyć pochodną numerycznie, możesz uciec od używania ilorazów centralnych różnic dla większości zastosowań. Dla pochodnej w jednym punkcie wzór wyglądałby mniej więcej tak

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

jeśli masz tablicę xodciętych z odpowiednią tablicą ywartości funkcji, możesz obliczyć przybliżenia pochodnych za pomocą

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

2
„Obliczanie pochodnych numerycznych dla przypadku bardziej ogólnego jest łatwe” - nie zgadzam się, obliczanie pochodnych numerycznych dla przypadków ogólnych jest dość trudne. Po prostu wybrałeś ładnie działające funkcje.
Znak wysokiej wydajności

co oznacza 2 po >>> print p ?? (w drugiej linii)
DrStrangeLove

@DrStrangeLove: To jest wykładnik. Ma na celu symulowanie notacji matematycznej.
Sven Marnach

@SvenMarnach czy to maksymalny wykładnik ?? albo co?? Dlaczego myśli, że wykładnik wynosi 2? Wprowadziliśmy tylko współczynniki ...
DrStrangeLove

2
@DrStrangeLove: Wyjście powinno być odczytywane jako 1 * x**2 + 1. W 2powyższym wierszu umieścili, ponieważ jest to wykładnik. Spójrz na to z daleka.
Sven Marnach

15

Zakładając, że chcesz użyć numpy, możesz numerycznie obliczyć pochodną funkcji w dowolnym momencie, używając definicji Rygorystycznej :

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

Aby uzyskać lepsze wyniki, możesz również użyć pochodnej symetrycznej :

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

Korzystając z Twojego przykładu, pełny kod powinien wyglądać mniej więcej tak:

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

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

Teraz możesz numerycznie znaleźć pochodną pod adresem x=5:

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

8

Rzucę inną metodę na stos ...

scipy.interpolateWiele interpolujących splajnów może zapewnić pochodne. Tak więc, używając liniowego splajnu ( k=1), pochodna splajnu (przy użyciu derivative()metody) powinna być równoważna różnicy w przód. Nie jestem do końca pewien, ale uważam, że użycie pochodnej sześciennej splajnu byłoby podobne do wyśrodkowanej pochodnej różnicy, ponieważ używa wartości przed i po do skonstruowania sześciennego splajnu.

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)

właśnie próbowałem tego, wciąż otrzymuję błędy z tej funkcji AxisError: oś -1 jest poza zakresem dla tablicy wymiaru 0 i nie widzę żadnych odpowiedzi na to również w społeczności, jakaś pomoc?
Ayan Mitra

Opublikuj swój problem jako nowe pytanie i łącze do niego tutaj. Prawdopodobnie potrzebne będzie podanie przykładu powodującego wystąpienie błędu. Błędy, które mam z funkcjami interp są zwykle spowodowane tym, że dane nie są dobrze uformowane - jak powtarzające się wartości, zła liczba wymiarów, jedna z tablic jest przypadkowo pusta, dane nie są sortowane względem x lub gdy posortowane poprawna funkcja itp. Możliwe, że scipy wywołuje numpy niepoprawnie, ale jest bardzo mało prawdopodobne. Sprawdź x.shape i y.shape. Sprawdź, czy działa np.interp () - może dostarczyć bardziej pomocnego błędu, jeśli nie.
flutefreak7

6

Aby obliczyć gradienty, społeczność uczenia maszynowego używa Autograd:

Efektywnie oblicza pochodne kodu numpy ”.

Żeby zainstalować:

pip install autograd

Oto przykład:

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

Może również obliczać gradienty funkcji złożonych, np. Funkcji wielowymiarowych.


Cześć, czy ta funkcja może służyć do numerycznego rozróżniania dwóch kolumn danych poprzez podanie długości kroku? dzięki
Ayan Mitra

3

W zależności od wymaganego poziomu dokładności możesz to rozwiązać samodzielnie, korzystając z prostego dowodu różnicowania:

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

nie możemy właściwie przyjąć granicy gradientu, ale to trochę zabawne. Musisz jednak uważać, ponieważ

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.