我尝试了以下内容:
spline= interpolate.InterpolatedUnivariateSpline(X, Y, k=3)
coefs= spline.get_coeffs()
X
和Y
分别有五个值,最后我还coefs
五个价值观。鉴于五个数据点意味着四个样条部分,和
一个三次多项式有四个系数,我希望得到
四次四次= 16次系数。有谁知道如何解释get_coeffs
方法返回的值?有没有记录这个的地方?
答案 0 :(得分:1)
这些不是x,x ** 2的系数,等等:这样的单项式不适合表示样条。相反,它们是B-splines的系数,它们是针对进行插值的特定网格计算的。所涉及的B样条的数量等于数据点的数量,并且系数的数量也是如此。例如,假设我们想要插入这些数据:
xv = [0, 1, 2, 3, 4, 5]
yv = [3, 6, 5, 7, 9, 1]
从更简单的k = 1(分段线性样条)的情况开始。然后B样条是这些"三角帽"功能:
其中有6个。它们中的每一个等于1,其中"网格点,所有其他网格点为0。这使得编写插值样条线非常容易:它是y[0]*b[0] + ... + y[5]*b[5]
。实际上,get_coeffs
显示系数是y值本身。
InterpolatedUnivariateSpline(xv, yv, k=1).get_coeffs() # [ 3., 6., 5., 7., 9., 1.]
现在它变得毛茸茸,因为我们需要"帽子"这是平滑的,而不是像上面那样尖锐。平滑度要求强制它们更宽,因此每个B样条曲线在几个网格点上具有非零值。 (技术性:立方B样条具有非零值,最高可达3节,但在下图中,1和4尽管是网格点,但由于所谓的"而不是结#34而不是结。没关系。)以下是我们网格的B样条:
为了得到这些,我使用了scipy.interpolate的旧方法splrep
和splev
,它们在引擎盖下调用相同的fitpack例程。这里的系数向量是元组tck的第二个条目;我将其修改为一个1,其余为0,从而创建基本样条(b样条)。
k = 3
tck = splrep(xv, yv, s=0, k=k)
xx = np.linspace(min(xv), max(xv), 500)
bsplines = []
for j in range(len(xv)):
tck_mod = (tck[0], np.arange(len(xv)+2*k-2) == j, k)
bsplines.append(splev(xx, tck_mod))
plt.plot(xx, bsplines[-1])
现在我们有一个列表bsplines
,我们可以使用get_coeffs
返回的系数将它们组合成一个插值样条:
coeffs = InterpolatedUnivariateSpline(xv, yv, k=3).get_coeffs()
interp_spline = sum([coeff*bspline for coeff, bspline in zip(coeffs, bsplines)])
plt.plot(xx, interp_spline)
如果你想要这些B样条曲线的公式,B-splines上的Cox-de Boor递推公式可以提供帮助,但这些都是手工计算的苦差事。
SymPy可以给formulas for B-splines,但有一点扭曲。一个人应该通过重复像
这样的结束值来传递一组填充的结[0, 0, 0, 0, 2, 3, 5, 5, 5, 5]
这是因为在0和5处,所有四个系数都改变了值,而在1和4处都没有改变,所以它们被省略("不是结")。 (此外,当前版本的SymPy(1.1.1)存在重复结的问题,但这将在下一版本中修复。)
from sympy import symbols, bspline_basis_set, plot
x = symbols('x')
xv_padded = [0, 0, 0, 0, 2, 3, 5, 5, 5, 5]
bs = bspline_basis_set(3, xv_padded, x)
现在bs
是一系列可怕的分段公式:
[Piecewise((-x**3/8 + 3*x**2/4 - 3*x/2 + 1, (x >= 0) & (x <= 2)), (0, True)),
Piecewise((19*x**3/72 - 5*x**2/4 + 3*x/2, (x >= 0) & (x <= 2)), (-x**3/9 + x**2 - 3*x + 3, (x >= 2) & (x <= 3)), (0, True)),
Piecewise((-31*x**3/180 + x**2/2, (x >= 0) & (x <= 2)), (11*x**3/45 - 2*x**2 + 5*x - 10/3, (x >= 2) & (x <= 3)), (-x**3/30 + x**2/2 - 5*x/2 + 25/6, (x >= 3) & (x <= 5)), (0, True)),
Piecewise((x**3/30, (x >= 0) & (x <= 2)), (-11*x**3/45 + 5*x**2/3 - 10*x/3 + 20/9, (x >= 2) & (x <= 3)), (31*x**3/180 - 25*x**2/12 + 95*x/12 - 325/36, (x >= 3) & (x <= 5)), (0, True)),
Piecewise((x**3/9 - 2*x**2/3 + 4*x/3 - 8/9, (x >= 2) & (x <= 3)), (-19*x**3/72 + 65*x**2/24 - 211*x/24 + 665/72, (x >= 3) & (x <= 5)), (0, True)),
Piecewise((x**3/8 - 9*x**2/8 + 27*x/8 - 27/8, (x >= 3) & (x <= 5)), (0, True))]