Подбирайте интегральную функцию Гаусса к данным

У меня проблема с поиском метода наименьших квадратов для набора заданных данных. Я знаю, что данные следуют функции, ведьма представляет собой свертку гаусса и прямоугольника (рентгеновский снимок через широкую щель). Что я сделал до сих пор, так это взглянул на интеграл свертки и обнаружил, что он сводится к следующему: введите описание изображения  здесь параметр интегрирования a - это ширина щели (неизвестная и желаемая) с g(xt) функцией Гаусса, определенной как введите описание изображения здесь Таким образом, в основном функция, которая подходит, представляет собой интеграционную функцию Гаусса с границами интегрирования, заданными параметром ширины a. Затем интегрирование также выполняется со сдвигом x-t.

Вот меньшая часть данных и ручная посадка. из pylab import * из scipy.optimize import curve_fit из scipy.integrate import quad

# 1/10 of the Data to show the form.
xData = array([-0.1 , -0.09, -0.08, -0.07, -0.06, -0.05, -0.04, -0.03, -0.02,
       -0.01,  0.  ,  0.01,  0.02,  0.03,  0.04,  0.05,  0.06,  0.07,
        0.08,  0.09,  0.1 ])
yData = array([  18.      ,   22.      ,   22.      ,   34.000999,   54.002998,
        152.022995,  398.15799 ,  628.39502 ,  884.781982,  848.719971,
        854.72998 ,  842.710022,  762.580994,  660.435974,  346.119995,
        138.018997,   40.001999,    8.      ,    6.      ,    4.      ,
        6.      ])
yerr = 0.1*yData # uncertainty of the data

plt.scatter(xData, yData)
plt.show()

график данных

# functions
def gaus(x, *p):
    """ gaussian with p = A, mu, sigma """
    A, mu, sigma = p
    return A/(sqrt(2*pi)*sigma)*numpy.exp(-(x-mu)**2/(2.*sigma**2))

def func(x,*p):
    """ Convolution of gaussian and rectangle is a gaussian integral.
        Parameters: A, mu, sigma, a"""
    A, mu, sigma, a = p
    return quad(lambda t: gaus(x-t,A,mu,sigma),-a,a)
vfunc = vectorize(func)  # Probably this is a Problem but if I dont use it, func can only be evaluated at 1 point not an array

Чтобы убедиться, что func действительно описывает данные и мои расчеты верны, я поиграл с данными и функциями и устал сопоставлять их. Я нашел возможным следующее:

p0=[850,0,0.01, 0.04] # will be used as starting values for fitting
sample = linspace(-0.1,0.1,200) # just to make the plot smooth
y, dy = vfunc(sample,*p0)       

plt.plot(sample, y, label="Handmade Fit")
plt.scatter(xData, yData, label="Data")
plt.legend()
plt.show()

Данные и ручная подгонкаПроблема возникает, когда я пытаюсь подогнать данные, используя только что полученные начальные значения:

fp, Sfcov =  curve_fit(vfunc, xData, yData, p0=p0, sigma=yerr)
yf = vfunc(xData, fp)
plt.plot(x, yf, label="Fit")
plt.show()


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-83-6d362c4b9204> in <module>()
----> 1 fp, Sfcov =  curve_fit(vfunc, xData, yData, p0=p0, sigma=yerr)
      2 yf = vfunc(xData,fp)
      3 plt.plot(x,yf, label="Fit")

    /usr/lib/python3/dist-packages/scipy/optimize/minpack.py in curve_fit(f, xdata, ydata, p0, sigma, **kw)
    531     # Remove full_output from kw, otherwise we're passing it in twice.
    532     return_full = kw.pop('full_output', False)
--> 533     res = leastsq(func, p0, args=args, full_output=1, **kw)
    534     (popt, pcov, infodict, errmsg, ier) = res
    535 

/usr/lib/python3/dist-packages/scipy/optimize/minpack.py in leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag)
    369     m = shape[0]
    370     if n > m:
--> 371         raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m))
    372     if epsfcn is None:
    373         epsfcn = finfo(dtype).eps

TypeError: Improper input: N=4 must not exceed M=2

Я думаю, это означает, что у меня меньше точек данных, чем подходящих параметров. Что ж, давайте посмотрим на это:

print("Fit-Parameters: %i"%len(p0))
print("Datapoints: %i"%len(yData))

Fit-Parameters: 4
Datapoints: 21

И на самом деле у меня есть 210 точек данных.

Как написано выше, я действительно не понимаю, почему мне нужно использовать функцию векторизации из numpy для интегральной функции (func ‹> vfunc), но не использовать ее тоже не помогает. В общем, можно передать массив numpy функции, но здесь он, похоже, не работает. С другой стороны, возможно, здесь я переоцениваю силу аппроксимации наименьших квадратов, и в данном случае она может оказаться непригодной, но мне не нравится использовать здесь метод максимального правдоподобия. В общем, я никогда не пытался подогнать интегральную функцию к данным, так что это для меня ново. Скорее всего проблема здесь. Мои знания о квадроциклах ограничены, и может быть лучший способ. Выполнение интеграла аналитически, насколько мне известно, невозможно, но явно было бы идеальным решением;).

Итак, есть идеи, откуда эта ошибка?


person user3613114    schedule 15.06.2014    source источник


Ответы (1)


У вас есть две проблемы. Во-первых, quad возвращает кортеж со значением и оценкой ошибки, а во-вторых, как вы векторизуете. Вы не хотите векторизовать параметр vectors. np.vectorize имеет цикл for, так что нет никакого выигрыша в производительности от самостоятельного выполнения:

def func(x, p):
    """ Convolution of gaussian and rectangle is a gaussian integral.
        Parameters: A, mu, sigma, a"""
    A, mu, sigma, a = p
    return quad(lambda t: gaus(x-t,A,mu,sigma),-a,a)[0]

def vfunc(x, *p):
    evaluations = numpy.array([func(i, p) for i in x])
    return evaluations

Обратите внимание, что я убрал * из func, но не из gaus. Кроме того, я выбираю первый вывод quad.

Принимая во внимание, что это решает вашу проблему, чтобы соответствовать свертке, вы можете подумать о переходе в пространство Фурье. Преобразование Фурье свертки — это произведение преобразований функций, и это сильно упростит вам жизнь. Кроме того, оказавшись в пространстве Фурье, вы можете рассмотреть возможность применения фильтра нижних частот для уменьшения шума. 210 точек данных достаточно для получения хороших результатов.

Кроме того, если вам нужны более мощные алгоритмы, вам следует подумать о iminuit, используя давно зарекомендовавший себя Minuit от ROOT.

person Davidmh    schedule 15.06.2014
comment
Идеально. Спасибо большое. Насчет ROOT и пространства Фурье вы, возможно, правы. В следующий раз я углублюсь в это. К настоящему времени я очень доволен вашим исправлением. - person user3613114; 15.06.2014