numpy.gradient 的作用是什么?
我知道数学函数的梯度是什么,所以我觉得我应该知道 numpy.gradient
是干嘛的。但我其实并不明白。文档也没有提供太多帮助:
返回一个N维数组的梯度。
那么,数组的梯度是什么呢?什么时候用到 numpy.gradient
呢?
4 个回答
把N维数组想象成一个矩阵。然后,梯度其实就是矩阵的微分。
如果想要更好的理解,可以看看MATLAB文档中关于梯度的描述。
这里发生了什么呢?泰勒级数展开告诉我们如何根据相近点的值来近似求导数。最简单的情况来自于一个有两个连续导数的函数的一级泰勒展开...
- f(x+h) = f(x) + f'(x)h + f''(xi)h^2/2。
我们可以求出 f'(x)...
- f'(x) = [f(x+h) - f(x)]/h + O(h)。
我们能做得更好吗?当然可以。如果我们假设有三个连续导数,那么泰勒展开是:
- f(x+h) = f(x) + f'(x)h + f''(x)h^2/2 + f'''(xi) h^3/6,
- f(x-h) = f(x) - f'(x)h + f''(x)h^2/2 - f'''(xi) h^3/6。
把这两个式子相减(h^0 和 h^2 的项会消掉!),然后求出 f'(x):
- f'(x) = [f(x+h) - f(x-h)]/(2h) + O(h^2)。
所以,如果我们有一个在等间距上定义的离散函数: x = x_0, x_0+h(=x_1),....,x_n=x_0+h*n,那么 numpy 的梯度函数会在两端使用一级估计,在中间使用更好的估计来生成一个“导数”数组。
例子 1. 如果你没有指定任何间距,默认间隔为 1。所以如果你调用
f = np.array([5, 7, 4, 8])
你实际上是在说 f(0) = 5, f(1) = 7, f(2) = 4, 和 f(3) = 8。那么
np.gradient(f)
将会是: f'(0) = (7 - 5)/1 = 2, f'(1) = (4 - 5)/(2*1) = -0.5, f'(2) = (8 - 7)/(2*1) = 0.5, f'(3) = (8 - 4)/1 = 4。
例子 2. 如果你指定了一个间距,那么间距是均匀的,但不一定是 1。
例如,如果你调用
np.gradient(f, 0.5)
这表示 h = 0.5,而不是 1,也就是说,函数实际上是 f(0) = 5, f(0.5) = 7, f(1.0) = 4, f(1.5) = 8。最终效果是把 h = 1 替换成 h = 0.5,所有结果都会翻倍。
例子 3. 假设离散函数 f(x) 不是在均匀间隔上定义的,比如 f(0) = 5, f(1) = 7, f(3) = 4, f(3.5) = 8,那么 numpy 的梯度函数会使用一种更复杂的离散化求导函数,你可以通过调用
np.gradient(f, np.array([0,1,3,3.5]))
来得到离散的导数。
最后,如果你的输入是一个二维数组,那么你可以把它看作是在一个网格上定义的函数 f(x, y)。numpy 的梯度函数将输出 x 和 y 方向的“离散化”偏导数数组。
在文档中还有提到:
>>> y = np.array([1, 2, 4, 7, 11, 16], dtype=np.float)
>>> j = np.gradient(y)
>>> j
array([ 1. , 1.5, 2.5, 3.5, 4.5, 5. ])
梯度的定义是(
y
的变化)/(x
的变化)。这里的
x
是列表的索引,所以相邻值之间的差就是1。在边界处,计算的是第一个差值。这意味着在数组的两端,给出的梯度只是最后两个值之间的差(除以1)。
在边界之外,某个特定索引的梯度是通过取两边的值之差,然后除以2来计算的。
所以,上面y
的梯度是这样计算的:
j[0] = (y[1]-y[0])/1 = (2-1)/1 = 1
j[1] = (y[2]-y[0])/2 = (4-1)/2 = 1.5
j[2] = (y[3]-y[1])/2 = (7-2)/2 = 2.5
j[3] = (y[4]-y[2])/2 = (11-4)/2 = 3.5
j[4] = (y[5]-y[3])/2 = (16-7)/2 = 4.5
j[5] = (y[5]-y[4])/1 = (16-11)/1 = 5
你可以在结果数组中找到所有绝对值的最小值,以此来找到曲线的转折点,例如。
1在文档的例子中,数组实际上叫x
,我把它改成y
是为了避免混淆。