J'ai un ensemble de données de simulation où je voudrais trouver la pente la plus basse en n dimensions. L'espacement des données est constant le long de chaque dimension, mais pas toujours identique (je pourrais changer cela par souci de simplicité).
Je peux vivre avec quelques imprécisions numériques, en particulier vers les bords. Je préférerais fortement ne pas générer de spline et utiliser ce dérivé; juste sur les valeurs brutes serait suffisant.
Il est possible de calculer la première dérivée avec numpy
à l'aide de la fonction numpy.gradient()
.
import numpy as np
data = np.random.Rand(30,50,40,20)
first_derivative = np.gradient(data)
# second_derivative = ??? <--- there be kudos (:
Ceci est un commentaire concernant laplace par rapport à la matrice de Hessian; Ce n'est plus une question, mais vise à aider à la compréhension des futurs lecteurs.
J'utilise comme test une fonction 2D pour déterminer la zone la plus «plate» sous un seuil. Les images suivantes montrent la différence de résultats entre l'utilisation du minimum de second_derivative_abs = np.abs(laplace(data))
et du minimum des éléments suivants:
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
L'échelle de couleur décrit les valeurs des fonctions, les flèches représentent la première dérivée (dégradé), le point rouge le point le plus proche de zéro et la ligne rouge le seuil.
La fonction de générateur pour les données était ( 1-np.exp(-10*xi**2 - yi**2) )/100.0
avec xi, yi étant généré avec np.meshgrid
.
Laplace:
Toile de jute:
Les dérivées secondes sont données par la matrice Hessian . Voici une implémentation Python pour les tableaux ND, qui consiste à appliquer deux fois le np.gradient
et à stocker correctement la sortie,
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)
Notez que si vous êtes uniquement intéressé par la magnitude des dérivées secondes, vous pouvez utiliser l'opérateur Laplace implémenté par scipy.ndimage.filters.laplace
, qui est la trace (somme d'éléments diagonaux) de la matrice de Hessian.
Prendre le plus petit élément de la matrice de Hesse pourrait être utilisé pour estimer la pente la plus basse dans n'importe quelle direction spatiale.
Vous pouvez voir la matrice de Hesse sous forme de dégradé, où vous appliquez un dégradé une seconde fois pour chaque composant du premier dégradé calculé ici. Il s'agit d'une matrice de Hesse wikipedia link / et vous pouvez voir clairement qu'il s'agit d'un dégradé. , voici une implémentation en python définissant le dégradé puis le hessien:
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
Comme test, la matrice hessienne de (x ^ 2 + y ^ 2) est 2 * I_2 où I_2 est la matrice d'identité de la dimension 2