ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

插值与拟合:从离散数据到连续模型的核心技术与工程实践

插值与拟合:从离散数据到连续模型的核心技术与工程实践 1. 项目概述从数据到模型的桥梁在科研、工程和商业分析的无数场景里我们常常会面对一堆离散的数据点。这些点可能来自实验测量、市场调研或是复杂的系统仿真。它们散落在坐标平面上像夜空中的星星蕴含着规律却又不够连续。比如我们测量了一天中每小时的室外温度得到了24个数据点但你想知道下午3点15分的精确温度是多少或者我们通过有限的几次风洞实验获得了飞行器在不同速度下的阻力系数但需要预测一个实验未覆盖的速度下的性能。这时候你就需要“插值”和“拟合”这两把钥匙来打开从离散数据通往连续认知的大门。简单来说插值与拟合是数学建模中处理离散数据、构建连续模型的核心技术。它们要解决的本质上都是“用已知推测未知”的问题但思路和适用场景截然不同。你可以把插值想象成“穿针引线”要求构造一条光滑的曲线必须严丝合缝地穿过每一个已知的数据点主要用于在数据点内部进行高精度估计。而拟合则更像是“大势所趋”不要求曲线经过每一个点而是寻找一条最能够反映数据整体变化趋势的曲线用于揭示内在规律、预测未来趋势或处理带有噪声的数据。无论是分析股票走势、优化工业参数还是处理图像、设计曲线这两项技术都是数据分析师和工程师工具箱里的必备品。接下来我将结合十多年的实操经验为你深入拆解这两项技术的核心思想、常用方法以及那些在教科书里不会写的避坑指南。2. 核心思想辨析插值 vs. 拟合在深入具体算法之前我们必须从根本上厘清插值与拟合的哲学差异和应用边界。混淆两者的核心目标是许多建模项目走弯路的起点。2.1 插值精确穿过已知点的艺术插值的核心诉求是“精确再现”。假设我们有n1个互不相同的已知数据点(x_i, y_i), i0,1,...,n插值的目标是构造一个函数P(x)使其满足严格的约束条件P(x_i) y_i对所有i成立。这意味着在已知数据点处插值函数给出的值必须与原始数据完全一致没有丝毫误差。这种特性决定了插值的最佳应用场景数据补全当你的数据本身是精确的如高精度计算输出、理论值但采样点不足或不均匀时需要用插值来获取中间点的值。例如从有限的高精度数值解中获取整个区域的信息。函数近似当一个复杂函数计算成本极高时可以预先在一些关键点计算出精确值然后用一个简单的插值函数如多项式来近似替代原函数从而加速后续计算。图像处理图像的缩放、旋转等几何变换本质上就是在像素网格上进行插值以确定新坐标点处的颜色值。插值的关键在于“信任数据”。它默认所有已知点都是准确无误的黄金标准。因此插值函数在数据点之间的行为完全依赖于这些点的位置和数值对数据噪声极度敏感。一个异常点就可能导致插值曲线在全局范围内发生剧烈的、不合理的震荡这被称为“龙格现象”Runges phenomenon在多项式插值中尤为常见。2.2 拟合捕捉整体趋势的科学拟合的核心诉求是“趋势概括”。我们承认观测数据(x_i, y_i)可能包含测量误差、随机噪声或其它不确定性。拟合的目标不再是精确穿过每一个点而是寻找一个参数化的模型函数f(x, θ)其中θ是待定参数向量使得该函数在整体上“最接近”所有数据点。这个“最接近”通常通过最小化一个损失函数来定义最常用的是最小二乘法寻找参数θ使得所有数据点的残差平方和最小即min Σ [y_i - f(x_i, θ)]^2。拟合得到的曲线可能不会经过任何原始数据点但它反映了数据背后潜在的、更简洁的物理规律或统计关系。拟合的典型应用场景包括经验公式建立通过实验数据确定物理公式中的系数如弹簧的胡克定律F kx中的劲度系数k。趋势预测与回归分析分析销售量与时间、广告投入的关系预测未来走势。数据平滑与去噪当数据含有明显噪声时用一个简单的模型如低阶多项式去拟合可以过滤掉随机波动揭示主要趋势。拟合的关键在于“理解数据”。它承认数据的不完美并致力于从噪声中提取信号。拟合模型的好坏不仅取决于算法更取决于所选模型形式是否与数据的内在生成机制相匹配。用一个直线模型去拟合显然是指数增长的数据无论怎么优化参数结果都是失败的。实操心得在选择插值还是拟合时我通常会问自己两个问题第一我的数据点本身是否足够精确、可靠第二我的核心需求是还原已知点之间的细节还是理解整体规律并用于预测如果答案是“精确”和“还原细节”选插值如果是“有噪声”和“看趋势”选拟合。在实际项目中两者也常结合使用例如先用拟合得到趋势线再对残差数据点与趋势线的偏差进行插值分析。3. 常用插值方法详解与实操理解了核心思想我们来深入几种最常用、也最实用的插值方法。我会重点讲解它们的原理、适用场景并附上可操作的实现要点。3.1 线性插值简单快速的连接这是最基本、最直观的插值方法。在相邻两个数据点(x_k, y_k)和(x_{k1}, y_{k1})之间用一条直线连接。对于区间[x_k, x_{k1}]内任意一点x其插值公式为P(x) y_k (y_{k1} - y_k) * (x - x_k) / (x_{k1} - x_k)实现要点查找区间给定待插值点x首先需要在数据点序列中找到其所在的区间即找到k使得x_k x x_{k1}。对于有序数组可以用二分查找法加速。边界处理如果x小于最小x_0或大于最大x_n则属于外插。线性外插风险很大通常不建议使用或需明确说明。Python代码示例使用NumPyimport numpy as np def linear_interpolation(x_known, y_known, x_new): 线性插值 x_known: 已知点的x坐标数组 y_known: 已知点的y坐标数组 x_new: 待插值点的x坐标标量或数组 # 确保输入数组有序通常数据已有序 indices np.searchsorted(x_known, x_new) - 1 indices np.clip(indices, 0, len(x_known)-2) # 处理边界禁止外插 x_low x_known[indices] x_high x_known[indices 1] y_low y_known[indices] y_high y_known[indices 1] # 计算插值权重 weights (x_new - x_low) / (x_high - x_low) y_new y_low weights * (y_high - y_low) return y_new # 示例使用 x_data np.array([0, 2, 5, 7, 10]) y_data np.array([1, 4, 2, 8, 3]) x_query 3.5 y_result linear_interpolation(x_data, y_data, x_query) print(f在 x{x_query} 处的线性插值结果为: {y_result})适用场景与局限线性插值计算效率极高在数据点密集、函数变化平缓时效果不错。但其结果曲线是折线不光滑一阶导数不连续。对于需要光滑性的应用如路径规划、图形设计就需要更高级的方法。3.2 多项式插值高精度与震荡风险多项式插值试图用一个n次多项式P_n(x)穿过所有n1个数据点。根据代数基本定理这样的多项式存在且唯一。拉格朗日插值和牛顿插值是两种经典的构造方法。拉格朗日插值公式直观体现了“穿过所有点”的思想P_n(x) Σ_{i0}^{n} y_i * L_i(x)其中L_i(x)是拉格朗日基多项式L_i(x) Π_{j≠i} (x - x_j) / (x_i - x_j)。它在x_i处值为1在其他已知点x_j (j≠i)处值为0。实现要点与陷阱计算复杂度直接计算拉格朗日公式的复杂度是 O(n^2)当点数n较大时效率低。牛顿插值法使用差商表在需要多次计算不同x的插值时更高效因为差商表可以预先计算。龙格现象这是高阶多项式插值通常n 7的致命伤。当在等距节点上对某些函数如f(x)1/(125x^2)在[-1,1]上进行插值时插值多项式在区间边缘会出现剧烈的震荡完全偏离真实函数。因此切勿盲目使用高阶多项式插值节点选择如果必须使用多项式插值采用切比雪夫节点在区间内非均匀分布两端密集中间稀疏可以极大缓解龙格现象。Python示例使用SciPy验证import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import lagrange # 定义一个光滑函数 def true_func(x): return np.sin(x) # 在等距节点上采样 x_known_eq np.linspace(0, 2*np.pi, 7) # 7个等距点 y_known_eq true_func(x_known_eq) # 使用拉格朗日插值 poly lagrange(x_known_eq, y_known_eq) x_fine np.linspace(0, 2*np.pi, 200) y_poly poly(x_fine) y_true true_func(x_fine) plt.figure(figsize(10,5)) plt.plot(x_fine, y_true, k-, label真实函数) plt.plot(x_fine, y_poly, r--, label7次多项式插值) plt.scatter(x_known_eq, y_known_eq, cblue, s80, zorder5, label已知数据点) plt.legend() plt.title(多项式插值示例等距节点) plt.grid(True) plt.show() # 观察区间两端震荡尚不明显。若将节点数增加到15震荡将非常剧烈。3.3 样条插值光滑性与稳定性的平衡为了克服高阶多项式插值的震荡问题同时获得光滑的曲线样条插值应运而生。其核心思想是“分而治之”将整个区间划分为多个子区间在每个子区间上使用低阶多项式最常用的是三次多项式进行插值并确保在连接点节点处具有连续的一阶和二阶导数从而保证整体曲线的光滑性。三次样条插值是最流行的样条方法。它要求S(x)在每个子区间[x_k, x_{k1}]上是一个三次多项式。S(x_k) y_k插值条件。S(x)、S(x)、S(x)在所有内节点x_k (k1,...,n-1)处连续。需要两个边界条件来唯一确定样条。常见的有自然样条S(x_0) S(x_n) 0。曲线在端点处曲率为零像一根放松的弹性木条。固定边界条件给定端点的一阶导数S(x_0)和S(x_n)。非扭结条件强制第一个和最后一个内节点处的三阶导数也连续这通常能产生视觉上更“自然”的曲线。实现要点优先使用库函数自己实现三次样条需要求解一个三对角线性方程组虽然有趣但易错。在实际工作中强烈建议使用成熟的科学计算库。边界条件选择如果不了解端点处的导数信息“非扭结”条件通常是比“自然”条件更好的默认选择因为它能减少边界处的扭曲。Python示例使用SciPyimport numpy as np from scipy.interpolate import CubicSpline, interp1d import matplotlib.pyplot as plt # 生成带轻微噪声的数据 np.random.seed(42) x_known np.sort(np.random.rand(10) * 10) y_known np.sin(x_known) 0.1 * np.random.randn(10) # 创建插值函数 # 方法1CubicSpline默认使用非扭结边界条件 cs CubicSpline(x_known, y_known) # 方法2interp1d函数指定样条类型 spline_interp interp1d(x_known, y_known, kindcubic) # 在密集点上评估 x_fine np.linspace(x_known.min(), x_known.max(), 200) y_cs cs(x_fine) y_si spline_interp(x_fine) plt.figure(figsize(12,5)) plt.scatter(x_known, y_known, cred, s100, label带噪声数据点, zorder5) plt.plot(x_fine, np.sin(x_fine), k-, alpha0.7, label真实函数sin(x)) plt.plot(x_fine, y_cs, b--, linewidth2, label三次样条插值 (CubicSpline)) plt.plot(x_fine, y_si, g:, linewidth2, label三次样条插值 (interp1d)) plt.legend() plt.title(三次样条插值处理带噪声数据) plt.grid(True) plt.show() # 可以看到样条曲线光滑地穿过了所有数据点并且整体上逼近了真实的正弦趋势。注意事项样条插值虽然强大但它依然是一种插值方法对数据噪声敏感。上图示例中由于数据点带有噪声样条曲线会忠实地穿过每一个噪声点导致曲线出现一些不必要的“小波动”。如果数据噪声明显且你的目的是提取趋势那么拟合如多项式拟合可能是更好的选择。4. 曲线拟合的核心方法与实战当数据存在噪声或我们更关注宏观规律时拟合就派上了用场。其核心是最优化问题找到模型参数使模型预测值与实际观测值之间的总体偏差最小。4.1 最小二乘法原理与矩阵求解最小二乘法的目标是最小化残差平方和RSS(θ) Σ [y_i - f(x_i, θ)]^2。当模型f(x, θ)是关于参数θ的线性函数时即“线性最小二乘”问题有解析解。线性模型示例y θ_0 θ_1 * x一元线性回归y θ_0 θ_1*x θ_2*x^2多项式拟合y θ_0 * exp(θ_1 * x)通过取对数可化为线性等。对于线性模型我们可以将其写成矩阵形式y Xθ ε其中y是观测值向量X是设计矩阵每一行对应一个样本的特征包括常数项θ是参数向量ε是误差向量。最小二乘的解为θ_hat (X^T X)^{-1} X^T y。Python实现从零开始与使用库import numpy as np import matplotlib.pyplot as plt # 生成模拟数据y 1.5 2.8*x 噪声 np.random.seed(123) x_data np.linspace(0, 5, 30) y_true 1.5 2.8 * x_data y_noise y_true np.random.randn(30) * 2 # 加入高斯噪声 y_data y_noise # 方法1使用NumPy直接求解正规方程 # 构建设计矩阵 X第一列为1对应截距第二列为x X np.column_stack((np.ones_like(x_data), x_data)) # 求解参数 theta (X^T X)^{-1} X^T y theta np.linalg.inv(X.T X) X.T y_data print(f手动求解参数: 截距{theta[0]:.3f}, 斜率{theta[1]:.3f}) # 方法2使用NumPy的lstsq函数更数值稳定 theta_lstsq, residuals, rank, s np.linalg.lstsq(X, y_data, rcondNone) print(flstsq求解参数: 截距{theta_lstsq[0]:.3f}, 斜率{theta_lstsq[1]:.3f}) # 方法3使用scikit-learn适合更复杂的机器学习流程 from sklearn.linear_model import LinearRegression model LinearRegression(fit_interceptTrue) # fit_interceptTrue会自行添加常数项 model.fit(x_data.reshape(-1,1), y_data) print(fscikit-learn求解: 截距{model.intercept_:.3f}, 斜率{model.coef_[0]:.3f}) # 绘制结果 x_fit np.linspace(0, 5, 100) y_fit theta[0] theta[1] * x_fit plt.figure(figsize(10,6)) plt.scatter(x_data, y_data, alpha0.7, label带噪声数据) plt.plot(x_data, y_true, k-, linewidth3, alpha0.5, label真实关系) plt.plot(x_fit, y_fit, r--, linewidth2, label最小二乘拟合线) plt.xlabel(x) plt.ylabel(y) plt.legend() plt.title(线性最小二乘拟合示例) plt.grid(True) plt.show()4.2 非线性最小二乘拟合当模型f(x, θ)关于参数θ是非线性的时如y a * exp(b*x) c问题就变成了非线性优化问题没有直接的解析解需要使用迭代算法来逼近最优解例如高斯-牛顿法、Levenberg-Marquardt算法等。Python实战使用SciPyimport numpy as np from scipy.optimize import curve_fit import matplotlib.pyplot as plt # 定义要拟合的非线性模型函数 def exponential_decay(x, a, b, c): 指数衰减模型y a * exp(-b*x) c return a * np.exp(-b * x) c # 生成模拟数据 np.random.seed(42) x_data np.linspace(0, 5, 50) # 真实参数a5, b1.2, c0.5 y_true exponential_decay(x_data, 5, 1.2, 0.5) y_noise y_true 0.2 * np.random.randn(len(x_data)) y_data y_noise # 使用curve_fit进行拟合。需要提供初始参数猜测p0这对收敛很重要。 initial_guess (4, 1, 0) # 猜测的(a, b, c)初始值 popt, pcov curve_fit(exponential_decay, x_data, y_data, p0initial_guess) # popt是最优参数估计pcov是参数的估计协方差矩阵 a_fit, b_fit, c_fit popt print(f拟合参数: a{a_fit:.3f}, b{b_fit:.3f}, c{c_fit:.3f}) print(f真实参数: a5.000, b1.200, c0.500) # 计算拟合优度 R-squared residuals y_data - exponential_decay(x_data, *popt) 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^2 {r_squared:.4f}) # 绘图 x_fine np.linspace(0, 5, 200) y_fit_curve exponential_decay(x_fine, *popt) plt.figure(figsize(10,6)) plt.scatter(x_data, y_data, alpha0.6, label观测数据含噪声) plt.plot(x_data, y_true, k-, linewidth3, alpha0.4, label真实模型) plt.plot(x_fine, y_fit_curve, r--, linewidth2, label非线性最小二乘拟合) plt.xlabel(时间 (x)) plt.ylabel(浓度/信号强度 (y)) plt.legend() plt.title(非线性最小二乘拟合指数衰减模型) plt.grid(True) plt.show()实操心得非线性拟合的成功极度依赖于初始参数猜测p0。一个糟糕的初始值可能导致算法收敛到局部最优解甚至发散。我的经验是1) 尽可能根据物理意义或数据范围估算参数的大致数量级2) 绘制数据和模型草图手动调整参数使曲线靠近数据点3) 多次尝试不同的初始值观察结果是否稳定4) 使用curve_fit的bounds参数限制参数范围可以大大提高收敛的稳定性和成功率。4.3 模型选择与过拟合陷阱拟合不仅仅是调参更重要的是选择模型。一个复杂的模型如高阶多项式可能对训练数据拟合得非常好残差小但它的预测能力可能很差因为它“学习”了数据中的噪声这种现象称为过拟合。如何诊断和避免过拟合可视化始终将拟合曲线与数据点画在一起。如果曲线为了穿过每一个点而变得极度扭曲、震荡这很可能是过拟合。交叉验证将数据随机分成训练集和测试集。用训练集拟合模型用测试集评估预测误差。如果模型在训练集上误差很小在测试集上误差很大就是过拟合的典型标志。信息准则如AIC赤池信息准则或BIC贝叶斯信息准则。它们在衡量模型拟合优度的同时惩罚了模型复杂度参数个数。AIC/BIC值越小模型在“简洁性”和“拟合度”之间平衡得越好。正则化在损失函数中加入对参数大小的惩罚项如L1/L2正则化迫使模型参数值变小从而抑制模型复杂度降低过拟合风险。这在机器学习中非常常见。多项式拟合阶数选择示例import numpy as np import matplotlib.pyplot as plt from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error from sklearn.model_selection import train_test_split # 生成数据一个二次关系加上噪声 np.random.seed(0) x np.random.rand(50) * 10 y_true 2 1.5*x - 0.2*x**2 y y_true np.random.randn(50) * 3 # 加入较大噪声 # 划分训练集和测试集 x_train, x_test, y_train, y_test train_test_split(x, y, test_size0.3, random_state42) train_mse [] test_mse [] degrees range(1, 10) # 尝试1到9阶多项式 for degree in degrees: # 生成多项式特征 poly PolynomialFeatures(degreedegree) X_train_poly poly.fit_transform(x_train.reshape(-1,1)) X_test_poly poly.transform(x_test.reshape(-1,1)) # 拟合线性模型实为多项式回归 model LinearRegression() model.fit(X_train_poly, y_train) # 计算训练集和测试集上的均方误差MSE y_train_pred model.predict(X_train_poly) y_test_pred model.predict(X_test_poly) train_mse.append(mean_squared_error(y_train, y_train_pred)) test_mse.append(mean_squared_error(y_test, y_test_pred)) # 绘制误差随多项式阶数的变化 plt.figure(figsize(10,5)) plt.plot(degrees, train_mse, bo-, label训练集 MSE) plt.plot(degrees, test_mse, rs-, label测试集 MSE) plt.xlabel(多项式阶数) plt.ylabel(均方误差 (MSE)) plt.title(模型复杂度多项式阶数对过拟合的影响) plt.legend() plt.grid(True) plt.yscale(log) # 对数坐标更清晰 plt.show() # 通常测试集误差会先下降后上升。最低点对应的阶数可能是较优选择。 optimal_degree degrees[np.argmin(test_mse)] print(f根据测试集MSE建议的多项式阶数为: {optimal_degree})从图中可以清晰看到随着多项式阶数增加训练误差持续下降因为模型越来越复杂能更好地“记住”训练数据但测试误差在降到最低点后开始反弹上升这就是过拟合的直观体现。5. 工程实践中的关键问题与排查技巧理论和方法都清楚了但在实际项目中你会遇到各种棘手的情况。下面是我总结的一些常见问题及应对策略。5.1 数据预处理质量决定上限在插值或拟合前数据清洗和预处理至关重要。异常值检测与处理一个离群点可能彻底扭曲插值曲线或拟合结果。使用箱线图、3σ原则或孤立森林等方法识别异常值。处理方式可以是删除、修正或用相邻值/中位数替代但需谨慎并记录。数据排序绝大多数插值算法要求输入的数据点按x坐标严格递增。如果数据是乱序的必须先排序。重复点处理如果存在x坐标相同但y值不同的点插值函数将无法定义。需要根据业务逻辑决定是取平均、取第一个值还是报错。数据变换对于非线性关系有时对变量进行变换如取对数、开方可以将问题转化为线性拟合更简单稳定。例如指数模型y a*e^(bx)取对数后变为ln(y) ln(a) b*x即可线性拟合。5.2 插值方法选择指南面对具体问题如何选择插值方法可以参考以下决策流程数据是否精确无噪声如果是进入插值流程如果否考虑拟合。对光滑性有何要求要求零阶连续值连续最近邻插值阶梯状。要求一阶连续切线连续线性插值折线。要求二阶连续曲率连续三次样条插值最常用。要求高阶连续或特殊性质高阶多项式插值慎用、埃尔米特插值还指定导数值。计算效率是否关键线性插值最快样条插值次之高阶多项式插值计算和求值成本都较高。是否在规则网格上对于二维或更高维网格数据有双线性插值、双三次插值等专门方法效率远高于散点插值。5.3 拟合效果评估与模型诊断拟合完成后不能只看R^2。需要进行全面的诊断残差分析绘制残差观测值-预测值图。理想的残差图应该是围绕0随机、均匀分布的散点没有明显的模式如漏斗形、曲线形。如果存在模式说明模型未能捕捉数据中的某些结构可能缺失了重要变量或函数形式不对。# 接前面的线性回归示例 y_pred theta[0] theta[1] * x_data residuals y_data - y_pred fig, axes plt.subplots(1, 2, figsize(12,4)) axes[0].scatter(x_data, residuals, alpha0.7) axes[0].axhline(y0, colorr, linestyle--) axes[0].set_xlabel(x) axes[0].set_ylabel(残差) axes[0].set_title(残差 vs. x) axes[0].grid(True) axes[1].scatter(y_pred, residuals, alpha0.7) axes[1].axhline(y0, colorr, linestyle--) axes[1].set_xlabel(预测值 y_pred) axes[1].set_ylabel(残差) axes[1].set_title(残差 vs. 预测值) axes[1].grid(True) plt.tight_layout() plt.show()检查参数显著性对于线性模型可以检查参数的p-value。通常p-value 0.05认为该参数显著不为零。如果一个高阶项的p-value很大可以考虑将其从模型中移除以简化模型。多重共线性检查当拟合多项式或多元线性回归时自变量之间可能存在高度相关性导致参数估计不稳定、方差增大。可以通过计算方差膨胀因子VIF来诊断。VIF 10通常表明存在严重的多重共线性。5.4 外推的风险与应对无论是插值还是拟合外推在数据范围之外进行预测都是高风险行为。模型在数据区间内建立的规律在区间外可能完全失效。线性模型外推风险相对较小但假设线性关系在区间外依然成立常常是不现实的。非线性模型如多项式外推行为可能极其夸张迅速趋向正负无穷。样条插值在边界处的行为由边界条件控制外推通常使用边界多项式进行风险很高。黄金法则尽量避免外推。如果必须外推务必明确告知结果的不确定性极高。仅做短期、有限范围的外推。考虑使用物理约束或先验知识来限制外推行为。使用专门设计用于外推的模型如某些时间序列模型并严格评估其表现。6. 高级话题与扩展方向掌握了基础方法后你可以进一步探索以下方向以应对更复杂的实际问题。6.1 多元插值与拟合当因变量y依赖于多个自变量(x1, x2, ..., xm)时问题就扩展到多维。多元插值对于网格数据可以使用scipy.interpolate.RegularGridInterpolator。对于散乱数据则使用scipy.interpolate.griddata它支持最近邻、线性和三次样条插值。多元拟合/回归本质上是寻找一个多元函数f(x1, x2, ..., xm; θ)。线性回归、多项式回归通过特征交叉可以直接推广到多维。对于复杂的非线性关系可能需要使用支持向量回归SVR、高斯过程回归GPR或神经网络等机器学习方法。6.2 鲁棒拟合当数据中存在显著异常值离群点时普通最小二乘法对误差平方会赋予异常点过大的权重导致拟合结果被拉偏。鲁棒拟合方法通过修改损失函数来降低异常值的影响。最小绝对偏差LAD最小化绝对误差和比最小二乘对异常值更不敏感。Huber损失、Tukey双权损失在误差较小时使用平方损失以保证效率误差较大时使用线性损失以抑制异常值。RANSAC随机抽样一致一种迭代算法它随机选择一部分数据点来拟合模型然后计算有多少点符合这个模型即内点重复多次选择内点最多的模型。它能有效剔除大量异常值。Python示例使用RANSAC拟合直线from sklearn.linear_model import RANSACRegressor from sklearn.linear_model import LinearRegression # 在之前的数据中加入几个极端异常值 x_data_robust np.append(x_data, [8, 9, 10]) y_data_robust np.append(y_data, [50, -30, 60]) # 加入三个离谱的点 # 普通最小二乘 lr LinearRegression() lr.fit(x_data_robust.reshape(-1,1), y_data_robust) # RANSAC ransac RANSACRegressor(LinearRegression(), residual_threshold10, random_state42) ransac.fit(x_data_robust.reshape(-1,1), y_data_robust) # 比较 x_line np.array([[0], [10]]) y_lr lr.predict(x_line) y_ransac ransac.predict(x_line) inlier_mask ransac.inlier_mask_ # RANSAC识别出的内点 outlier_mask np.logical_not(inlier_mask) plt.figure(figsize(10,6)) plt.scatter(x_data_robust[inlier_mask], y_data_robust[inlier_mask], cblue, label内点, alpha0.6) plt.scatter(x_data_robust[outlier_mask], y_data_robust[outlier_mask], cred, label异常值被RANSAC排除, s100) plt.plot(x_line, y_lr, g-, linewidth3, label普通最小二乘受异常值影响) plt.plot(x_line, y_ransac, k--, linewidth3, labelRANSAC拟合鲁棒) plt.legend() plt.title(RANSAC鲁棒拟合 vs. 普通最小二乘) plt.grid(True) plt.show()可以看到RANSAC成功地忽略了红色的异常值拟合出了更符合主体数据趋势的直线。6.3 参数化曲线与曲面拟合有时我们需要拟合的不仅仅是一个函数yf(x)而是一条由参数方程(x(t), y(t))定义的曲线或是一个曲面zf(x,y)。这在计算机图形学、路径规划和逆向工程中很常见。参数曲线拟合可以将参数t设为累积弦长或均匀参数然后分别对x(t)和y(t)进行样条插值或拟合。曲面拟合对于三维散点数据(x_i, y_i, z_i)可以使用scipy.interpolate.griddata进行插值或使用scipy.optimize.curve_fit拟合一个二元函数z f(x, y)也可以使用多项式回归构造x, y的交叉项。数学建模中插值与拟合是通向数据深处、构建有效模型的必经之路。从最初级的线性方法到复杂的非线性鲁棒拟合工具的选择永远服务于具体问题的核心需求你是要精确还原还是要概括趋势你的数据是干净的金标准还是充满噪声的现场观测没有放之四海而皆准的“最佳方法”只有最“合适”的方法。我个人的经验是在开始任何计算之前花时间可视化你的数据理解其分布和可能存在的问题这往往比盲目尝试各种高级算法更能带来好的结果。最后永远对模型保持怀疑用残差分析、交叉验证等工具来审视它的表现记住所有的模型都是错的但有些确实有用。
返回列表