首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用边界可变的多个域函数拟合数据

用边界可变的多个域函数拟合数据
EN

Stack Overflow用户
提问于 2020-07-23 18:20:52
回答 1查看 93关注 0票数 0

正如标题所提到的,我很难将数据点拟合到具有3个域的函数,这些域的边界是我的函数的参数。下面是我正在处理的函数:

代码语言:javascript
复制
global sigma_m
sigma_m=2*10**(-12)

global sigma_f
sigma_f=10**3

def Conductivity (phi,phi_c,t,s):
    sigma=[0]*(len(phi))
    for i in range (0,len(phi)):
        if phi[i]<phi_c:
            sigma[i]=sigma_m*(phi_c-phi[i])**(-s)
        elif phi[i]==phi_c:
            sigma[i]=sigma_f*(sigma_m/sigma_f)**(t/(t+s))
        else:
            sigma[i]=sigma_f*(phi[i]-phi_c)**t      
    return sigma 

我的数据点是:

代码语言:javascript
复制
phi_data=[0,0.005,0.007,0.008,0.017,0.05,0.085,0.10]
sigma_data=[2.00E-12,2.50E-12,3.00E-12,9.00E-04,1.00E-01,1.00E+00,2.00E+00,3.00E+00]

我的约束是phi_c、s和t必须严格大于0(在实践中,phi_c很少大于0.001,但高于0.5,s通常在0.5到1.5之间,t通常在1.5到6之间)。

我的目标是拟合我的数据点,并让我的拟合给出phi_c、s和t的值。可以估计s和t来帮助代码(在我显示的特定数据点集中,t应该在2左右,s应该在0.5左右)。除了我在上面提到的值范围之外,phi_c是完全未知的。

我使用了来自scipy的curve_fit和来自lmfit的模型,但它们都提供了非常小的phi_c值(例如10**(-16)或类似的小值,这让我相信程序希望phi_c为负值)。

下面是我使用curve_fit时的代码:

代码语言:javascript
复制
popt, pcov = curve_fit(Conductivity, phi_data, sigma_data, p0=[0.01,2,0.5], bounds=(0,[0.5,10,3]))

以下是我在使用lmfit中的Model时的代码:

代码语言:javascript
复制
t_estimate=0.5
s_estimate=2
phi_c_estimate=0.005
condmodel = Model(Conductivity)
params = condmodel.make_params(phi_c=phi_c_estimate,t=t_estimate,s=s_estimate)
result = condmodel.fit(sigma_data, params, phi=phi_data)
params['phi_c'].min = 0
params['phi_c'].max = 0.1

这两种选择在绘制时都可以很好地拟合,但phi_c的估计值远非可信。如果你有任何想法,我可以做更好的适合,请让我知道!

PS:我读了一篇很有希望的文章,关于使用symfit包分别拟合不同区域上的数据,不幸的是symfit包不适合我。它一直在卸载我的scipy版本,然后重新安装一个旧版本,然后它告诉我它需要一个新版本的scipy才能工作。

编辑:我设法让symfit包正常工作。下面是我的完整代码:

代码语言:javascript
复制
from symfit import parameters, variables, Fit, Piecewise, exp, Eq
import numpy as np
import matplotlib.pyplot as plt

global sigma_m
sigma_m=2*10**(-12)

global sigma_f
sigma_f=10**3

phi, sigma = variables ('phi, sigma')
t, s, phi_c = parameters('t, s, phi_c')

phi_c.min = 0.001
phi_c.max = 0.1

sigma1 = sigma_m*(phi_c-phi)**(-s)
sigma2 = sigma_f*(phi-phi_c)**t
model = {sigma: Piecewise ((sigma1, phi <= phi_c), (sigma2, phi > phi_c))}

constraints = [Eq(sigma1.subs({phi: phi_c}), sigma2.subs({phi: phi_c}))]

phi_data=np.array([0,0.005,0.007,0.008,0.017,0.05,0.085,0.10])
sigma_data=np.array([2.00E-12,2.50E-12,3.00E-12,9.00E-04,1.00E-01,1.00E+00,2.00E+00,3.00E+00])

fit = Fit(model, phi=phi_data, sigma=sigma_data, constraints=constraints)
fit_result = fit.execute()
print(fit_result)

不幸的是,我得到了以下错误:

代码语言:javascript
复制
  File "D:\Programs\Anaconda\lib\site-packages\sympy\printing\pycode.py", line 236, in _print_ComplexInfinity
    return self._print_NaN(expr)

  File "D:\Programs\Anaconda\lib\site-packages\sympy\printing\pycode.py", line 74, in _print_known_const
    known = self.known_constants[expr.__class__.__name__]

KeyError: 'ComplexInfinity'

我的编码知识非常有限,我不知道这意味着什么,我应该做什么才能不再有这个错误。如果你有什么想法,请告诉我。

EN

回答 1

Stack Overflow用户

发布于 2020-07-25 03:46:09

我不确定我是否有一个单一的答案,但这将是太长了,不适合在评论中。

首先,切换函数形式的模型特别具有挑战性。但是,更重要的是,您的表单具有

代码语言:javascript
复制
 elif phi[i]==phi_c:

对于作为变量的浮点数,这基本上永远不会是真的。您的意思可能不是“完全相等”,而是“非常接近”,这可能是

代码语言:javascript
复制
 elif abs(phi[i] - phi_c) < 1.0e-5:  

或者别的什么..。

但是,将其从for循环转换为使用numpy.where()可能也是值得一试的。

其次,为了确保函数的连续性,你的不同形式实际上在边界上的值是相同的,这一点一点也不清楚。你可能会想要检查一下。

第三,具有幂和指数的模型特别具有挑战性,因为功率的微小变化可能会对结果价值产生巨大影响。也很容易得到“负值提升到非整数值”,这当然很复杂。

第四,那些sigma_msigma_f常量看起来很容易造成麻烦。你绝对应该用你的起始参数值来评估你的模型,看看你是否能用你的模型和合理的起始值来重现你的数据。我怀疑您需要更改您的起始值。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63051995

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档