简体   繁体   English

使用来自scipy和python 3.x的*** curve_fit ***改进高斯拟合

[英]Improving Gaussian fitting using ***curve_fit*** from scipy and python 3.x

I believe I am successfully implementing gaussian fitting using curve fit from scipy. 我相信我可以使用scipy的曲线拟合成功地实现高斯拟合。 But the problem that I am running into is that... the fit isn't so great, because the optimized parameter is changing the centroid. 但是我遇到的问题是...拟合度不是很高,因为优化的参数正在改变质心。

    data =np.loadtxt('mock.txt')
    my_x=data[:,0]
    my_y=data[:,1]

    def gauss(x,mu,sigma,A):
        return A*np.exp(-(x-mu)**2/2/sigma**2)
    def trimodal_gauss(x,mu1,sigma1,A1,mu2,sigma2,A2,mu3,sigma3,A3):
        return gauss(x,mu1,sigma1,A1)+gauss(x,mu2,sigma2,A2)+gauss(x,mu3,sigma3,A3)



    """""
    Gaussian fitting parameters recognized in each file
    """""
    first_centroid=(10180.4*2+9)/9
    second_centroid=(10180.4*2+(58.6934*1)+7)/9
    third_centroid=(10180.4*2+(58.6934*2)+5)/9
    centroid=[]
    centroid+=(first_centroid,second_centroid,third_centroid)

    apparent_resolving_power=1200
    sigma=[]
    for i in range(len(centroid)):
        sigma.append(centroid[i]/((apparent_resolving_power)*2.355))

    height=[1,1,1]

    p=[]    

    p = np.array([list(t) for t in zip(centroid, sigma, height)]).flatten() 


    popt, pcov = curve_fit(trimodal_gauss,my_x,my_y,p0=p) 

output: 输出: 在此处输入图片说明

I understand that there are a lot of peaks here but I really need it to fit only three Gaussians but at the right centroid(given in my initial guess). 我知道这里有很多峰,但我真的需要它适合三个高斯峰,但要在合适的质心处(在我最初的猜测中给出)。 In other words, I really don't hope that the centroid I give is not changing. 换句话说,我真的不希望我给的质心没有改变。 Has anyone encountered a challenge as such? 有人遇到过这样的挑战吗? and could please help me what I could do to make it happen? 并请帮我做些什么才能实现呢?

You should define three separate functions with fixed values for the centers. 您应该定义三个单独的函数,并为中心指定固定的值。 Then you fit the sum function of these functions for only the leftover parameters. 然后,仅将剩余参数适合这些函数的求和函数。

Simply put, your trimodal_gauss() should not take mu s but only A s and sigma s. 简而言之,您的trimodal_gauss()不应只包含mu而只能包含Asigma The mu s should be constants. mu应该是常数。

A trivial (but not very general) way of doing this is: 一个简单(但不是很通用)的方法是:

def trimodal_gauss(x, sigma1, A1, sigma2, A2, sigma3, A3):
    mu1 = 1234 # put your mu's here
    mu2 = 2345
    mu3 = 3456
    g1 = gauss(x, mu1, sigma1, A1)
    g2 = gauss(x, mu2, sigma2, A2)
    g3 = gauss(x, mu3, sigma3, A3)
    return g1 + g2 + g3

From this one can generalize the idea by a "generator" for trimodal_gauss functions that takes the three (or n?) mu s and creates the function of the other parameters. 这一个可以通过一个“发电机”为概括的想法trimodal_gauss功能,是以三个(或N 2) mu S和产生其他参数的函数。 Like so: 像这样:

def make_trimodal_gauss(mu1, mu2, mu3):
    def result_function(x, sigma1, A1, sigma2, A2, sigma3, A3):
        g1 = gauss(x, mu1, sigma1, A1)
        g2 = gauss(x, mu2, sigma2, A2)
        g3 = gauss(x, mu3, sigma3, A3)
        return g1 + g2 + g3
    return result_function


mu1 = 1234 # put your mu's here
mu2 = 2345
mu3 = 3456

trimodal_gauss = make_trimodal_gauss(mu1, mu2, mu3)

#usage like this: trimodal_gauss(x, sigma1, A1, sigma2, A2, sigma3, A3)

If you use the lmfit module ( https://github.com/lmfit/lmfit-py ), you can easily put bounds on the centroids of your Gaussian functions, or even fix them. 如果使用lmfit模块( https://github.com/lmfit/lmfit-py ),则可以轻松地将边界置于高斯函数的质心上,甚至可以对其进行修复。 Lmfit also makes it easy to build up multi-peak models. Lmfit还使构建多峰模型变得容易。

You didn't give a complete example or link to your data, but a fit with lmfit to your data might look like this: 您没有提供完整的示例或数据链接,但是将lmfit与数据拟合可能如下所示:

import numpy as np
from lmfit import GaussianModel
data =np.loadtxt('mock.txt')
my_x=data[:,0]
my_y=data[:,1]

model = ( GaussianModel(prefix='p1_') +
          GaussianModel(prefix='p2_') +
          GaussianModel(prefix='p3_') )

params = model.make_params(p1_amplitude=100, p1_sigma=2, p1_center=2262,
                           p2_amplitude=100, p2_sigma=2, p2_center=2269,
                           p3_amplitude=100, p3_sigma=2, p3_center=2276,
                       )

# set boundaries on the Gaussian Centers:
params['p1_center'].min = 2260
params['p1_center'].max = 2264

params['p2_center'].min = 2267
params['p2_center'].max = 2273

params['p3_center'].min = 2274
params['p3_center'].max = 2279

# or you could just fix one of the centroids like this:
params['p3_center'].vary = False

# if needed, you could force all the sigmas to be the same value
# or related by simple mathematical expressions
params['p2_sigma'].expr = 'p1_sigma'
params['p3_sigma'].expr = '2*p1_sigma'

# fit this model to data:
result  = model.fit(my_y, params, x=my_x)

# print results
print(result.fit_report())

# evaluate individual gaussian components:
peaks = model.eval_components(params=result.params, x=my_x)

# plot results:
plt.plot(my_x, my_y, label='data')
plt.plot(my_x, result.best_fit, label='best fit')
plt.plot(my_x, peaks['p1_'])
plt.plot(my_x, peaks['p2_'])
plt.plot(my_x, peaks['p3_'])
plt.show()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM