Как рассчитать производную от функции, например
y = x 2 +1
с помощью numpy
?
Скажем, я хочу, чтобы значение производной при x = 5...
Как рассчитать производную от функции, например
y = x 2 +1
с помощью numpy
?
Скажем, я хочу, чтобы значение производной при x = 5...
У вас есть четыре варианта
Конечные различия не требуют внешних инструментов, но подвержены числовой ошибке и, если вы находитесь в многомерной ситуации, могут занять некоторое время.
Символическое дифференцирование идеально, если ваша проблема достаточно проста. Символические методы в настоящее время становятся довольно устойчивыми. SymPy - отличный проект для этого, который хорошо интегрируется с NumPy. Посмотрите на функции autowrap или lambdify или зайдите в блог Jensen о подобном вопросе.
Автоматические производные очень классные, не подвержены числовым ошибкам, но требуют некоторых дополнительных библиотек (для этого есть несколько хороших вариантов). Это самый надежный, но также самый сложный/сложный выбор. Если вы отлично ограничиваете себя синтаксисом 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.]
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)
Самый простой способ, которым я могу думать, - использовать функцию градиента 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).
Я поставлю еще один метод на куче...
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)
Предполагая, что вы хотите использовать 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
В зависимости от уровня точности, который вы требуете, вы можете сами это исправить, используя простое доказательство дифференциации:
>>> (((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
Для расчета градиентов сообщество машинного обучения использует Autograd:
Установить:
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))
Он также может вычислять градиенты сложных функций, например многомерных функций.