少量数据下实现平滑Gaussian拟合的方法求助
少数据点下的高斯拟合优化方案
你的问题核心是数据点数量有限(仅7个)且存在异常值(最后一个y值为-9),导致无约束的高斯拟合结果偏离标准形态。不增加数据的前提下,可以通过以下几种方式优化:
1. 约束参数取值范围
利用curve_fit的bounds参数限制参数的合理区间,避免拟合出不符合物理意义的结果(如负的标准差、不合理的振幅)。
修改后的完整代码:
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit x = np.array([63.8, 69.9, 76, 82.1, 88.2, 94.3, 100.4]) y = np.array([124, 349, 1793, 5143, 2782, 174, -9]) def gaus(x, amp, cen, sigma): return amp * (1/(sigma * np.sqrt(2*np.pi))) * np.exp(-0.5 * ((x - cen)/sigma)**2) # 设置参数边界:振幅(0, 60000)、中心(70, 90)、标准差(5, 15) popt_gauss, _ = curve_fit(gaus, x, y, p0=[5150, 81, 10], bounds=([0, 70, 5], [60000, 90, 15])) # 生成密集x点绘制平滑拟合曲线 x_fit = np.linspace(min(x), max(x), 100) y_fit = gaus(x_fit, *popt_gauss) plt.scatter(x, y, color="black", marker=".", s=30, label="原始数据") plt.plot(x_fit, y_fit, color="red", linewidth=1, label="高斯拟合曲线") plt.legend() plt.show()
2. 剔除异常数据点
最后一个数据点(100.4, -9)明显偏离整体趋势,属于异常值,剔除后能显著提升拟合的合理性:
# 移除最后一个异常点 x = np.array([63.8, 69.9, 76, 82.1, 88.2, 94.3]) y = np.array([124, 349, 1793, 5143, 2782, 174])
配合参数约束使用,拟合结果会更接近标准高斯曲线。
3. 优化初始猜测值
初始猜测值对少数据点的拟合影响极大,根据数据峰值位置和大小调整p0,能帮助拟合算法更快收敛到合理结果:
peak_y = max(y) peak_x = x[np.argmax(y)] # 根据高斯函数峰值公式估算初始振幅 init_amp = peak_y * 8 * np.sqrt(2*np.pi) # 假设初始标准差为8 p0 = [init_amp, peak_x, 8] # 用优化后的初始值拟合 popt_gauss, _ = curve_fit(gaus, x, y, p0=p0, bounds=([0, 70, 5], [60000, 90, 15]))
4. 带正则化的拟合
如果不想剔除数据,可使用least_squares替代curve_fit,通过正则化约束参数,避免过拟合:
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import least_squares x = np.array([63.8, 69.9, 76, 82.1, 88.2, 94.3, 100.4]) y = np.array([124, 349, 1793, 5143, 2782, 174, -9]) def gaus(x, amp, cen, sigma): return amp * (1/(sigma * np.sqrt(2*np.pi))) * np.exp(-0.5 * ((x - cen)/sigma)**2) def residuals(params, x, y): amp, cen, sigma = params return y - gaus(x, amp, cen, sigma) # 使用soft_l1损失实现正则化,f_scale控制正则化强度 result = least_squares(residuals, x0=[5150, 81, 10], args=(x, y), loss='soft_l1', f_scale=100) popt_gauss = result.x x_fit = np.linspace(min(x), max(x), 100) y_fit = gaus(x_fit, *popt_gauss) plt.scatter(x, y, color="black", marker=".", s=30, label="原始数据") plt.plot(x_fit, y_fit, color="red", linewidth=1, label="高斯拟合曲线") plt.legend() plt.show()
内容的提问来源于stack exchange,提问作者daveidix
相关产品推荐
相关产品推荐

