1. 项目概述:为什么说插值与拟合是数模的“空气与水”?
搞数学建模的朋友,尤其是参加过国赛、美赛的,应该都听过一句话:“得数据者得天下”。但现实是,你拿到的数据往往不那么“天下太平”——数据点稀疏得像撒胡椒面、测量误差大得让你怀疑人生、或者干脆在某些关键区间缺了一大块。这时候,插值和拟合这两项技术,就不再是课本里冷冰冰的公式,而是你手里救命的“空气与水”,没有它们,你的模型可能连第一步都迈不出去。
简单来说,插值(Interpolation)干的是“无中生有”的精细活:在已知的离散数据点之间,构造一个光滑的曲线或曲面,让它精确地穿过每一个已知点。它的核心思想是“尊重原始数据”,适用于数据精度高、需要还原真实函数形态的场景,比如从有限个GPS轨迹点还原完整运动路径。
而拟合(Fitting),尤其是最小二乘法拟合,干的是“抓大放小”的概括活:它不要求曲线穿过每一个点,而是寻找一个整体趋势最优的函数,让所有数据点到这条曲线的“距离”平方和最小。它坦然接受数据有误差,目标是抓住主要矛盾,揭示数据背后的宏观规律,比如从一堆散乱的实验数据中找到物理定律的近似表达式。
在数模竞赛中,这两者几乎无处不在:物理题里用插值补全缺失的观测值;经济题里用拟合预测未来趋势;环境题里用曲面插值绘制污染分布图。可以说,从数据预处理到模型构建,再到结果可视化,插值拟合是贯穿始终的基础工具。接下来,我就结合自己多年带赛和评审的经验,把这套“组合拳”的里里外外、坑坑洼洼都给你拆解明白。
2. 核心思路解析:插值与拟合的本质区别与选用逻辑
很多新手会把插值和拟合混为一谈,或者简单理解为“一个要过点,一个不过点”。这没错,但太表面了。它们的本质区别,源于对数据误差的不同假设和处理哲学,这直接决定了你的应用场景。
2.1 插值:追求局部精确的“完美主义者”
插值是一个确定性问题。给定n+1个互不相同的节点,理论上存在唯一的一个不超过n次的多项式,可以精确穿过所有这些点(这就是拉格朗日插值定理)。插值函数在节点处的函数值必须等于给定值,这意味着它完全信任你提供的每一个数据点。
核心假设:已知数据点是精确无误的,或者误差小到可以忽略。任何偏离都是不可接受的。
典型场景:
- 数据补全:历史气温记录在某些日期缺失,需要用前后日期的记录插值出当天的估计值。
- 函数逼近:已知某个复杂函数在若干点的值(例如通过昂贵实验或仿真得到),需要快速获取该函数在其他任意点的值。例如,在有限元分析中,通过单元节点位移插值得到单元内部任意点的位移。
- 图像处理:图像放大(上采样)时,需要根据已知像素点的颜色值,插值计算出新像素点的颜色,如双线性插值、双三次插值。
注意:高次多项式插值(如用10个点做9次多项式插值)在节点之间可能产生剧烈的振荡(龙格现象),导致结果完全失真。因此,实践中对于多点插值,更常用的是分段低次插值(如分段线性、分段三次)或样条插值,以保证整体的稳定性和光滑性。
2.2 拟合:拥抱全局趋势的“务实主义者”
拟合是一个统计性问题。它承认观测数据存在随机误差(噪声)。拟合的目标不是复现每一个可能被污染的数据点,而是找出一个参数化的模型,使得模型对整个数据集的“解释”在统计意义上最优(通常指残差平方和最小)。
核心假设:数据存在观测误差或噪声。我们寻找的是隐藏在这些噪声背后的、更简洁的客观规律。
典型场景:
- 经验公式发现:通过一组实验数据(x, y),寻找y与x之间的近似函数关系,如指数衰减、幂律关系等。
- 趋势预测与回归分析:经济学中根据过去几年的GDP数据,拟合一个线性或多项式模型,用于预测未来增长趋势。
- 数据平滑:去除数据中的高频噪声,提取低频趋势信号。拟合出的曲线比原始散点更光滑,更能反映本质。
选用逻辑决策图: 当你拿到一组数据(x_i, y_i), i=1,2,...,n,可以问自己两个问题:
- 数据精度可靠吗?误差是否远小于数据变化幅度?
- 是 -> 优先考虑插值。
- 否 -> 进入问题2。
- 你的目标是还原每个细节,还是把握整体规律?
- 还原细节(如补缺、内插)-> 选用插值(注意避免高次振荡)。
- 把握规律(如预测、找公式)-> 选用拟合。
在实际数模中,更常见的是先拟合,后插值的思路。例如,在分析地区降雨量时,我们先对多年数据进行拟合,得到一个“平均”或“趋势”模型。然后,如果某一年数据缺失,我们可以用这个拟合模型在该年的预测值作为一个合理的估计,这本质上是一种基于模型的插值。
3. 关键算法详解与MATLAB/Python实操
理论说再多,不如一行代码。下面我们聚焦最核心、最常用的几种方法,用MATLAB和Python(NumPy/SciPy)分别实现,并对比其特点。
3.1 插值算法:从简单到强大
3.1.1 分段线性插值:最直观的“连连看”这就是用直线依次连接相邻数据点。方法简单,计算量小,但得到的曲线不光滑(导数不连续)。
% MATLAB x_known = [0, 1, 3, 4, 7]; y_known = [0, 2, 1, 4, 3]; x_query = linspace(0, 7, 100); % 生成100个待插值点 y_interp_linear = interp1(x_known, y_known, x_query, 'linear'); plot(x_known, y_known, 'o', x_query, y_interp_linear, '-');# Python import numpy as np from scipy import interpolate import matplotlib.pyplot as plt x_known = np.array([0, 1, 3, 4, 7]) y_known = np.array([0, 2, 1, 4, 3]) f_linear = interpolate.interp1d(x_known, y_known, kind='linear') x_query = np.linspace(0, 7, 100) y_interp_linear = f_linear(x_query) plt.plot(x_known, y_known, 'o', label='已知点') plt.plot(x_query, y_interp_linear, '-', label='线性插值') plt.legend() plt.show()3.1.2 三次样条插值:光滑的“柔性尺”这是工程和科学计算中的绝对主力。它用分段三次多项式连接节点,并保证连接点处不仅函数值连续,一阶和二阶导数也连续。结果非常光滑,物理意义明确(可类比为弹性梁的弯曲)。
% MATLAB 使用 'spline' 或 'pchip' y_interp_spline = interp1(x_known, y_known, x_query, 'spline'); % 样条插值 y_interp_pchip = interp1(x_known, y_known, x_query, 'pchip'); % 保形分段三次埃尔米特插值# Python f_cubic = interpolate.interp1d(x_known, y_known, kind='cubic') # 三次样条 # 或使用更强大的接口 spline_obj = interpolate.CubicSpline(x_known, y_known) y_interp_spline = spline_obj(x_query)实操心得:
‘spline’(样条)和‘pchip’(保形分段三次埃尔米特插值)是MATLAB中interp1的两种高级选项。简单来说,‘spline’更光滑,但可能在数据单调的区域产生非单调的插值(出现微小波动);‘pchip’能保持数据的单调性和形状,光滑性稍逊。如果你的数据本身是单调的(如随时间递增的累积量),用‘pchip’更安全。
3.1.3 网格数据插值:从曲线到曲面当你的数据是二维网格形式(例如,经纬度网格上的温度值),就需要二维插值。
% MATLAB 已知网格点 (X, Y) 及对应的值 Z, 插值到更密的网格 (XI, YI) [X, Y] = meshgrid(1:5, 1:5); Z = peaks(5); % 一个示例曲面数据 [XI, YI] = meshgrid(linspace(1,5,50), linspace(1,5,50)); ZI_linear = interp2(X, Y, Z, XI, YI, 'linear'); ZI_cubic = interp2(X, Y, Z, XI, YI, 'cubic'); surf(XI, YI, ZI_cubic);# Python from scipy.interpolate import griddata # 假设我们有散乱的二维数据点 points = np.random.rand(100, 2) # 100个随机点 (x, y) values = np.sin(points[:,0]*2*np.pi) * np.cos(points[:,1]*2*np.pi) # 对应的z值 # 定义规则网格 grid_x, grid_y = np.mgrid[0:1:50j, 0:1:50j] # 进行插值, method可选 'linear', 'cubic', 'nearest' grid_z_linear = griddata(points, values, (grid_x, grid_y), method='linear')踩坑记录:
interp2要求输入数据必须是规则网格。如果你的原始数据是散乱点,需要先用scatteredInterpolant(MATLAB)或griddata(Python)将其插值到规则网格上,才能进行后续的interp2操作或绘图。直接对散点用interp2会报错。
3.2 拟合算法:最小二乘法的七十二变
最小二乘法的核心是求解一个最优化问题:找到一组参数θ,使损失函数L(θ) = Σ(y_i - f(x_i; θ))^2最小。
3.2.1 线性拟合:万物的起点模型形式:y = a*x + b。虽然简单,却能揭示两个变量间最直接的关联。
% MATLAB x_data = [1,2,3,4,5]'; y_data = [1.9, 3.1, 3.9, 5.1, 6.0]'; p = polyfit(x_data, y_data, 1); % 1代表1次多项式,即线性 a = p(1); b = p(2); y_fit = polyval(p, x_data); plot(x_data, y_data, 'o', x_data, y_fit, 'r-'); legend('数据', sprintf('拟合直线: y=%.2fx+%.2f', a, b));# Python import numpy as np x_data = np.array([1,2,3,4,5]) y_data = np.array([1.9, 3.1, 3.9, 5.1, 6.0]) # 使用numpy的polyfit coefficients = np.polyfit(x_data, y_data, deg=1) a, b = coefficients # 使用poly1d对象方便计算 poly_func = np.poly1d(coefficients) y_fit = poly_func(x_data)如何解读结果?除了画出拟合线,一定要计算决定系数 R-squared。它表示模型对数据波动的解释程度,越接近1越好。
# Python 计算R^2 residuals = y_data - y_fit ss_res = np.sum(residuals**2) ss_tot = np.sum((y_data - np.mean(y_data))**2) r_squared = 1 - (ss_res / ss_tot) print(f"R-squared: {r_squared:.4f}")3.2.2 多项式拟合:小心“过拟合”陷阱模型形式:y = a0 + a1*x + a2*x^2 + ... + an*x^n。polyfit函数可以轻松搞定。
% MATLAB 用3次多项式拟合 p_cubic = polyfit(x_data, y_data, 3);关键问题:次数n怎么选?
- 画图观察:先画出散点图,看趋势是直线、抛物线还是更复杂的曲线。
- 交叉验证:将数据分为训练集和测试集。用训练集拟合不同次数的模型,在测试集上计算误差。选择测试误差最小的那个n。
- 看R^2变化:随着n增加,R^2会一直增加(因为模型更复杂)。但当n增加到一定程度,R^2的增幅会急剧变小,此时再增加n意义不大,反而容易过拟合。
- 奥卡姆剃刀原则:在效果相近的情况下,选择次数更低的简单模型。
血泪教训:我曾见过一个队,用9次多项式去拟合只有10个点的数据,R^2高达0.999,他们欣喜若狂。结果用来预测下一个点,误差离谱。这就是典型的过拟合:模型不仅学到了规律,还“记住”了噪声。在数模论文中,如果你用了高次多项式拟合,必须进行过拟合分析,比如展示不同次数下的拟合效果对比,或说明你通过交叉验证选择了当前次数。
3.2.3 非线性拟合:通向真实世界的钥匙很多物理、生物、经济模型都是非线性的,如指数衰减y = a * exp(-b*x)、幂律y = a * x^b、对数y = a + b*ln(x)等。
策略一:化为线性拟合(强力推荐!)这是处理非线性问题的大招。通过对变量或函数进行变换,将非线性模型转化为线性模型。
- 指数模型
y = a * e^(b*x)-> 两边取自然对数:ln(y) = ln(a) + b*x。令Y = ln(y),A = ln(a),则变为Y = A + b*x,对(x, Y)进行线性拟合。 - 幂律模型
y = a * x^b-> 两边取对数:ln(y) = ln(a) + b*ln(x)。令Y = ln(y),X = ln(x),A = ln(a),则变为Y = A + b*X。
# Python 指数拟合示例(线性化方法) x_data = np.array([0, 1, 2, 3, 4]) y_data = np.array([2.0, 1.5, 1.1, 0.85, 0.63]) # 近似指数衰减 # 线性化 Y = np.log(y_data) # 线性拟合 coefficients_lin = np.polyfit(x_data, Y, 1) b = coefficients_lin[0] A = coefficients_lin[1] a = np.exp(A) print(f"拟合参数: a={a:.3f}, b={b:.3f}") # 还原为非线性函数 y_fit_exp = a * np.exp(b * x_data)优点:计算简单、速度快、结果稳定。缺点:对原数据的误差分布有改变(对数变换后,y的恒定误差会变成比例误差),且只能处理可线性化的模型。
策略二:非线性最小二乘(lsqcurvefit/curve_fit)当模型无法线性化,或你想直接处理原始误差时,就用这个。
% MATLAB 使用 lsqcurvefit model = @(p, x) p(1) * exp(p(2) * x); % 定义模型函数 p0 = [2, -0.5]; % 初始参数猜测值,非常重要! [p_opt, resnorm] = lsqcurvefit(model, p0, x_data, y_data);# Python 使用 scipy.optimize.curve_fit from scipy.optimize import curve_fit def exp_func(x, a, b): return a * np.exp(b * x) popt, pcov = curve_fit(exp_func, x_data, y_data, p0=[2, -0.5]) a_opt, b_opt = popt print(f"非线性拟合参数: a={a_opt:.3f}, b={b_opt:.3f}") # pcov是参数的协方差矩阵,可用来计算标准差 perr = np.sqrt(np.diag(pcov)) print(f"参数标准差: a_err={perr[0]:.3f}, b_err={perr[1]:.3f}")致命要点:非线性拟合的初始值
p0至关重要!糟糕的初始值可能导致算法收敛到局部最优甚至发散。提供初始值有几种方法:1)根据物理意义估算;2)从图上大致读数;3)先用线性化方法得到一个粗略解,作为初始值。永远不要用全零或随机数作为复杂模型的初始值。
4. 数模实战全流程:从数据到论文图表
我们模拟一个数模竞赛中的常见场景,将上述技术串联起来。
场景:研究某湖泊不同位置、不同深度的水温垂直分布。由于测量成本高,只在少数几个位置和深度进行了采样。你的任务是:1) 拟合出每个位置水温随深度变化的经验公式;2) 在未测量的位置,插值出整个湖区的三维水温分布图。
4.1 第一步:数据探索与单点拟合假设在位置A,我们测得深度z(米)和温度T(摄氏度)数据如下:z = [0, 2, 5, 10, 15, 20, 30]T = [25.0, 24.2, 20.1, 15.5, 12.0, 10.1, 9.8]
画散点图发现,温度随深度增加迅速下降后趋于平缓,很像指数衰减或负幂函数。
- 尝试1:指数衰减拟合
T(z) = A * exp(B*z) + C。这里加了一个常数C,代表深水区的稳定温度。 - 尝试2:分段拟合。0-10米用二次多项式,10米以下用常数或线性。这更符合物理直觉(表层变化快,深层恒温)。
我们选择尝试1,因为它用一个光滑函数描述了全过程,参数少,便于后续分析。
# 实战代码:非线性拟合水温剖面 import numpy as np from scipy.optimize import curve_fit import matplotlib.pyplot as plt z_data = np.array([0, 2, 5, 10, 15, 20, 30]) T_data = np.array([25.0, 24.2, 20.1, 15.5, 12.0, 10.1, 9.8]) def model_exp(z, A, B, C): return A * np.exp(B * z) + C # 提供合理的初始值:A约等于表层与深层的温差,B应为负数,C约等于深层温度 p0 = [25-10, -0.2, 10] popt, pcov = curve_fit(model_exp, z_data, T_data, p0=p0) A_opt, B_opt, C_opt = popt print(f"拟合公式: T(z) = {A_opt:.2f} * exp({B_opt:.3f} * z) + {C_opt:.2f}") # 计算R^2 T_pred = model_exp(z_data, *popt) ss_res = np.sum((T_data - T_pred)**2) ss_tot = np.sum((T_data - np.mean(T_data))**2) r2 = 1 - ss_res/ss_tot print(f"R-squared: {r2:.4f}") # 绘图 z_fine = np.linspace(0, 30, 100) T_fine = model_exp(z_fine, *popt) plt.figure(figsize=(8,5)) plt.scatter(z_data, T_data, s=80, label='实测数据', zorder=5) plt.plot(z_fine, T_fine, 'r-', linewidth=2, label=f'拟合曲线 (R²={r2:.3f})') plt.xlabel('深度 (m)') plt.ylabel('温度 (°C)') plt.title('位置A水温垂直分布拟合') plt.grid(True, linestyle='--', alpha=0.7) plt.legend() plt.gca().invert_yaxis() # 深度向下增加,符合常识 plt.show()论文中如何表述:“针对位置A的测温数据,我们观察到水温随深度呈指数衰减趋势,并趋于一个稳定值。采用带基线的指数衰减模型T(z)=Ae^{Bz}+C进行非线性最小二乘拟合。拟合优度R²达到0.992,表明模型能很好地解释数据变化。拟合得到稳定水温C约为9.8°C,衰减系数B为-0.15 m⁻¹。”
4.2 第二步:多点拟合与参数空间插值现在,假设我们在湖面上选了5个位置(A, B, C, D, E),每个位置都通过上述方法拟合得到了自己的参数组(A_i, B_i, C_i)。这5个位置有各自的平面坐标(x_i, y_i)。
我们的目标是:对于湖面上任意一个未测点(x, y),都能给出其水温剖面参数(A, B, C),从而通过公式计算出任意深度的水温。
这需要做三次二维空间插值:分别对参数A、B、C在平面坐标(x, y)上进行插值。
# 假设我们有5个点的信息 points_xy = np.array([[10, 20], [30, 15], [50, 40], [25, 50], [45, 10]]) # 5个点的x,y坐标 # 假设通过单点拟合得到的参数 params_A = np.array([15.0, 12.5, 18.0, 14.0, 16.5]) # 每个点的A参数 params_B = np.array([-0.15, -0.12, -0.18, -0.14, -0.16]) params_C = np.array([9.8, 10.2, 9.5, 10.0, 9.9]) # 为整个湖区生成一个精细网格 grid_x, grid_y = np.mgrid[0:60:100j, 0:60:100j] # 对每个参数进行插值 from scipy.interpolate import griddata grid_A = griddata(points_xy, params_A, (grid_x, grid_y), method='cubic') grid_B = griddata(points_xy, params_B, (grid_x, grid_y), method='cubic') grid_C = griddata(points_xy, params_C, (grid_x, grid_y), method='cubic')现在,对于网格上任一点(grid_x[i,j], grid_y[i,j]),其水温剖面参数就是(grid_A[i,j], grid_B[i,j], grid_C[i,j])。
4.3 第三步:可视化与结果输出我们可以绘制:
- 参数空间分布图:例如,绘制稳定水温C在整个湖区的分布等值线图。
- 三维水温立体图:选择一个断面(如y=30),绘制温度T随x和深度z变化的曲面图。
# 绘制稳定水温C的分布 plt.figure(figsize=(10,8)) contour = plt.contourf(grid_x, grid_y, grid_C, levels=20, cmap='coolwarm') plt.scatter(points_xy[:,0], points_xy[:,1], c='black', s=50, label='测点') plt.colorbar(contour, label='稳定水温 C (°C)') plt.xlabel('东向坐标 (m)') plt.ylabel('北向坐标 (m)') plt.title('湖区底部稳定水温空间分布(插值结果)') plt.legend() plt.axis('equal') plt.show() # 绘制断面水温曲面图(以y=30的断面为例) y_slice_index = 50 # 假设grid_y的索引50对应y=30 x_for_slice = grid_x[:, y_slice_index] C_slice = grid_C[:, y_slice_index] B_slice = grid_B[:, y_slice_index] A_slice = grid_A[:, y_slice_index] # 创建深度网格 Z, X = np.meshgrid(np.linspace(0,30,50), x_for_slice) # 根据每个x位置对应的参数,计算温度 T_slice = A_slice[:, np.newaxis] * np.exp(B_slice[:, np.newaxis] * Z) + C_slice[:, np.newaxis] fig = plt.figure(figsize=(12,6)) ax = fig.add_subplot(111, projection='3d') surf = ax.plot_surface(X, Z, T_slice, cmap='jet', linewidth=0, antialiased=True) ax.set_xlabel('东向坐标 (m)') ax.set_ylabel('深度 (m)') ax.set_zlabel('温度 (°C)') ax.set_title('湖区y=30m断面水温三维分布') fig.colorbar(surf, ax=ax, shrink=0.5, aspect=10, label='温度 (°C)') ax.invert_yaxis() # 深度轴向下 plt.show()论文整合:将以上流程图、拟合结果图、参数空间分布图、三维水温图整合到论文的“模型建立与求解”部分。用文字阐述你的技术路线:“首先,基于单点垂直剖面数据,采用非线性最小二乘法拟合得到指数衰减模型参数;其次,将各测点拟合参数视为湖面二维空间的标量场,采用三次样条插值法进行空间插值,从而获得湖区任意位置的水温剖面模型;最后,基于该模型实现了全湖区三维水温场的可视化重构。”
5. 避坑指南与高阶技巧
走过路过,坑别错过。下面这些经验,很多是教程里不会写的。
5.1 插值中的大坑
- 外推的诅咒:绝对不要轻易使用插值函数对超出数据范围
[x_min, x_max]的点进行预测(这称为外推)。外推行为不可控,误差可能爆炸式增长。如果必须外推,应基于物理模型(如拟合得到的趋势)进行,并明确说明其不确定性。 - 龙格现象:前面提过,高次多项式插值在均匀节点上可能震荡。解决方案:1) 使用分段低次插值(如样条);2) 使用切比雪夫节点(非均匀节点)进行多项式插值,可以极大缓解震荡。
- 缺失值与异常值:如果你的数据点里混入了明显的异常值(比如由于传感器故障),直接插值会把错误平滑地传播开。必须先进行数据清洗!对于缺失值,简单情况可以用前后点的均值,复杂情况可能需要用插值本身来估计(迭代或基于模型)。
5.2 拟合中的大坑
- 过拟合与欠拟合的诊断:
- 欠拟合:拟合曲线连数据的整体趋势都抓不住,训练集上R²就很低。说明模型太简单(如用直线拟合明显弯曲的数据),需要增加模型复杂度(如提高多项式次数、增加非线性项)。
- 过拟合:拟合曲线疯狂扭动去穿过每一个点,包括噪声点。训练集R²很高,但新数据(测试集)上表现极差。诊断方法:永远保留一部分数据(如20%)作为测试集,不参与拟合,只用来看模型泛化能力。
- 权重的重要性:在最小二乘法中,默认所有数据点同等重要。但如果你的数据中,某些点测量精度更高,就应该给它们更大的权重。MATLAB的
polyfit和Python的np.polyfit都支持w参数输入权重。# 假设后三个数据点测量更精确,权重更高 weights = np.array([1, 1, 1, 2, 2, 2, 2]) coefficients_weighted = np.polyfit(x_data, y_data, deg=2, w=weights) - 拟合优度R²的误用:R²高不一定代表模型好。对于非线性模型,或者强制穿过原点的模型,R²的定义会发生变化,甚至可能出现负值。此时应更关注残差图:将残差
(y_i - y_pred_i)相对于x_i或y_pred_i画出来。一个好的拟合,残差应该随机、均匀地分布在0线上下,没有明显的模式(如喇叭形、曲线形)。如果残差有模式,说明模型遗漏了某个系统性因素。
5.3 数模论文加分技巧
- 敏感性分析:改变插值方法(如从线性换为样条)、改变拟合模型的初始值,看结果变化大不大。如果不敏感,说明你的模型稳健;如果敏感,则需要谨慎,并在论文中说明这一局限性。
- 不确定性量化:拟合参数
popt的协方差矩阵pcov包含了参数的不确定性信息。你可以计算参数的置信区间。例如,a_opt ± 2*perr[0]给出了参数a在约95%置信水平下的区间估计。在论文中画出带有置信区间的拟合带,逼格瞬间提升。# 计算预测值的置信区间(简化版,基于参数线性近似) from scipy import stats alpha = 0.05 # 95% 置信区间 n = len(x_data) # 数据点数 p = len(popt) # 参数个数 dof = max(0, n - p) # 自由度 t_val = stats.t.ppf(1-alpha/2, dof) # t分布临界值 # 此处需要计算预测值处的雅可比矩阵和标准误差,略复杂。一个简单替代是绘制参数置信区间产生的曲线族。 - 模型对比:不要只用一个模型。对于同一组数据,尝试线性、二次、指数、幂律等多种模型。用调整后的R²、AIC(赤池信息准则)或BIC(贝叶斯信息准则)这些考虑模型复杂度的指标来客观比较,选择最优模型。在论文中用一个表格清晰展示对比结果,是严谨性的体现。
最后,记住工具箱里不止有锤子。插值和拟合是强大的工具,但理解你的数据、你的问题背景才是根本。在按下polyfit或interp1的回车键之前,多花一分钟画个散点图,想一想数据的物理意义,这能帮你避开大多数低级错误,让你的数模解决方案更加扎实、出彩。