使用Python拟合模拟和实验数据点

时间:2011-09-16 13:02:40

标签: python scipy scientific-computing curve-fitting least-squares

我编写了一些执行蒙特卡罗模拟的代码,并生成信号强度与时间的曲线。这种曲线的形状取决于各种参数,我的合作者想要通过我模拟的实验的“真实版本”确定其中的两个参数。

我们已准备好将她的实验数据与我的模拟曲线进行比较,但现在我卡住了,因为我还没有能够执行任何拟合(到目前为止,我已经用模拟的噪声数据替换了实验数据进行测试)。我已经尝试使用scipy.optimize.leastsq,它以代码2退出(根据文档,这意味着拟合成功),但它主要只返回我输入的值(不完全相同,但接近)猜测,无论他们与真正的价值观有多接近或远离。如果它确实报告了不同的值,则生成的曲线仍然与真实曲线明显不同。

另一个观察是infodict['nfev']总是包含

The relative error between two consecutive iterates is at most 0.000000

在使用我的模拟噪声数据时,我已经玩了两个参数的真实值具有相同的数量级(因为我认为使用的步长可能只会合理地影响其中一个),非常不同数量级,我改变了步长(参数epsfcn),但无济于事。

有没有人知道我可能做错了什么, 或者我可以使用哪种拟合函数 leastsq?如果是这样的话:非常感谢!

修改

正如Russ所建议的,我现在将提供有关如何进行模拟的一些细节:我们正在研究与大分子结合的小分子。这种情况发生的概率取决于它们的相互亲和力(亲和力是从实验数据中提取的值之一)。一旦发生了绑定,我们还会模拟复合体再次分离所需的时间(解离时间常数是我们感兴趣的第二个参数)。还有许多其他参数,但它们仅在计算预期信号强度时才变得相关,因此它们与实际模拟无关。

我们从给定数量的小分子开始,每个小分子的状态被模拟多个时间步长。在每个时间步骤,我们使用亲和力值来确定该分子是否未结合,是否与大分子结合。如果它已被绑定,我们使用解离时间常数和它已被绑定的时间量来确定它是否在此步骤中解离。

在这两种情况下,参数(亲和力,解离时间常数)用于计算概率,然后将其与随机数(0和1之间)进行比较,并且在此比较中,它取决于小分子的状态(绑定/未绑定)更改。

编辑2

没有定义明确的函数来确定结果曲线的形状,即使形状清晰可重复,每个数据点都有一个随机元素。 因此,我现在尝试使用optimize.fmin而不是leastsq,但它不会收敛,只是在执行了最大迭代次数后退出。

编辑3

根据Andrea的建议,我上传了sample plot。我真的不认为提供样本数据会有很大帮助,它只是每个x值(时间)的一个y值(信号强度)......

4 个答案:

答案 0 :(得分:3)

为了使用任意函数拟合数据,您通常需要Levenberg–Marquardt算法,这就是scipy.optimize.leastsq使用的算法,因此您最有可能使用正确的函数。

查看this page第5.4节中的教程,看看它是否有帮助。

您的基础功能也很难适应(功能是什么?),但听起来您可能遇到其他问题。

此外 - 与StackOverflow一样,通过使用一些示例代码和更多详细信息直接发布到Scipy-User mailing list,您可能会对scipy问题获得更多知识渊博的答案。

答案 1 :(得分:2)

如果您不知道全局的预期函数形式,但可以预测“下一个”点的预期值,给定系统的当前状态,您可以考虑使用{{ 3}}(是的,“过滤器”在适合的环境中听起来很傻,但名称是历史的,现在不能轻易改变)。

基础数学看起来有点可怕,但重要的是你不必理解它。您通常需要能够

  1. 定义表示空间
  2. 在表示空间中表达您的数据(模拟或实验)。
  3. 定义一个更新程序,该程序从给定的一个
  4. 获取“下一个”表示
  5. 从fitter
  6. 返回的系列表示中提取所需曲线

    似乎至少Kalman filter支持这一点(请注意,这里的界面与我以前的界面不同,我不能提供很多使用它的建议。)

答案 2 :(得分:2)

不完全是答案,但也有PyMinuit尝试。

http://code.google.com/p/pyminuit/

您要做的是将您的pdf和数据点转换为chi ^ 2或-ln(似然)或您选择的指标,并使用PyMinuit最小化该指标。它可以配置得非常冗长,这样你就可以找出出错的地方(如果出错了)。

答案 3 :(得分:1)

由于您只有两个参数,因此您应该只进行网格搜索。

results = {}
for p0 in parameter_space_for_first_parameter:
     for p1 in parameter_space_for_second_parameter:
           results[p0,p1] = compare(p0,p1)

如果您能负担得起计算,compare应执行多次运行(使用不同的初始化)并计算平均值和标准差。您可以尝试使用我的软件包jug来管理您的计算(它专为此类设计而设计)。

最后,绘制结果,看最小值(可能有几个)。这是一种“愚蠢”的方法,但它可以在许多其他方法卡住的情况下工作。

如果计算量太大,可以通过两次传递:粗粒度网格,然后是粗粒度空间最小值附近的细粒度网格。