使用 scipy.optimize.least_squares 将高斯混合模型拟合到光谱数据

Use scipy.optimize.least_squares to fit Gaussian Mixture Model to spectral data

我正在尝试使用 scipy.minimize 函数将 3 个高斯分布的总和拟合到实验数据。

我需要你的帮助来正确传递 objective 函数,因为这似乎是错误指向的地方。显然,我是 Python.

的新手

scipy.minimize 的文档没有针对此案例的明确示例,并且之前在此处提出的有关 GMM 的问题表述不当。 请指教...

import numpy
from matplotlib import pyplot
from scipy.optimize import minimize, rosen_der, rosen_hess

x = numpy.arange(0, 55)
y = [-0.00058032, -0.00063992, -0.00057869, -0.00058395, -0.00053528,  -0.0002694, -0.0003716, -0.000284,    0.00104651,  0.00209935,  0.00360213,  0.00502779,  0.00625538,  0.00715873,   0.00753231,  0.00712235,  0.00689089,  0.0061677,  0.00544124,  0.00478251,  0.00487787,  0.00415067,  0.00368579,  0.00370327,  0.00323007,  0.0029862,   0.00250529,  0.00219493,  0.00212242,  0.00209026,  0.0020827,  0.00204044,  0.00218628,  0.00236552,  0.00245056,  0.00282404,  0.0031072,   0.00332862,  0.00351655,  0.00367349,  0.00387923,  0.00395812,  0.00388796,  0.00379902,  0.00369458,  0.00350222,  0.00337815,  0.0032241,  0.00306897,  0.00294152,  0.00276761,  0.00257586,  0.00231613,  0.00211727,  0.00190347]

# experimental data: y
# objective function that is to be minimized: G1 + G2 + G3 - y
def sumGauss(x, y, *args):
    m1, m2, m3, s1, s2, s3, k1, k2, k3 = args
    ret = -y
    ret += k1 * numpy.exp(-(x - m1)**2 / (2 * s1**2))
    ret += k2 * numpy.exp(-(x - m2)**2 / (2 * s2**2))
    ret += k3 * numpy.exp(-(x - m3)**2 / (2 * s3**2))
    return ret

initial_values = [15, 29, 43, 1, 1, 1, 1, 1, 1]

res = minimize(sumGauss(x, y), initial_values, method='trust-exact',
                jac=rosen_der, hess=rosen_hess,
                options={'gtol': 1e-8, 'disp': True})

错误信息如下:

Traceback (most recent call last):
File "fit_gaussian.py", line 64, in <module>    res = minimize(sumGauss(x, y), params, method='trust-exact',
File "fit_gaussian.py", line 41, in sumGauss
m1, m2, m3, s1, s2, s3, k1, k2, k3 = args
ValueError: not enough values to unpack (expected 9, got 0)

只有几处需要更改。如果你想拟合数据,最好使用 least_squares:

from scipy.optimize import least_squares

制作y一个numpy数组,这样你就可以对其进行算术运算:

y=numpy.array(y)

不要解压args,它们应该保持单一输入。优化函数通常作用于第一个输入参数,因此向前移动:

def sumGauss(args, x, y):
    m1, m2, m3, s1, s2, s3, k1, k2, k3 = args
    ret = -y
    ret += k1 * np.exp(-(x - m1)**2 / (2 * s1**2))
    ret += k2 * np.exp(-(x - m2)**2 / (2 * s2**2))
    ret += k3 * np.exp(-(x - m3)**2 / (2 * s3**2))
    return ret

然后 运行 优化,那些 jacobians 用于不同的功能,所以不要使用它们。使用关键字 args:

将函数所需的额外参数作为元组传递

res = least_squares(sumGauss, initial_values, method='trf', args=(x,y))

您的优化参数: res.x

绘图,res.fun是残差:

import matplotlib.pyplot as plt
plt.plot(y,'o');plt.plot(res.fun+y);plt.plot(res.fun)