N次元で最も低い勾配を見つけたい一連のシミュレーションデータがあります。データの間隔は各次元に沿って一定ですが、すべて同じではありません(簡単にするために変更することもできます)。
特に端に向かって、私はいくつかの数値の不正確さを抱えて生きることができます。スプラインを生成せず、その導関数を使用しないほうがいいと思います。そのままの値で十分です。
numpy.gradient()
関数を使用すると、numpy
を使用して1次導関数を計算できます。
_import numpy as np
data = np.random.Rand(30,50,40,20)
first_derivative = np.gradient(data)
# second_derivative = ??? <--- there be kudos (:
_
これはラプラス対ヘシアン行列に関するコメントです。これはもはや問題ではありませんが、将来の読者の理解を助けることを目的としています。
テストケースとして2D関数を使用して、しきい値を下回る「最も平坦な」領域を決定します。次の図は、最小値のsecond_derivative_abs = np.abs(laplace(data))
と最小値の使用の結果の違いを示しています。
_second_derivative_abs = np.zeros(data.shape)
hess = hessian(data)
# based on the function description; would [-1] be more appropriate?
for i in hess[0]: # calculate a norm
for j in i[0]:
second_derivative_abs += j*j
_
カラースケールは関数値、矢印は1次導関数(勾配)、赤い点はゼロに最も近い点、赤い線はしきい値を表します。
データのジェネレーター関数は_( 1-np.exp(-10*xi**2 - yi**2) )/100.0
_で、xiは_np.meshgrid
_で生成されました。
ラプラス:
ヘッセ行列:
2次導関数は ヘッシアン行列 で与えられます。 Python ND配列の実装です。これは、np.gradient
2回出力を適切に保存し、
import numpy as np
def hessian(x):
"""
Calculate the hessian matrix with finite differences
Parameters:
- x : ndarray
Returns:
an array of shape (x.dim, x.ndim) + x.shape
where the array[i, j, ...] corresponds to the second derivative x_ij
"""
x_grad = np.gradient(x)
hessian = np.empty((x.ndim, x.ndim) + x.shape, dtype=x.dtype)
for k, grad_k in enumerate(x_grad):
# iterate over dimensions
# apply gradient again to every component of the first derivative.
tmp_grad = np.gradient(grad_k)
for l, grad_kl in enumerate(tmp_grad):
hessian[k, l, :, :] = grad_kl
return hessian
x = np.random.randn(100, 100, 100)
hessian(x)
2次導関数の大きさだけに関心がある場合は、 ラプラス演算子scipy.ndimage.filters.laplace
、これはヘッセ行列のトレース(対角要素の合計)です。
ヘッセ行列の最小要素を取ることは、あらゆる空間方向の最低勾配を推定するために使用できます。
ヘッセ行列を勾配の勾配として見ることができます。ここで計算された最初の勾配の各成分に2回勾配を適用すると、ここで計算されたWikipediaです link ヘッセ行列を定義し、それが勾配の勾配、これが勾配を定義するpython実装、次にヘッセ行列です:
import numpy as np
#Gradient Function
def gradient_f(x, f):
assert (x.shape[0] >= x.shape[1]), "the vector should be a column vector"
x = x.astype(float)
N = x.shape[0]
gradient = []
for i in range(N):
eps = abs(x[i]) * np.finfo(np.float32).eps
xx0 = 1. * x[i]
f0 = f(x)
x[i] = x[i] + eps
f1 = f(x)
gradient.append(np.asscalar(np.array([f1 - f0]))/eps)
x[i] = xx0
return np.array(gradient).reshape(x.shape)
#Hessian Matrix
def hessian (x, the_func):
N = x.shape[0]
hessian = np.zeros((N,N))
Gd_0 = gradient_f( x, the_func)
eps = np.linalg.norm(Gd_0) * np.finfo(np.float32).eps
for i in range(N):
xx0 = 1.*x[i]
x[i] = xx0 + eps
Gd_1 = gradient_f(x, the_func)
hessian[:,i] = ((Gd_1 - Gd_0)/eps).reshape(x.shape[0])
x[i] =xx0
return hessian
テストとして、(x ^ 2 + y ^ 2)のヘッセ行列は 2 * I_2 ここで、I_2は次元2の単位行列です
スロープ、ヘシアン、ラプラシアンは関連していますが、3つの異なるものです。
2dで開始:2つの変数の関数(x、y)。丘の範囲の高さマップ、
勾配別名勾配は、方向ベクトル、各ポイントの方向と長さ_x y
_です。
これは、デカルト座標では2つの数値_dx dy
_、極座標では角度θと長さsqrt( dx^2 + dy^2 )
で指定できます。丘の全範囲にわたって、 ベクトルフィールド を取得します。
ヘシアンは_x y
_付近の曲率を記述します。放物面またはサドル、4つの数字:_dxx dxy dyx dyy
_。
ラプラシアンは、各点で_dxx + dyy
_の1つの数値_x y
_です。丘の範囲にわたって、 スカラーフィールド を取得します。 ( Laplacian = 0 の関数または丘は特に滑らかです。)
勾配は線形近似とヘッセ行列の二次近似であり、点の近くの小さなステップh
の場合xy
:
_f(xy + h) ~ f(xy)
+ slope . h -- dot product, linear in both slope and h
+ h' H h / 2 -- quadratic in h
_
ここで、xy
、slope
およびh
は2つの数値のベクトルであり、H
は4つの数値の行列_dxx dxy dyx dyy
_です。
N-dも同様です。各点での勾配はN数値の方向ベクトル、ヘッシアンはN ^ 2数値、ラプラシアン1数値の行列です。
( math.stackexchange でより良い答えが見つかるかもしれません。)