我有一组模拟数据,我希望在n维中找到最低的斜率。数据的间距沿着每个维度是恒定的,但不是全部相同(为了简单起见,我可以改变它)。
我可以忍受一些数字不准确,尤其是边缘。我非常希望不生成样条并使用该衍生物;仅仅根据原始值就足够了。
可以使用numpy
函数计算numpy.gradient()
的一阶导数。
import numpy as np
data = np.random.rand(30,50,40,20)
first_derivative = np.gradient(data)
# second_derivative = ??? <--- there be kudos (:
这是关于拉普拉斯与粗麻布矩阵的评论;这不再是一个问题,而是为了帮助理解未来的读者。
我使用2D功能作为测试用例来确定最平坦的&#39;低于阈值的区域。以下图片显示了使用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-np.exp(-10*xi**2 - yi**2) )/100.0
,其中xi,yi由np.meshgrid
生成。
拉普拉斯:
的Hessian:
答案 0 :(得分:16)
二阶导数由Hessian matrix给出。这是ND数组的Python实现,包括应用np.gradient
两次并适当地存储输出,
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)
请注意,如果您只对二阶导数的大小感兴趣,可以使用Laplace operator实现的scipy.ndimage.filters.laplace
,这是Hessian矩阵的跟踪(对角元素之和)。
采用Hessian矩阵的最小元素可用于估计任何空间方向上的最低斜率。
答案 1 :(得分:1)
你可以看到Hessian矩阵是一个渐变渐变,你在这里计算的第一个渐变的每个分量第二次应用渐变是维基百科link definig Hessian矩阵,你可以清楚地看到它是一个渐变渐变,这里是一个定义渐变的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)的Hessian矩阵 2 * I_2 其中I_2是维数2的单位矩阵
答案 2 :(得分:0)
坡度,黑森州和拉普拉斯人是相关的,但有3种不同。
以2d开头:2个变量的函数(x,y),例如一系列丘陵的高度图,
斜率(也称为梯度)是方向矢量,每个点x y
上的方向和长度。
可以通过笛卡尔坐标中的两个数字dx dy
来给出,
或极坐标中的角度θ和长度sqrt( dx^2 + dy^2 )
。
在整个山丘上,我们得到了
vector field。
黑森斯描述x y
附近的曲率,例如抛物面或鞍形
有4个数字:dxx dxy dyx dyy
。
拉普拉斯算子在每个点dxx + dyy
上都是1个数字x y
。
在一系列的山丘上,我们得到了
scalar field。
(具有Laplacian = 0的功能或丘陵
特别平滑。)
对于点h
附近的微小步长xy
,坡度是线性拟合,并且是Hessians二次拟合:
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个数字的方向向量, 在每个点上,Hessian都是N ^ 2数的矩阵,而Laplacians是1数的矩阵。
(您可能会在上找到更好的答案 math.stackexchange。)
答案 3 :(得分:0)
hessians = np.asarray(np.gradient(np.gradient(f(X, Y))))
hessians[1:]
为 3-d 函数 f 工作。