我想在Python中使用三维样条拟合噪声x,y数据并提取每个区间的样条系数(即我希望每个区间获得四个样条系数)
到目前为止,我已尝试过(全部来自scipy.interpolate):
1)CubicSpline,但这种方法不允许我平滑样条曲线,导致不切实际的跳跃系数数据。
2)组合splrep和splev,例如
tck = splrep(x, y, k=3, s=1e25)
我使用
提取系数/节点F = PPoly.from_spline(tck)
coeffs = F.c
knots = F.x
然而,我无法在整个x范围内找到平滑系数(在接近零和1e23的值之间跳转,这是非物理的),即使我将平滑参数s增加到非常大的数字,最终会导致数字太小结节数随着节数的减少而减少。似乎我无法同时找到合适的参数s和结数。
3)我用过 单变量样条(x,y,k = 3,s = 0.03) 在这里,我发现更改s的灵敏度更高,但相应的get_coeffs()方法不为每个区间提供4个系数,但只提供一个,我不明白。
4)我还尝试了使用三阶多项式的分段脊状线性回归,但是这种方法为拟合提供了太大的百分比误差,因此使其中一种标准样条方法起作用会很棒。
我错过了什么?有人可以帮忙吗?
答案 0 :(得分:2)
我在这里看到的具体问题是UnivariateSpline
不会在插值样条中产生x的各种幂的代数系数。这是因为它保留在私有_data
属性中的系数(也是get_coeffs
方法返回的属性)是B-spline coefficients的一种。这些系数描述了没有任何冗余的样条曲线(对于具有N个自由度的样条曲线,你需要它们的N个),但是它们附加到的样条的基础样条有些复杂。
但是,您可以使用样条线对象的derivatives
方法获得所需的系数。它返回给定点x处的所有四个导数,从中可以很容易地找到Taylor coefficients。使用这种方法很自然,x是插值的结,排除最右边的结;获得的系数从该结到下一个结是有效的。这是一个例子,完整的"花式"格式化输出。
import numpy as np
from scipy.interpolate import UnivariateSpline
spl = UnivariateSpline(np.arange(6), np.array([3, 1, 4, 1, 5, 9]), s=0)
kn = spl.get_knots()
for i in range(len(kn)-1):
cf = [1, 1, 1/2, 1/6] * spl.derivatives(kn[i])
print("For {0} <= x <= {1}, p(x) = {5}*(x-{0})^3 + {4}*(x-{0})^2 + {3}*(x-{0}) + {2}".format(kn[i], kn[i+1], *cf))
在这个例子中,结是0,2,3,5。输出是:
For 0.0 <= x <= 2.0, p(x) = -3.1222222222222222*(x-0.0)^3 + 11.866666666666667*(x-0.0)^2 + -10.744444444444445*(x-0.0) + 3.000000000000001
For 2.0 <= x <= 3.0, p(x) = 4.611111111111111*(x-2.0)^3 + -6.866666666666667*(x-2.0)^2 + -0.7444444444444436*(x-2.0) + 4.000000000000001
For 3.0 <= x <= 5.0, p(x) = -2.322222222222221*(x-3.0)^3 + 6.966666666666665*(x-3.0)^2 + -0.6444444444444457*(x-3.0) + 1.0000000000000016
请注意,对于每个片段,cf
保持从最低度开始的系数,因此在格式化字符串时顺序相反。
(当然,你可能想用这些系数做其他事情)
要检查公式是否正确,我将其复制粘贴以进行绘图: