Python 中的二阶导数 - scipy/numpy/pandas

Posted

技术标签:

【中文标题】Python 中的二阶导数 - scipy/numpy/pandas【英文标题】:Second Derivative in Python - scipy/numpy/pandas 【发布时间】:2017-03-06 16:47:09 【问题描述】:

我正在尝试在 python 中使用两个 numpy 数据数组进行二阶导数。

例如,有问题的数组如下所示:

import numpy as np

x = np.array([ 120. ,  121.5,  122. ,  122.5,  123. ,  123.5,  124. ,  124.5,
        125. ,  125.5,  126. ,  126.5,  127. ,  127.5,  128. ,  128.5,
        129. ,  129.5,  130. ,  130.5,  131. ,  131.5,  132. ,  132.5,
        133. ,  133.5,  134. ,  134.5,  135. ,  135.5,  136. ,  136.5,
        137. ,  137.5,  138. ,  138.5,  139. ,  139.5,  140. ,  140.5,
        141. ,  141.5,  142. ,  142.5,  143. ,  143.5,  144. ,  144.5,
        145. ,  145.5,  146. ,  146.5,  147. ])

y = np.array([  1.25750000e+01,   1.10750000e+01,   1.05750000e+01,
         1.00750000e+01,   9.57500000e+00,   9.07500000e+00,
         8.57500000e+00,   8.07500000e+00,   7.57500000e+00,
         7.07500000e+00,   6.57500000e+00,   6.07500000e+00,
         5.57500000e+00,   5.07500000e+00,   4.57500000e+00,
         4.07500000e+00,   3.57500000e+00,   3.07500000e+00,
         2.60500000e+00,   2.14500000e+00,   1.71000000e+00,
         1.30500000e+00,   9.55000000e-01,   6.65000000e-01,
         4.35000000e-01,   2.70000000e-01,   1.55000000e-01,
         9.00000000e-02,   5.00000000e-02,   2.50000000e-02,
         1.50000000e-02,   1.00000000e-02,   1.00000000e-02,
         1.00000000e-02,   1.00000000e-02,   1.00000000e-02,
         1.00000000e-02,   1.00000000e-02,   5.00000000e-03,
         5.00000000e-03,   5.00000000e-03,   5.00000000e-03,
         5.00000000e-03,   5.00000000e-03,   5.00000000e-03,
         5.00000000e-03,   5.00000000e-03,   5.00000000e-03,
         5.00000000e-03,   5.00000000e-03,   5.00000000e-03,
         5.00000000e-03,   5.00000000e-03])

我目前有f(x) = y,我想要d^2 y / dx^2

在数值上,我知道我可以对函数进行插值并分析求导,也可以使用higher order finite-differences。我认为有足够的数据可以使用,如果一个或另一个被认为更快、更准确等。

我查看了 np.interp()scipy.interpolate 没有成功,因为这返回了一个拟合(线性或三次)样条曲线,但不知道如何获得该点的导数。

非常感谢任何指导。

【问题讨论】:

你看过np.diff吗? 我担心我的数据点间距不均匀。 【参考方案1】:

您可以使用 scipy 的一维 Splines 函数对数据进行插值。计算样条有一个方便的derivative 方法来计算导数。

对于您示例的数据,使用 UnivariateSpline 给出以下拟合

import matplotlib.pyplot as plt
from scipy.interpolate import UnivariateSpline

y_spl = UnivariateSpline(x,y,s=0,k=4)

plt.semilogy(x,y,'ro',label = 'data')
x_range = np.linspace(x[0],x[-1],1000)
plt.semilogy(x_range,y_spl(x_range))

合身看起来相当不错,至少在视觉上是这样。您可能想试验UnivariateSpline 使用的参数。

样条拟合的二阶导数可以简单地获得为

y_spl_2d = y_spl.derivative(n=2)

plt.plot(x_range,y_spl_2d(x_range))

结果看起来有些不自然(如果您的数据对应于某个物理过程)。您可能想要更改样条拟合参数、改进数据(例如,提供更多样本、执行较少噪声的测量),或者决定使用分析函数对数据进行建模并执行曲线拟合(例如,使用 sicpy 的 curve_fit )

【讨论】:

这个数据应该代表一个概率密度函数。规范化这条曲线和应用一些规则(比如没有负值)等的最佳方法是什么? 我认为没有标准答案,因为使用通用插值方法的方法在施加约束方面的选择有限。原则上,您需要从头开始制定和解决约束优化问题。您可能希望首先标准化您的数据,因为y_spl.integral(x[0],x[-1]) 大约是 80,这当然不是 pdf 的有效值。 这个答案与两次使用np.diff 的比率有何不同?在数值上是好是坏?【参考方案2】:

通过有限差分,数组上 x 的每个平均值的 y 的一阶导数由下式给出:

dy=np.diff(y,1)
dx=np.diff(x,1)
yfirst=dy/dx

而x对应的值为:

xfirst=0.5*(x[:-1]+x[1:])

对于第二个订单,再次执行相同的过程:

dyfirst=np.diff(yfirst,1)
dxfirst=np.diff(xfirst,1)
ysecond=dyfirst/dxfirst

xsecond=0.5*(xfirst[:-1]+xfirst[1:])

【讨论】:

np.diff(np.diff([x*x for x in range(0,10)])) = [2,2,2..]

以上是关于Python 中的二阶导数 - scipy/numpy/pandas的主要内容,如果未能解决你的问题,请参考以下文章

什么是一阶导数和二阶导数?

Jacobian矩阵、Hessian矩阵和多元函数的二阶导数

OpenCV之图像梯度 – 拉普拉斯算子(二阶导数算子)

OpenCV之图像梯度 – 拉普拉斯算子(二阶导数算子)

一阶导数/微分和二阶导数/微分算子在图像锐化处理方面的区别

求一阶导数,求详细计算过程