如何用scipy.stats.beta建模不对称色谱峰曲线?
色谱峰Beta分布拟合问题排查
我正在开展色谱峰积分工作,需通过峰形建模精准判定峰的起止位置。目前能成功拟合高斯峰,但多数色谱峰存在不对称性,这类峰更适合采用Beta分布建模。现在我能拟合高斯模型,却无法得到匹配峰形的Beta模型,想咨询问题出在哪里?我查阅了多篇Stack Overflow相关帖子,但均未演示如何将推导的模型叠加在原始数据上以展示拟合效果。
原代码(存在错误)
from scipy.stats import beta import plotly.graph_objects as go import peakutils # raw data yy = [128459, 1822448, 10216680, 24042041, 30715114, 29537797, 25022446, 18416199, 14138783, 12116635, 9596337, 7201602, 5668133, 4671416, 3920953, 3259980, 2756295, 2326780, 2095209, 1858894, 1646824, 1375129, 1300799, 1253879, 1086045, 968363, 932041, 793707, 741462, 741593] xx = list(range(0,len(yy))) fig = go.Figure() fig.add_trace(go.Scatter(x = xx, y = yy, name = 'raw', mode = 'lines')) # Gaussian model gamp, gcen, gwid = peakutils.peak.gaussian_fit(xx, yy, center_only= False) # this calculates the Amplitude, Center & Width of a guassian peak print(gamp, gcen, gwid) gauss_model = [peakutils.peak.gaussian(x, gamp, gcen, gwid) for x in xx] fig.add_trace(go.Scatter(x = xx, y = gauss_model, mode = 'lines', name = 'Gaussian')) # Beta distribution model aa, bb, loc, scale = beta.fit(dat) # 错误:dat未定义,应传入yy print('beta fit:', beta_fit) # 错误:beta_fit未定义,应输出拟合参数 beta_model = beta.pdf(xx, aa, bb, loc, scale) fig.add_trace(go.Scatter(x = xx, y = beta_model, mode = 'lines', name = 'Beta')) fig.show()
拟合效果说明
原始拟合图中,高斯曲线与峰形贴合较好,但Beta分布曲线数值极小,完全无法匹配原始峰形的振幅和趋势。
问题根源与修正方案
核心问题点
- 数据定义域不匹配:Beta分布默认仅在[0,1]区间有非零概率密度,而你的x轴范围是0-29,直接拟合会导致参数失效
- 变量定义错误:代码中
dat和beta_fit未定义,属于语法错误 - 拟合目标偏差:
beta.fit是对数据做概率密度分布拟合,而你需要的是峰形曲线拟合(需匹配原始数据的振幅),两者目标完全不同 - 振幅未适配:Beta概率密度的输出范围远小于原始数据的百万级峰值,直接使用会导致曲线几乎不可见
修正后的代码
from scipy.stats import beta import plotly.graph_objects as go import peakutils import numpy as np from scipy.optimize import curve_fit # 原始数据 yy = [128459, 1822448, 10216680, 24042041, 30715114, 29537797, 25022446, 18416199, 14138783, 12116635, 9596337, 7201602, 5668133, 4671416, 3920953, 3259980, 2756295, 2326780, 2095209, 1858894, 1646824, 1375129, 1300799, 1253879, 1086045, 968363, 932041, 793707, 741462, 741593] xx = np.arange(len(yy)) fig = go.Figure() fig.add_trace(go.Scatter(x=xx, y=yy, name='原始数据', mode='lines')) # 高斯模型拟合(保留原有逻辑) gamp, gcen, gwid = peakutils.peak.gaussian_fit(xx, yy, center_only=False) gauss_model = [peakutils.peak.gaussian(x, gamp, gcen, gwid) for x in xx] fig.add_trace(go.Scatter(x=xx, y=gauss_model, mode='lines', name='高斯拟合')) # 自定义Beta峰形模型:包含振幅、形状参数、位置和缩放参数 def beta_peak(x, amp, a, b, loc, scale): # 将x归一化到Beta分布的[0,1]定义域 x_norm = (x - loc) / scale # 用振幅缩放概率密度值,匹配原始峰高 return amp * beta.pdf(x_norm, a, b) # 初始化拟合参数:振幅用原始峰值,loc/scale覆盖x范围,a/b初始设为2(接近对称) x_min, x_max = xx.min(), xx.max() init_params = [yy.max(), 2, 2, x_min, x_max - x_min] # 用curve_fit拟合自定义模型,以峰形匹配为目标 popt, _ = curve_fit(beta_peak, xx, yy, p0=init_params) amp_fit, a_fit, b_fit, loc_fit, scale_fit = popt # 生成拟合后的Beta峰形曲线 beta_model = beta_peak(xx, *popt) fig.add_trace(go.Scatter(x=xx, y=beta_model, mode='lines', name='Beta拟合')) print("Beta拟合参数(振幅, 形状a, 形状b, 位置, 缩放):", popt) fig.show()
修正要点说明
- 自定义了带振幅参数的Beta峰形模型,解决概率密度值与原始峰振幅不匹配的问题
- 对x轴做归一化转换,适配Beta分布的[0,1]定义域要求
- 使用
curve_fit替代默认的beta.fit,将拟合目标从概率密度分布改为峰形曲线匹配 - 修正了原代码中的变量未定义错误
内容的提问来源于stack exchange,提问作者Ninja Chris
相关产品推荐
相关产品推荐

