Значения амплитуды не совпадают между графиком и возвращенными результатами для двухгауссовой подгонки с lmfit

У меня есть набор данных с хорошим поведением, и я пытаюсь сопоставить этот набор данных с двумя гауссовскими установками. Мой код для установки этого набора данных:

from scipy import stats  
from pylab import *
from scipy.optimize import curve_fit
from scipy.integrate import*
from lmfit import Model

data=concatenate((normal(1,.2,5000),normal(2,.2,2500)))
y,x,_=hist(data,100,alpha=.3,label='data')    
x=(x[1:]+x[:-1])/2


def gaussian1(x, amp1, cen1, wid1):
    "1-d gaussian: gaussian(x, amp, cen, wid)"
    return (amp1/(sqrt(2*pi)*wid1)) * exp(-(x-cen1)**2 /(2*wid1**2))

def gaussian2(x, amp2, cen2, wid2):
    "1-d gaussian: gaussian(x, amp, cen, wid)"
    return (amp2/(sqrt(2*pi)*wid2)) * exp(-(x-cen2)**2 /(2*wid2**2))

    
gmodel = Model(gaussian1) + Model(gaussian2)
#pars  = gmodel.make_params( amp1=20,cen1=1.0,wid1=0.2,amp2=10,cen2=2.0,wid2=0.19)

pars  = gmodel.make_params(amp1=260,cen1=1.0,wid1=0.2,amp2=140,cen2=2.0,wid2=0.19)

result = gmodel.fit(y, pars, x=x)    
print(result.fit_report())        

#plt.plot(x, y, 'bo')
plt.plot(x, result.init_fit, 'k--',label='Initial Fit')
plt.plot(x, result.best_fit, 'r-',label='Best Fit')
plt.show()

Это возвращает приведенный ниже вывод и график:

[[Model]]
    (Model(gaussian1) + Model(gaussian2))
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 29
    # data points      = 100
    # variables        = 6
    chi-square         = 8297.41156
    reduced chi-square = 88.2703358
    Akaike info crit   = 453.852870
    Bayesian info crit = 469.483891
[[Variables]]
    amp1:  122.899857 +/- 1.52937166 (1.24%) (init = 260)
    cen1:  1.00027783 +/- 0.00288716 (0.29%) (init = 1)
    wid1:  0.20129987 +/- 0.00290241 (1.44%) (init = 0.2)
    amp2:  61.0231508 +/- 1.51470406 (2.48%) (init = 140)
    cen2:  1.99916357 +/- 0.00564876 (0.28%) (init = 2)
    wid2:  0.19744994 +/- 0.00567828 (2.88%) (init = 0.19)
[[Correlations]] (unreported correlations are < 0.100)
    C(amp2, wid2) =  0.581
    C(amp1, wid1) =  0.581
    C(wid1, wid2) = -0.103

введите здесь описание изображения

Сюжет для этой посадки выглядит прекрасно. Но проблема в том, что значения двух значений амплитуды amp1, amp2 не совпадают с показанными на графике:

По сюжету amp1=255 и amp2 = 125

Согласно напечатанным значениям amp1 = 122.89 и amp2 = 61.02

Другое дело, что он возвращает очень высокое значение хи-квадрат (например, 8297,41).

Пожалуйста, помогите мне исправить значение amp1, amp2 и значение хи-квадрат и решить эти проблемы.


person sundar45    schedule 14.12.2020    source источник


Ответы (3)


Перво-наперво: pylab отклонена matplotlib и import * не рекомендуется из-за загромождения пространства имен, которое может непреднамеренно перезаписать другие функции. Ваш импорт должен быть

from lmfit import Model
import numpy as np
from matplotlib import pyplot as plt

Теперь к вашей реальной проблеме. Вы определили амплитуды вашей модели как ampN/(np.sqrt(2*np.pi)*widN), а не как ampN, поэтому вам необходимо соответственно вычислить фактическую амплитуду A, показанную на рисунке:

A1 = result.params["amp1"].value/(np.sqrt(2*np.pi)*result.params["wid1"].value)
A2 = result.params["amp2"].value/(np.sqrt(2*np.pi)*result.params["wid2"].value)

И вуаля, это действительно амплитуды, которые вы видите на графике.

person Mr. T    schedule 14.12.2020
comment
спасибо, что сказали это снова....нет import *. - person mikuszefski; 15.12.2020
comment
Спасибо, это сработало, это идеальный ответ. - person sundar45; 15.12.2020

Есть ли у вас основания полагать, что по оси Y откладываются усилители, а не сумма двух гауссов?

Подгонка великолепная. На оси Y присутствует не amp, а значение сложения gaussian1 и gaussian2 с их параметрами. Я просто ввел значения, которые вы указали в выводе, подключил к следующему уравнению и построил его.

RecreatedVals = gaussian1(x, 122.899, 1.000,0.201)+gaussian2(x, 61.023, 1.999, 0.197)

Процедура подгонки сработала хорошо. Воссозданные значения и наилучшее соответствие накладываются друг на друга.

