【问题标题】:How to fit multiple exponential curves using python如何使用python拟合多条指数曲线
【发布时间】:2020-12-14 07:02:19
【问题描述】:

对于单个指数曲线,例如此处的图像 curve_fit for as single exponential curve 中所示,我可以使用 scipy.optimize.curve_fit 拟合数据。但是,我不确定如何实现对由多个指数曲线组成的类似数据集的拟合,如double exponential curves 所示。 我使用以下方法实现了对单曲线的拟合:

def exp_decay(x,a,r):
    return a * ((1-r)**x) 

x = np.linspace(0,50,50)
y = exp_decay(x, 400, 0.06)

y1 = exp_decay(x, 550, 0.06)      # this is to be used to append to y to generate two curves

pars, cov = curve_fit(exp_decay, x, y, p0=[0,0])
plt.scatter(x,y)
plt.plot(x, exp_decay(x, *pars), 'r-')     #this realizes the fit for a single curve

yx = np.append(y,y1)   #this realizes two exponential curves (as shown above - double exponential curves) for which I don't need to fit a model to

有人可以帮助描述如何为两条曲线的数据集实现这一目标。我的实际数据集由多条指数曲线组成,但我认为如果我能实现两条曲线的拟合,我可能能够为我的数据集复制相同的曲线。这不能用 scipy 的 curve_fit 来完成;任何可行的实现都很好。

请帮忙!!!

【问题讨论】:

  • 好消息/坏消息。如果您可以将一条曲线拟合到相似的数据(看起来可以),那么您可以拟合 N 条曲线。您显然(?)需要通过分离数据来分别拟合它们。所以……潜在的坏消息。如何在数据集中标记或区分来自单独曲线的数据?
  • @AirSquid 是的,我可以单曲线;但因为它是来自某些观察的连续数据集,所以分离数据不是一种选择。曲线是我需要找到合适的重复模式。这些曲线具有不同的数据点 - 不同的时期。感谢您的评论。
  • 使用一阶导数标准分割数据集(曲线变化时一阶差值非常高),然后通过转移到原点或添加额外的滞后参数来应用单曲线拟合。最后组装结果。
  • 好吧,您显然必须以某种方式分离不同曲线的数据。曲线拟合算法如何知道要拟合哪条曲线?建议您使用数据扩充您的帖子,或者发布一个新帖子。如果数据在您的示例中在您的 x 轴上间隔开,那么在寻找大跳跃或查看上面建议的导数时会有一些希望......这一切都取决于很多事情!

标签: python python-3.x machine-learning artificial-intelligence data-analysis


【解决方案1】:

您的问题可以通过使用简单的标准(例如一阶导数估计)拆分数据集来轻松解决,然后我们可以将简单的曲线拟合程序应用于每个子数据集。

试验数据集

首先,让我们导入一些包并创建一个包含三条曲线的合成数据集来表示您的问题。

我们使用两个参数指数模型,因为时间原点偏移将由分裂方法处理。我们还添加了噪声,因为现实世界的数据中总是存在噪声:

import numpy as np
import pandas as pd
from scipy import optimize
import matplotlib.pyplot as plt

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

N = 1001
n1 = N//3
n2 = 2*n1

t = np.linspace(0, 10, N)

x0 = func(t[:n1], 1, -0.2)
x1 = func(t[n1:n2]-t[n1], 5, -0.4)
x2 = func(t[n2:]-t[n2], 2, -1.2)

x = np.hstack([x0, x1, x2])
xr = x + 0.025*np.random.randn(x.size)

以图形方式呈现如下:

数据集拆分

我们可以将数据集拆分为三个子数据集,使用一个简单的标准作为一阶导数估计,使用一阶差分对其进行评估。目标是检测曲线何时急剧上升或下降(数据集应在何处拆分。一阶导数估计如下):

dxrdt = np.abs(np.diff(xr)/np.diff(t))

该标准需要一个额外的参数(阈值),必须根据您的信号规格进行调整。该标准相当于:

xcrit = 20
q = np.where(dxrdt > xcrit) # (array([332, 665], dtype=int64),)

而拆分索引是:

idx = [0] + list(q[0]+1) + [t.size] # [0, 333, 666, 1001]

主要标准阈值将受数据上噪声的性质和强度以及两条曲线之间的差距幅度的影响。该方法的使用取决于在存在噪声的情况下检测曲线间隙的能力。当噪声功率与我们想要检测的间隙大小相同时,它将中断。如果噪声严重拖尾(很少有强异常值),您还可以观察到错误的拆分索引。

在这个 MCVE 中,我们将阈值设置为20 [Signal Units/Time Units]

此手工标准的替代方法是将标识委托给 scipy 的出色 find_peaks 方法。但它不会避免根据您的信号规格调整检测的要求。

拟合原点偏移数据集

现在我们可以对每个子数据集(原点偏移时间)应用曲线拟合,收集参数和统计数据并绘制结果:

trials = []
fig, axe = plt.subplots()
for k, (i, j) in enumerate(zip(idx[:-1], idx[1:])):
    p, s = optimize.curve_fit(func, t[i:j]-t[i], xr[i:j])
    axe.plot(t[i:j], xr[i:j], '.', label="Data #{}".format(k+1))
    axe.plot(t[i:j], func(t[i:j]-t[i], *p), label="Data Fit #{}".format(k+1))
    trials.append({"n0": i, "n1": j, "t0": t[i], "a": p[0], "b": p[1],
                   "s_a": s[0,0], "s_b": s[1,1], "s_ab": s[0,1]})
axe.set_title("Curve Fits")
axe.set_xlabel("Time, $t$")
axe.set_ylabel("Signal Estimate, $\hat{g}(t)$")
axe.legend()
axe.grid()
df = pd.DataFrame(trials)

返回如下拟合结果:

    n0    n1    t0         a         b       s_a           s_b      s_ab
0    0   333  0.00  0.998032 -0.199102  0.000011  4.199937e-06 -0.000005
1  333   666  3.33  5.001710 -0.399537  0.000013  3.072542e-07 -0.000002
2  666  1001  6.66  2.002495 -1.203943  0.000030  2.256274e-05 -0.000018

这符合我们的原始参数(请参阅试用数据集部分)。

我们可以通过图形检查拟合优度:

【讨论】:

  • 非常感谢。这似乎真的是它。是否有可能获得包含所有绘图的整个 jupyter 笔记本文件以用于您的实现?只是为了更好地了解这项技术(以前从未这样做过)。再次感谢。
  • @Ziggey,不客气。如果您觉得合适,可以将其标记为答案。这是笔记本:raw.githubusercontent.com/jlandercy/cookbook/master/python/…
  • 我想了解阈值的背景知识在这里非常重要。如果这些知识不方便,如何实现? “该标准需要一个额外的参数(阈值),必须根据您的信号规格进行调整。”如果没有这些信息,您能描述一下如何实现这一目标吗?
  • 你是怎么想出 20 作为阈值的?
  • 我进行了 5 次抽奖,并为此 MCVE 直观地选择了它。如果可以假设您的噪音正常,您可以将此阈值设置为 5 sigma 左右(适当缩放以具有正确的单位)。这将是一个好的开始。您可以从过去的数据中估计它,并评估它与新获取的数据的表现如何。只要您的过程保持稳定,它就应该可以工作。但这取决于您的过程和我们可以从中得出的假设。
猜你喜欢
  • 2023-04-09
  • 1970-01-01
  • 2021-07-23
  • 2014-09-08
  • 1970-01-01
  • 1970-01-01
  • 2018-11-13
  • 2014-12-02
  • 1970-01-01
相关资源
最近更新 更多