Як обчислити похідну за допомогою Numpy?


95

Як я можу обчислити похідну функції, наприклад

y = x 2 +1

використання numpy?

Скажімо, я хочу значення похідної при x = 5 ...


5
Вам потрібно використовувати Sympy: symy.org/en/index.html Numpy - це числова обчислювальна бібліотека для Python
пррао

Як варіант, вам потрібен метод оцінки числового значення похідної? Для цього ви можете використовувати метод кінцевих різниць, але майте на увазі, що вони, як правило, страшенно галасливі.
Генрі Гомерсалл,

Відповіді:


146

У вас є чотири варіанти

  1. Кінцеві відмінності
  2. Автоматичні похідні
  3. Символічна диференціація
  4. Обчислити похідні від руки.

Кінцеві відмінності не вимагають зовнішніх інструментів, але вони схильні до чисельних помилок, і, якщо ви перебуваєте в багатовимірній ситуації, це може зайняти деякий час.

Символічна диференціація ідеальна, якщо ваша проблема досить проста. Символічні методи в наш час стають досить надійними. SymPy - чудовий проект для цього, який добре інтегрується з NumPy. Подивіться на функції автоматичного обертання або лямбдіфікації або перегляньте допис блогу Дженсена про подібне питання .

Автоматичні похідні дуже класні, не схильні до числових помилок, але вимагають додаткових бібліотек (для цього потрібно погуглити, є кілька хороших варіантів). Це найнадійніший, але також найскладніший / складний у налаштуванні вибір. Якщо ви добре обмежуєтесь numpyсинтаксисом, то Theano може бути хорошим вибором.

Ось приклад використання 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.]

Вибачте, якщо це здається дурним, у чому різниця між 3.Символічною диференціацією та 4.за допомогою диференціації руками ??
DrStrangeLove

11
Коли я сказав "символічна диференціація", я мав на увазі, що процесом керував комп'ютер. В принципі 3 і 4 відрізняються лише тим, хто виконує роботу, комп'ютером або програмістом. 3 є кращим над 4 через послідовність, масштабованість та лінощі. 4 необхідний, якщо 3 не вдається знайти рішення.
MRocklin

4
У рядку 7 ми зробили f, функцію, яка обчислює похідну від y wrt x. У 8 ми застосуємо цю похідну функцію до вектора всіх одиниць і отримаємо вектор усіх подвійних. Це тому, що, як зазначено у рядку 6, yprime = 2 * x.
MRocklin

Тільки заради повноти ви також можете здійснити диференціацію шляхом інтеграції (див. Інтегральну формулу Коші), вона реалізована, наприклад, у mpmath(однак не впевнений, що саме вони роблять).
DerWeh

Чи є простий спосіб зробити кінцеві різниці в numpy, не застосовуючи це самостійно? Наприклад, я хочу знайти градієнт функції у визначених точках.
Олексій

42

Найбільш прямий спосіб, про який я можу придумати, - це використання функції градієнта Numpy :

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

Таким чином, dydx буде обчислюватися з використанням центральних різниць і матиме однакову довжину як y, на відміну від numpy.diff, який використовує прямі різниці і повертає (n-1) вектор розміру.


2
Що робити, якщо dx не є постійним?
weberc2

3
@ weberc2, у такому випадку вам слід розділити один вектор на інший, але обробляти ребра окремо похідними вперед і назад вручну.
Спарклер

2
Або ви можете інтерполювати y з константою dx, потім обчислити градієнт.
IceArdor

@Sparkler Дякую за вашу пропозицію. Якщо я можу задати 2 невеликі запитання, (i) чому ми переходимо dxдо numpy.gradientзамість x? (ii) Чи можемо ми також зробити останній ваш рядок таким чином dydx = numpy.gradient(y, numpy.gradient(x)):?
user929304

2
Починаючи з версії 1.13, нерівномірний інтервал можна вказати, використовуючи масив як другий аргумент. Див. Розділ Приклади на цій сторінці .
Натаніель Джонс,

28

NumPy не надає загальної функціональності для обчислення похідних. Однак він може обробляти простий особливий випадок поліномів:

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

Якщо ви хочете обчислити похідну чисельно, ви можете уникнути, використовуючи коефіцієнти центральної різниці для переважної більшості програм. Для похідної в одній точці формула буде приблизно такою

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

якщо у вас є масив xабсцис із відповідним масивом yзначень функції, ви можете обчислити наближення похідних з

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

2
«Обчислення числових похідних для більш загального випадку є простим» - я благаю сказати, обчислення числових похідних для загальних випадків досить складно. Ви просто вибрали гарні функції.
High Performance Mark

що означає 2 після >>> print p ?? (на 2-му рядку)
DrStrangeLove

@DrStrangeLove: Це показник ступеня. Він призначений для імітації математичних позначень.
Sven Marnach

@SvenMarnach це максимальний показник ?? або те, що?? Чому він вважає, що показник степеня 2? Ми ввели лише коефіцієнти ...
DrStrangeLove

2
@DrStrangeLove: вихідні дані слід читати як 1 * x**2 + 1. Вони ставлять 2у рядок вище, оскільки це показник ступеня. Подивіться на це здалеку.
Sven Marnach

15

Припускаючи, що ви хочете використовувати numpy, ви можете чисельно обчислити похідну функції в будь-якій точці, використовуючи суворе визначення :

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

Ви також можете використовувати симетричну похідну для кращих результатів:

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

На вашому прикладі повний код повинен виглядати приблизно так:

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

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

Тепер ви можете чисельно знайти похідну за адресою x=5:

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

8

Я кину ще один метод на купу ...

scipy.interpolateбагато інтерполюючих сплайнів здатні надати похідні. Отже, використовуючи лінійний сплайн ( k=1), похідна сплайна (за допомогою derivative()методу) повинна бути еквівалентна прямій різниці. Я не зовсім впевнений, але я вважаю, що використання кубічної сплайн-похідної було б подібним до похідної відцентрованої різниці, оскільки вона використовує значення до і після для побудови кубічного сплайну.

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)

щойно спробував це, я продовжую отримувати помилки від цієї функції AxisError: вісь -1 виходить за межі масиву розмірності 0, і я не бачу відповідей на це в спільноті, а також будь-яка допомога?
Аян Мітра,

Опублікуйте свою проблему як нове запитання та посилання на неї тут. Надання прикладу, який спричиняє помилку, можливо буде потрібно. Помилки, які виникають у мене з функціями інтерпу, зазвичай полягають у тому, що дані не добре сформовані - наприклад, повторювані значення, неправильна кількість розмірів, один із масивів випадково порожній, дані не сортуються по x або при сортуванні не є допустима функція тощо. Можливо, scipy неправильно викликає numpy, але дуже малоймовірно. Перевірте x.shape та y.shape. Перевірте, чи працює np.interp () - якщо ні, це може надати кориснішу помилку.
flutefreak7

6

Для обчислення градієнтів спільнота машинного навчання використовує Autograd:

" Ефективно обчислює похідні коду numpy. "

Щоб встановити:

pip install autograd

Ось приклад:

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

Він також може обчислювати градієнти складних функцій, наприклад багатовимірних функцій.


Привіт, чи можна використовувати цю функцію для розмежування двох стовпців даних чисельно, надаючи довжину кроку? подяка
Аян Мітра

3

Залежно від рівня точності, який вам потрібен, ви можете розробити це самостійно, використовуючи простий доказ диференціації:

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

ми насправді не можемо взяти межу градієнта, але це якось весело. Ти мусиш пильнувати, хоча тому, що

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.