Как вы можете видеть, воссозданные значения и ваше наилучшее соответствие находятся друг над другом. Подгонка удалась хорошо. Вам не о чем беспокоиться.

Отредактированный код, если он вам нужен, выглядит следующим образом.

from scipy import stats  
from pylab import *
from scipy.optimize import curve_fit
from scipy.integrate import*
from lmfit import Model, minimize

data=concatenate((normal(1,.2,5000),normal(2,.2,2500)))
y,x,_=hist(data,100,alpha=.3,label='data')

x=(x[1:]+x[:-1])/2



def gaussian1(x, amp1, cen1, wid1):
    "1-d gaussian: gaussian(x, amp, cen, wid)"
    return (amp1/(sqrt(2*pi)*wid1)) * exp(-(x-cen1)**2 /(2*wid1**2))

def gaussian2(x, amp2, cen2, wid2):
    "1-d gaussian: gaussian(x, amp, cen, wid)"
    return (amp2/(sqrt(2*pi)*wid2)) * exp(-(x-cen2)**2 /(2*wid2**2))



gmodel = Model(gaussian1) + Model(gaussian2)
#pars  = gmodel.make_params( amp1=20,cen1=1.0,wid1=0.2,amp2=10,cen2=2.0,wid2=0.19)

pars  = gmodel.make_params(amp1=260,cen1=1.0,wid1=0.2,amp2=140,cen2=2.0,wid2=0.19)

result = gmodel.fit(y, pars, x=x)

print(result.fit_report())

RecreatedVals = gaussian1(x, 122.899, 1.000,0.201)+gaussian2(x, 61.023, 1.999, 0.197)

#plt.plot(x, y, 'bo')
plt.plot(x, result.init_fit, 'k--',label='Initial Fit')
plt.plot(x, result.best_fit, 'r-',label='Best Fit')
plt.plot(x, RecreatedVals, 'g--', label="Back Calculated Values")
plt.show()
person Amit    schedule 14.12.2020

Просто чтобы повторить и перефразировать то, что сказали @Amit и @MrT:

Параметр амплитуды здесь не является максимальной высотой гауссианы. Это амплитуда нормализованной по единице Гаусса - площадь под кривой, если хотите. На самом деле, если бы вы использовали встроенный GaussianModel из lmfit, он сообщил бы не только об этой амплитуде, но и о параметрах height и fwhm:

import numpy as np
import matplotlib.pyplot as plt
from lmfit.models import GaussianModel

np.random.seed(1)

data = np.concatenate((np.random.normal(1,.2,5000),
                       np.random.normal(2,.2,2500)))

y, x, _ = plt.hist(data,100,alpha=.3,label='data')    
x = (x[1:]+x[:-1])/2

gmodel = GaussianModel(prefix='p1_') + GaussianModel(prefix='p2_')
params = gmodel.make_params(p1_amplitude=20, p1_center=1.0, p1_sigma=0.2,
                            p2_amplitude=20, p2_center=2.0, p2_sigma=0.2)

result = gmodel.fit(y, params, x=x)    
print(result.fit_report())        

plt.plot(x, result.init_fit, 'k--',label='Initial Fit')
plt.plot(x, result.best_fit, 'r-',label='Best Fit')
plt.show()

что дало бы

[[Model]]
    (Model(gaussian, prefix='p1_') + Model(gaussian, prefix='p2_'))
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 36
    # data points      = 100
    # variables        = 6
    chi-square         = 8131.43279
    reduced chi-square = 86.5046041
    Akaike info crit   = 451.832224
    Bayesian info crit = 467.463245
[[Variables]]
    p1_amplitude:  116.269963 +/- 1.46784977 (1.26%) (init = 20)
    p1_center:     1.00574290 +/- 0.00290097 (0.29%) (init = 1)
    p1_sigma:      0.19941410 +/- 0.00291806 (1.46%) (init = 0.2)
    p2_amplitude:  57.9229780 +/- 1.45262882 (2.51%) (init = 20)
    p2_center:     1.98961370 +/- 0.00564475 (0.28%) (init = 2)
    p2_sigma:      0.19531569 +/- 0.00567660 (2.91%) (init = 0.2)
    p1_fwhm:       0.46958430 +/- 0.00687150 (1.46%) == '2.3548200*p1_sigma'
    p1_height:     232.606458 +/- 2.93016223 (1.26%) == '0.3989423*p1_amplitude/max(2.220446049250313e-16, p1_sigma)'
    p2_fwhm:       0.45993329 +/- 0.01336736 (2.91%) == '2.3548200*p2_sigma'
    p2_height:     118.310650 +/- 2.96047824 (2.50%) == '0.3989423*p2_amplitude/max(2.220446049250313e-16, p2_sigma)'
[[Correlations]] (unreported correlations are < 0.100)
    C(p1_amplitude, p1_sigma) =  0.581
    C(p2_amplitude, p2_sigma) =  0.581
    C(p1_sigma, p2_sigma)     = -0.107
person M Newville    schedule 15.12.2020