web-dev-qa-db-ja.com

Numpyを使用して微分を計算するにはどうすればよいですか?

たとえば、関数の導関数を計算するにはどうすればよいですか

y = x2+1

numpyを使用していますか?

たとえば、x = 5での微分値が必要です...

75
DrStrangeLove

4つのオプションがあります

  1. 有限差分
  2. 自動デリバティブ
  3. シンボリック微分
  4. 手で導関数を計算します。

有限差分には外部ツールは必要ありませんが、数値エラーが発生しやすく、多変量の状況にある場合は時間がかかることがあります。

シンボリック微分は、問題が単純な場合に理想的です。シンボリックメソッドは、最近非常に堅牢になっています。 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.]
119
MRocklin

私が考えることができる最も簡単な方法は、 numpyの勾配関数 を使用することです:

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

このように、dydxは中心差分を使用して計算され、前方差分を使用して(n-1)サイズのベクトルを返すnumpy.diffとは異なり、yと同じ長さを持ちます。

32
Sparkler

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)
26
Sven Marnach

numpyを使用すると仮定すると、 Rigorous definition を使用して、任意の時点で関数の導関数を数値的に計算できます。

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
11
yellow01

パイルに別のメソッドをスローします...

scipy.interpolateの多くの補間スプラインは、導関数を提供できます。したがって、線形スプライン(k=1)を使用すると、スプラインの導関数(derivative()メソッドを使用)は前方差分と同等になります。完全には定かではありませんが、3次スプライン導関数を使用することは、3次スプラインを構成する前と後の値を使用するため、中央差分導関数に似ていると思います。

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

必要な精度のレベルに応じて、差別化の簡単な証明を使用して自分で解決できます。

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

勾配を計算するために、機械学習コミュニティは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))

複雑な関数の勾配も計算できます。多変量関数。

2