Python曲线适合变化点

时间:2017-03-30 12:31:39

标签: python r curve-fitting curve

由于我很难从R代码到Python代码,我想请一些帮助。我想要使​​用的代码是通过stackexchange的数学论坛提供给我的。

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

我明白发生了什么。但我真的很难尝试解决R代码,因为我从未见过它。我写了函数来返回平方和。但我仍然坚持如何使用类似于optim函数的函数。而且我也不喜欢初始值的猜测。我希望运行并重新运行一种优化函数,直到得到想要的结果,因为我对近乎完美的曲线拟合的需求非常高。

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代码......

3 个答案:

答案 0 :(得分:0)

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

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,所以这是一个难题破解这个功能,它会产生这个(差)结果:

Result

答案 1 :(得分:0)

我写了一个开源Python包(BSD许可证),它有一个遗传算法(差异进化)前端到scipy Levenberg-Marquardt解算器,它的功能与你在问题中描述的类似。 github URL是:

https://github.com/zunzun/pyeq3

它带有一个&#34;用户定义的功能&#34;这个例子相当容易使用:

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

以及命令行,GUI,群集,并行和基于Web的示例。您可以使用&#34; pip3 install pyeq3&#34;安装软件包。看它是否适合你的需要。

答案 2 :(得分:0)

我认为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))

但最重要的是,有一个概念问题可能会困扰这个模型:你的标准[5]意味着代表一个模型改变形式的断点。这些优化例程很难找到。这些例程通常对每个参数值进行非常小的改变,以估计剩余阵列相对于该变量的导数,以便弄清楚如何改变该变量。如果参数主要用作整数,则初始值的微小变化根本不起作用,算法将无法确定此参数的值。使用一些scipy.optimize算法(特别是leastsq),您可以指定要进行相对更改的比例。使用名为leastsq的{​​{1}}。您可能需要将此值设置为高达0.3或1.0,以使断点适合工作。不幸的是,这不能按变量设置,只能按照拟合。您可能需要尝试使用epsfcnleast_squares的此选项和其他选项。