Как вычислить производную с помощью Numpy?

97

Как рассчитать производную функции, например

у = х 2 +1

используя numpy?

Скажем, мне нужно значение производной при x = 5 ...

DrStrangeLove
источник
5
Вам необходимо использовать Sympy: sympy.org/en/index.html Numpy - это библиотека числовых вычислений для Python
prrao
Или вам нужен метод оценки числового значения производной? Для этого вы можете использовать метод конечных разностей, но имейте в виду, что он очень шумный.
Генри Гомерсалл,

Ответы:

148

У вас есть четыре варианта

  1. Конечные различия
  2. Автоматические деривативы
  3. Символическая дифференциация
  4. Вычисляйте производные вручную.

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

Символическая дифференциация идеальна, если ваша проблема достаточно проста. В наши дни символические методы становятся все более надежными. SymPy - отличный проект для этого, который хорошо интегрируется с NumPy. Посмотрите на функции autowrap или lambdify или почитайте блог Дженсена по аналогичному вопросу .

Автоматические производные очень хороши, не подвержены числовым ошибкам, но требуют дополнительных библиотек (для этого есть несколько хороших вариантов в Google). Это самый надежный, но также самый сложный / сложный в настройке вариант. Если вы хорошо ограничиваетесь 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.]
MRocklin
источник
Извините, если это кажется глупым, в чем разница между 3. символической дифференциацией и 4. ручной дифференциацией ??
DrStrangeLove
11
Когда я сказал «символическое различие», я имел в виду, что этим процессом управляет компьютер. Принципиально 3 и 4 различаются только тем, кто выполняет эту работу: компьютер или программист. 3 предпочтительнее 4 из-за согласованности, масштабируемости и лени. 4 необходимо, если 3 не может найти решение.
MRocklin
4
В строке 7 мы создали функцию f, которая вычисляет производную y по x. В 8 мы применяем эту производную функцию к вектору всех единиц и получаем вектор всех двоек. Это потому, что, как указано в строке 6, yprime = 2 * x.
MRocklin
Просто для полноты вы также можете выполнить дифференцирование путем интегрирования (см. Интегральную формулу Коши), это реализовано, например, в mpmath(не уверен, однако, что именно они делают).
DerWeh
Есть ли простой способ сделать конечные различия в numpy, не реализуя его самостоятельно? например, я хочу найти градиент функции в заранее определенных точках.
Алекс
44

Самый простой способ, который я могу придумать, - это использовать функцию градиента 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 01
3
@ weberc2, в этом случае вы должны разделить один вектор на другой, но обрабатывать края отдельно с помощью прямых и обратных производных вручную.
Sparkler 02
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
fabda01
источник
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)
флейтефрик7
источник
просто попробовал это, я продолжаю получать ошибки от этой функции 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
Fraxel
источник
2

Вы можете использовать scipy, что довольно просто:

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

Найдите n-ю производную функции в точке.

В твоем случае:

from scipy.misc import derivative

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

derivative(f, 5, dx=1e-6)
# 10.00000000139778
Джонсон
источник