【问题标题】:Can I fit a spectrum of multiple gaussians whos centroids and peak heights are randomly distributed?我可以拟合质心和峰高随机分布的多个高斯谱吗?
【发布时间】:2021-10-29 16:16:57
【问题描述】:

这里是新手,但我已尝试在发布之前进行尽职调查。对任何无意的失礼深表歉意。

我正在以电压与时间序列的形式从示波器采集数据。时间箱的宽度为 0.8 纳秒。我运行多个“数据捕获”周期。单个捕获将具有固定数量的样本,以及 5 到 15 个高斯峰,确切的峰数未知。高斯峰具有相对受限的 FWHM(在 2 到 3 纳秒之间)、变化的峰高和随机到达时间(即质心位置不是周期性的)。

我一直在使用 Python 对这些数据进行高斯拟合,并且使用 scipy.optimise 库和 astropy 库取得了一些成功。下面包含使用 scipy.optimise 的代码。我可以拟合多个高斯,但我的代码中的一个关键步骤是提供峰数的“猜测”,并为每个峰估计质心位置、峰高和峰宽。有没有办法概括这段代码而不必提供“猜测”?如果我放松“猜测”中的条件,那么拟合就会失去质量。我知道这些峰将是具有良好约束宽度的高斯峰,但我想推广代码以适应任何给定数据捕获中的峰质心和峰高。

import ctypes
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

#Get data from file
with open('test3.txt') as f:
    w, h = [float(x) for x in next(f).split()]
    print(w, h)
    array = [[float(x) for x in line.split()] for line in f]

#Separate    
x, z = zip(*array)
#Change sign since fitting routine seems to
#prefer positive numbers
y=[ -p for p in z]

def func(x, *params):
    y = np.zeros_like(x)
    for i in range(0, len(params), 3):
        ctr = params[i]
        amp = params[i+1]
        wid = params[i+2]
        y = y + amp * np.exp( -((x - ctr)/wid)**2)
    return y

#Guess the peak positions, heights, and widths
guess = [16, 5, 2, 75, 5, 2, 105, 5, 2, 139, 5, 2, 225, 5, 2, 315, 5, 2, 330, 5, 2]

#Fit and print parameters to screen
popt, pcov = curve_fit(func, x, y, p0=guess)
print(popt)
fit = func(x, *popt)

#Plot stuff
plt.plot(x, y)
plt.plot(x, fit , 'r-')
plt.show()

结果如下所示: Plot of Data and Fits

数据文件在这里:https://spaces.hightail.com/receive/5MY7Vc7r9R

这类似于How can I fit multiple Gaussian curved to mass spectrometry data in Python?fit multiple gaussians to the data in python,但是这两个依赖于拟合周期性数据集或具有已知峰位置、宽度和高度的数据集。他们让我走到这一步很有用,但我现在被困住了。有什么想法或建议我可以跟进?

谢谢, 阿迪

【问题讨论】:

  • 嗨,这似乎更像是一个数学问题而不是编码问题,所以我建议查看signal processing,例如但一般来说,优化问题总是需要初步猜测,除非你可能使用人工智能,但在这种情况下,训练数据基本上就是你的猜测。
  • 因此,如果您想避免不得不手动提出猜测,则需要找到某种关系/公式,该关系/公式擅长根据输入数据预测初始猜测。

标签: python curve-fitting


【解决方案1】:

我的想法是我们将曲线的值与其平均值进行比较。
multiplier 变量表示该值必须大于平均值多少倍才能让我们了解这是峰值之一。超过该值的峰值的第一个点被认为是逼近该峰值平均值的起点。
我还将列表替换为 x 和 y 的数组。

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

#Get data from file
with open('test3.txt') as f:
    w, h = [float(x) for x in next(f).split()]
    array = [[float(x) for x in line.split()] for line in f]

#Separate    
x, z = zip(*array)
x = np.array(x)
y = np.array([ -p for p in z])
#Change sign since fitting routine seems to
#prefer positive numbers


def func(x, *params):
    y = np.zeros_like(x)
    for i in range(0, len(params), 3):
        ctr = params[i]
        amp = params[i+1]
        wid = params[i+2]
        y = y + amp * np.exp( -((x - ctr)/wid)**2)
    return y

#Guess the peak positions, heights, and widths
# guess = [16, 5, 2, 75, 5, 2, 105, 5, 2, 139, 5, 2, 225, 5, 2, 315, 5, 2, 330, 5, 2]

def getPeaks(x, y, multiplier):
    x_peaks = []
    isPeak = False
    for i, j in zip(x, y):
        if j > y.mean() * multiplier:
            if not isPeak:
                isPeak = True
                x_peaks.append(i)
        else:
            isPeak = False
    return x_peaks

multiplier = 3
x_peaks = getPeaks(x, y, multiplier)

guess = []
for i in range(len(x_peaks)):
    guess.append(x_peaks[i])
    guess.append(5)
    guess.append(2)
    

#Fit and print parameters to screen
popt, pcov = curve_fit(func, x, y, p0=guess)
print(popt)
fit = func(x, *popt)

#Plot stuff
plt.plot(x, y)
plt.plot(x, fit , 'r--')
# plt.plot(popt[::3], np.ones_like(popt[::3]) * multiplier, 'ko')
plt.show()

【讨论】:

  • 嗨,马克,您的添加效果非常好,是一个非常优雅的解决方案。我已经在其他数据捕获上进行了尝试,其中包含更多的整体数据和多达 55 个峰值 - 它适用于所有这些数据。谢谢!
  • 不客气!
【解决方案2】:

正如 cmets 中提到的,每个迭代算法估计都需要从一些超参数开始。在您描述的问题中,您有初始高斯参数和高斯数。 在估计高斯分布时,EM 算法被证明是收敛的。我建议将它与随机初始高斯参数和网格搜索一起使用,以寻找分布数量的最佳解决方案。从 5 到 15 开始,计算每个解的距离并取最小距离解。 (https://en.m.wikipedia.org/wiki/Expectation%E2%80%93maximization_algorithm)

【讨论】:

    猜你喜欢
    • 2021-06-22
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    • 2017-02-23
    • 2021-08-20
    相关资源
    最近更新 更多