使用 scipy.optimize 拟合多个高斯的大多数 pythonic 方法

Most pythonic way to fit multiple gaussians using scipy.optimize

from scipy.optimize import curve_fit

def func(x, a, b):
    return a * np.exp(-b * x)

xdata = np.linspace(0, 4, 50)
ydata = np.linspace(0, 4, 50)
popt, pcov = curve_fit(func, xdata, ydata)

使用类似上述方法的方法很容易在 python 中拟合任意高斯分布。但是,我想准备一个函数,让用户始终使用 select 任意数量的高斯分布,并仍然尝试找到最合适的。

我正在尝试弄清楚如何修改函数 func 以便我可以向它传递一个附加参数 n=2 例如它会 return 一个函数尝试拟合 2 个高斯函数,类似于:

from scipy.optimize import curve_fit

def func2(x, a, b, d, e):
    return (a * np.exp(-b * x) + c * np.exp(-d * x))  

xdata = np.linspace(0, 4, 50)
ydata = np.linspace(0, 4, 50)
popt, pcov = curve_fit(func2, xdata, ydata)

无需对这些额外的情况进行硬编码,这样我们就可以像 func(...,n=2) 一样传递单个函数并获得与上述相同的结果。我很难找到一个优雅的解决方案。我的猜测是最好的解决方案是使用 lambda 函数。

您可以使用 def func(x, *args) 将函数定义为采用可变数量的参数。 *args 变量包含类似 (a1, b1, a2, b2, a3, ...) 的内容。可以循环遍历这些并对高斯求和,但我展示的是矢量化解决方案。

由于 curve_fit 无法再确定此函数的参数数量,您可以提供一个初始猜测来确定您想要拟合的高斯数量。每个高斯分布需要两个参数,因此 [1, 1]*n 生成一个正确长度的参数向量。

from scipy.optimize import curve_fit
import numpy as np

def func(x, *args):
    x = x.reshape(-1, 1)
    a = np.array(args[0::2]).reshape(1, -1)
    b = np.array(args[1::2]).reshape(1, -1)
    return np.sum(a * np.exp(-b * x), axis=1)

n = 3

xdata = np.linspace(0, 4, 50)
ydata = np.linspace(0, 4, 50)
popt, pcov = curve_fit(func, xdata, ydata, p0=[1, 1] * n)