Scipy中splprep与splrep处理同数据返回不同结果的问题
样条拟合差异解析:splprep vs splrep/make_interp_spline
问题背景
用样条拟合一组数据点时,相同条件下splprep与splrep/make_interp_spline输出结果差异明显:splrep使用更便捷,但splprep的结果更符合需求——希望给定的点作为样条峰值,且点间插值效果与splprep一致,需明确差异原因。
拟合数据
x_points = [ 0, 5, 10, 15, 20, 30, 40, 50, 60] y_points = [12, 5, 19, 5, 19, 5, 19, 5 ,12]
实现代码与结果
1. splprep实现
def get_spline_points(xs, ys): mytck, myu = itp.splprep([xs, ys], k=2, s=0) xnew, ynew = itp.splev(np.linspace(0, 1, 1000), mytck) return (xnew, ynew)

2. splrep实现
def get_spline_points(xs, ys): mytck = itp.splrep(x=xs, y=ys, k=2, s=0) ys = itp.splev(np.arange(0, 60.5, 0.5), mytck) return ys

3. make_interp_spline实现
def get_spline_points(xs, ys): bspline = interpolate.make_interp_spline(xs, ys, k=2) fig, ax = plt.subplots() xs_n = np.arange(0, 60.5, 0.5) ys_n = bspline(xs_n) ax.plot(xs_n, ys_n, linewidth=2.0) ax.scatter(x_points, y_points, c='green') plt.show()
(结果与splrep一致)
差异原因
两类函数的核心逻辑完全不同:
splprep:参数化曲线插值
把x、y都视为参数u的函数(默认u是点间弧长累积值,s=0时强制通过所有输入点),拟合的是二维曲线的路径,不要求x单调。它会按曲线的节点密度(而非x轴间距)来分配样条的平滑度,因此能让每个原始点都成为曲线的关键峰值点,贴合需求。splrep/make_interp_spline:单变量函数插值
是传统的y=f(x)型插值,要求x严格单调(你的数据满足)。拟合时以x为自变量,最小化y的拟合误差,样条的平滑度受x轴间距影响:x密集区域样条变化更灵敏,稀疏区域(如你的x从20到30间距为10)则会过度平滑,导致峰值被拉平。
解决方案:兼顾易用性与拟合效果
如果想保留splrep的易用性,同时得到splprep的峰值拟合效果,可以手动构造参数u,分别拟合x(u)和y(u),再通过u生成插值点:
import numpy as np from scipy import interpolate as itp import matplotlib.pyplot as plt x_points = [0, 5, 10, 15, 20, 30, 40, 50, 60] y_points = [12, 5, 19, 5, 19, 5, 19, 5, 12] # 构造等距参数u u = np.linspace(0, 1, len(x_points)) # 分别拟合x关于u、y关于u的样条 tck_x = itp.splrep(u, x_points, k=2, s=0) tck_y = itp.splrep(u, y_points, k=2, s=0) # 生成高密度u点,得到插值后的x、y u_new = np.linspace(0, 1, 1000) x_new = itp.splev(u_new, tck_x) y_new = itp.splev(u_new, tck_y) # 可视化 plt.plot(x_new, y_new, linewidth=2.0) plt.scatter(x_points, y_points, c='green') plt.show()
内容的提问来源于stack exchange,提问作者Yoav Schwartz
相关产品推荐
相关产品推荐

