简体   繁体   English

python中的scipy BSpline拟合

[英]scipy BSpline fitting in python

This is my first time using BSpline, and I want to fit a curve to my data points.这是我第一次使用 BSpline,我想为我的数据点拟合一条曲线。 I've tried using Univariate Spline and attempted to use splev and splrep but I'd really like to learn how to do this using BSpline.我尝试过使用 Univariate Spline 并尝试使用 splev 和 splrep,但我真的很想学习如何使用 BSpline 来做到这一点。

It looks like my fitting is really choppy and the line isn't even going through the points.看起来我的配件真的很断断续续,这条线甚至没有穿过这些点。

arraymagU = linspace(U_timeband.min(),U_timeband.max(),300) #array for my x data points
UfunctionBS = BSpline(U_timeband,U_magband,k=4,extrapolate=False)
arraymagU2 = UfunctionBS(arraymagU)

plt.plot(arraymagU,arraymagU2)

U_timeband is my x coordinates and U_magband is simply my y. U_timeband 是我的 x 坐标,U_magband 只是我的 y。 k=4 I think indicates a cubic fit? k=4 我认为表示三次拟合? I've played around with that value and it doesn't seem to make it better.我已经玩过了这个价值,但它似乎并没有让它变得更好。

It produces this:它产生这个:

这

How can I make this better, consistent?我怎样才能使它更好,更一致? I think I may have to define breakpoints, but I'm not sure how to do that either.我想我可能需要定义断点,但我也不知道该怎么做。

splrep returns a tuple (t,c,k) containing the vector of knots, the B-spline coefficients, and the degree of the spline. splrep返回一个元组(t,c,k)其中包含节点向量、B 样条系数和样条的数。 These can be fed to interpolate.BSpline to create a BSpline object:这些可以提供给interpolate.BSpline以创建一个 BSpline 对象:

import numpy as np
import scipy.interpolate as interpolate
import matplotlib.pyplot as plt

x = np.array([ 0. ,  1.2,  1.9,  3.2,  4. ,  6.5])
y = np.array([ 0. ,  2.3,  3. ,  4.3,  2.9,  3.1])

t, c, k = interpolate.splrep(x, y, s=0, k=4)
print('''\
t: {}
c: {}
k: {}
'''.format(t, c, k))
N = 100
xmin, xmax = x.min(), x.max()
xx = np.linspace(xmin, xmax, N)
spline = interpolate.BSpline(t, c, k, extrapolate=False)

plt.plot(x, y, 'bo', label='Original points')
plt.plot(xx, spline(xx), 'r', label='BSpline')
plt.grid()
plt.legend(loc='best')
plt.show()

在此处输入图片说明

BSpline allows you to construct a b-spline if you know its coefficients.如果您知道BSpline的系数,则BSpline允许您构建b 样条。 If you want to fit these coefficients, you'll have to use something like splrep .如果要拟合这些系数,则必须使用splrep类的splrep The alternative would be to do a linear regression on the BSpline.basis_elemement s, but it's almost surely better to use splrep for your use-case.另一种方法是对BSpline.basis_elemement进行线性回归,但对于您的用例,使用splrep几乎肯定会更好。

It's usually necessary to give the knots, but thankfully it's not too complicated.通常有必要打结,但幸运的是这并不太复杂。 The accepted answer (exact fit with s=0 ) essentially sets the knots to the interior points of the input coordinates, but with noisy data it will overfit and still be quite "choppy":接受的答案(与s=0完全匹配)本质上将节点设置为输入坐标的内部点,但是对于嘈杂的数据,它会过度拟合并且仍然非常“不稳定”:

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import BSpline, splrep, splev

# Generate
np.random.seed(0)
n = 300
ts = np.sort(np.random.uniform(0, 5, size=n))
ys = np.sin(ts) + 0.1*np.random.randn(n)

# Fit
tck = splrep(ts, ys, t=ts[2:-2], k=3)
# Alternative:
# tck = splrep(ts, ys, s=0, k=3)
ys_interp = splev(ts, tck)

# Display
plt.figure(figsize=(12, 6))
plt.plot(ts, ys, '.c')
plt.plot(ts, ys_interp, '-m')
plt.show()

断断续续的情节

A usually better way is to define the knots to be the quantiles of the input coordinates, choosing a reasonable number (I find that 5-10 works well for simple shapes):通常更好的方法是将节点定义为输入坐标的分位数,选择一个合理的数字(我发现 5-10 对简单形状很有效):

# Fit
n_interior_knots = 5
qs = np.linspace(0, 1, n_interior_knots+2)[1:-1]
knots = np.quantile(ts, qs)
tck = splrep(ts, ys, t=knots, k=3)
ys_smooth = splev(ts, tck)

# Alternative if one really wants to use BSpline: 
# ys_smooth = BSpline(*tck)(ts)

# Display
plt.figure(figsize=(12, 6))
plt.plot(ts, ys, '.c')
plt.plot(ts, ys_smooth, '-m')
plt.show()

平滑图

请注意,要使用interpolate.BSpline您需要 scipy 0.19 或更高版本(请参阅: https ://docs.scipy.org/doc/scipy/reference/release.0.19.0.html#scipy-interpolate-improvements)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM