繁体   English   中英

Python曲线与变化点拟合

[英]Python curve fit with change point

由于我真的很难从R代码转换为Python代码,因此我想寻求帮助。 我想使用的代码是从stackexchange数学论坛提供给我的。

https://math.stackexchange.com/questions/2205573/curve-fitting-on-dataset

我知道发生了什么事。 但是我真的很难解决R代码,因为我从未见过任何东西。 我已经编写了返回平方和的函数。 但是,我对如何使用与优化函数相似的函数感到困惑。 而且我也不太喜欢初始值的猜测。 我希望最好运行并重新运行某种优化函数,直到获得所需的结果为止,因为对几乎完美的曲线拟合的需求确实很高。

def model (par,x):
    n = len(x)
    res = []
    for i in range(1,n):
        A0 = par[3] + (par[4]-par[1])*par[6] + (par[5]-par[2])*par[6]**2
        if(x[i] == par[6]):
            res[i] = A0 + par[1]*x[i] + par[2]*x[i]**2
        else:
            res[i] = par[3] + par[4]*x[i] + par[5]*x[i]**2
    return res

这是我的模型功能...

def sum_squares (par, x, y):
    ss = sum((y-model(par,x))^2)
    return ss

这是平方和

但是我不知道如何转换它:

 #I found these initial values with a few minutes of guess and check.
 par0 <- c(7,-1,-395,70,-2.3,10)
 sol <- optim(par= par0, fn=sqerror, x=x, y=y)$par

到Python代码...

似乎我已经能够解决问题。

def model (par,x):
    n = len(x)
    res = np.array([]) 
    for i in range(0,n):
        A0 = par[2] + (par[3]-par[0])*par[5] + (par[4]-par[1])*par[5]**2
        if(x[i] <= par[5]):
            res = np.append(res, A0 + par[0]*x[i] + par[1]*x[i]**2)
        else:
            res = np.append(res,par[2] + par[3]*x[i] + par[4]*x[i]**2)
    return res

def sum_squares (par, x, y):
    ss = sum((y-model(par,x))**2)
    print('Sum of squares = {0}'.format(ss))
    return ss

然后,我使用了以下功能:

parameter = sy.array([0.0,-8.0,0.0018,0.0018,0,200])
res = least_squares(sum_squares, parameter, bounds=(-360,360), args=(x1,y1),verbose = 1)

唯一的问题是,它不会产生我想要的结果...这主要是因为我的x值为[0,360],而Y值仅相差约0.2,因此很难破解此函数,并产生以下(较差的)结果:

结果

我写了一个开放源代码的Python软件包(BSD许可证),该软件包具有针对scipy Levenberg-Marquardt求解器的遗传算法(差分进化)前端,其功能类似于您在问题中所描述的。 github URL是:

https://github.com/zunzun/pyeq3

它带有一个“用户定义的函数”示例,该示例非常易于使用:

https://github.com/zunzun/pyeq3/blob/master/Examples/Simple/FitUserDefinedFunction_2D.py

以及命令行,GUI,群集,并行和基于Web的示例。 您可以使用“ pip3 install pyeq3”安装该软件包,以查看它是否适合您的需求。

我认为x值[0,360]和y值(您说是〜0.2)的范围可能不是问题。 为参数获取良好的初始值可能更为重要。

在具有numpy / scipy的Python中,您肯定不希望循环x的值,而要做更多类似的事情

def model(par,x):
    res = par[2] + par[3]*x + par[4]*x**2        
    A0  = par[2] + (par[3]-par[0])*par[5] + (par[4]-par[1])*par[5]**2
    res[np.where(x <= par[5])] = A0 + par[0]*x + par[1]*x**2 
    return res

对我来说,尚不清楚该形式确实是您想要的:为什么A0(一个与x无关的值添加到模型的一部分中)如此复杂且相互依赖于其他参数?

更重要的是,你的sum_of_squares()函数其实并没有什么least_squares()想:你应该返回残阵,你不应该做自己平方的总和。 所以,那应该是

def sum_of_squares(par, x, y): 
    return (y - model(par, x))

但最重要的是,存在一个概念问题可能会困扰该模型:您的par [5]表示模型更改形式的断点。 这些优化例程很难找到。 这些例程通常会对每个参数值进行非常小的更改,以估计相对于该变量的残差数组的导数,以便弄清楚如何更改该变量。 对于本质上用作整数的参数,初始值的微小变化将完全无效,并且算法将无法确定该参数的值。 使用某些scipy.optimize算法(尤其是leastsq ),您可以指定要进行的相对更改的比例。 使用leastsq称为epsfcn 您可能需要将此值设置为0.3或1.0以使断点适合工作。 不幸的是,不能为每个变量设置此值,而只能为每个拟合设置。 您可能需要与此和其他选项进行实验least_squaresleastsq

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM