我想在Python中将多条高斯曲线拟合到质谱数据中。现在我一次将数据拟合为高斯 - 一次只有一个范围。
有更简化的方法吗?有没有办法可以通过循环运行数据在每个峰值绘制高斯?我猜测那里必须有更好的方法,但我已经通过互联网进行了梳理。
我的两位高斯图表如下所示。
我的示例数据可在以下网址找到:http://txt.do/dooxv
这是我目前的代码:
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as opt
from scipy.interpolate import interp1d
RGAdata = np.loadtxt("/Users/ilenemitchell/Desktop/RGAscan.txt", skiprows=14)
RGAdata=RGAdata.transpose()
x=RGAdata[0]
y=RGAdata[1]
# graph labels
plt.ylabel('ion current')
plt.xlabel('mass/charge ratio')
plt.xticks(np.arange(min(RGAdata[0]), max(RGAdata[0])+2, 2.0))
plt.ylim([10**-12.5, 10**-9])
plt.title('RGA Data Jul 25, 2017')
plt.semilogy(x, y,'b')
#fitting a guassian to a peak
def gauss(x, a, mu, sig):
return a*np.exp(-(x-mu)**2/(2*sig**2))
fitx=x[(x>40)*(x<43)]
fity=y[(x>40)*(x<43)]
mu=np.sum(fitx*fity)/np.sum(fity)
sig=np.sqrt(np.sum(fity*(fitx-mu)**2)/np.sum(fity))
print (mu, sig, max(fity))
popt, pcov = opt.curve_fit(gauss, fitx, fity, p0=[max(fity),mu, sig])
plt.semilogy(x, gauss(x, popt[0],popt[1],popt[2]), 'r-', label='fit')
#second guassian
fitx2=x[(x>26)*(x<31)]
fity2=y[(x>26)*(x<31)]
mu=np.sum(fitx2*fity2)/np.sum(fity2)
sig=np.sqrt(np.sum(fity2*(fitx2-mu)**2)/np.sum(fity2))
print (mu, sig, max(fity2))
popt2, pcov2 = opt.curve_fit(gauss, fitx2, fity2, p0=[max(fity2),mu, sig])
plt.semilogy(x, gauss(x, popt2[0],popt2[1],popt2[2]), 'm', label='fit2')
plt.show()
答案 0 :(得分:0)
以下是一些示例代码,用于识别数据集中的峰值以帮助您入门。您可以找到所有示例here的链接。
import numpy as np
import peakutils
cb = np.array([-0.010223, ... ])
indexes = peakutils.indexes(cb, thres=0.02/max(cb), min_dist=100)
# [ 333 693 1234 1600]
interpolatedIndexes = peakutils.interpolate(range(0, len(cb)), cb, ind=indexes)
# [ 332.61234263 694.94831376 1231.92840845 1600.52446335]
答案 1 :(得分:0)
除了Alex F的回答之外,您还需要识别峰值并分析其周围环境,以确定xmin
和xmax
值。
如果你已经这样做了,你可以使用这个稍微重构的代码和循环来绘制所有相关数据
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as opt
from scipy.interpolate import interp1d
def _gauss(x, a, mu, sig):
return a*np.exp(-(x-mu)**2/(2*sig**2))
def gauss(x, y, xmin, xmax):
fitx = x[(x>xmin)*(x<xmax)]
fity = y[(x>xmin)*(x<xmax)]
mu = np.sum(fitx*fity)/np.sum(fity)
sig = np.sqrt(np.sum(fity*(fitx-mu)**2)/np.sum(fity))
print (mu, sig, max(fity))
popt, pcov = opt.curve_fit(_gauss, fitx, fity, p0=[max(fity), mu, sig])
return _gauss(x, popt[0], popt[1], popt[2])
# Load data and define x - y
RGAdata = np.loadtxt("/Users/ilenemitchell/Desktop/RGAscan.txt", skiprows=14)
x, y = RGAdata.T
# Create the plot
fig, ax = plt.subplots()
ax.semilogy(x, y, 'b')
# Plot the Gaussian's between xmin and xmax
for xmin, xmax in [(40, 43), (26, 31)]:
yG = gauss(x, y, xmin, xmax)
ax.semilogy(x, yG)
# Prettify the graph
ax.set_xlabel("mass/charge ratio")
ax.set_ylabel("ion current")
ax.set_xticks(np.arange(min(x), max(x)+2, 2.0))
ax.set_ylim([10**-12.5, 10**-9])
ax.set_title("RGA Data Jul 25, 2017")
plt.show()
答案 2 :(得分:0)
您可能会发现lmfit模块(https://lmfit.github.io/lmfit-py/)很有帮助。这提供了一个预先构建的GaussianModel类,用于将峰拟合到单个高斯,并支持将多个模型(不一定是高斯,还有其他峰模型和其他可能对背景有用的函数)添加到一个复合模型中立刻适应。
Lmfit支持固定或给某些参数赋予范围,这样您就可以将模型建立为具有固定位置的高斯之和,从而限制质心的值随某个范围变化(因此峰值不会混淆)。此外,您可以对参数值施加简单的数学约束,以便您可能要求所有峰宽都相同(或以某种简单形式相关)。
特别是,您可以使用2个高斯和背景函数来查看https://lmfit.github.io/lmfit-py/builtin_models.html#example-3-fitting-multiple-peaks-and-using-prefixes的拟合示例。
对于高峰发现,我发现scipy.signal.find_peaks_cwt
非常好。