简体   繁体   English

分段函数

[英]Piecewise Function lmfit

I am trying to define a piecewise function to be fitted by lmfit library in Python. 我试图定义一个分段函数,以适合lmfit库在Python中。 The issue I am having is a parameter I have defined for the function will not evaluate alongside the data I am submitting. 我遇到的问题是我为函数定义的参数,不会与我提交的数据一起评估。

I have one example of a case somewhat similar to mine here . 我有几分类似地雷的情况下的一个例子在这里 However, the vectorize function the answer describes wasn't producing values I wanted, and when reading the documentation, it didn't seem to be the answer to my solution. 但是,答案描述的vectorize函数不能产生我想要的值,并且在阅读文档时,它似乎并不是我的解决方案的答案。 I also used scipy.optimize.leastsq, but I got the same issue with lmfit described below. 我也使用了scipy.optimize.leastsq,但是在下面描述的lmfit中也遇到了同样的问题。

I have a my residual function defined such as 我定义了一个残差函数,例如

from lmfit import minimize, Parameters, Model

def residual(params, y, x):
    param1 = params['one']
    param2 = params['two']
    if(param2 < x):
        p = 1
    else:
        p = param1*x + param2
    return p - y 

params = Parameters()
params.add('one', value=1)
params.add('two', value=2)
out = minimize(residual, params,args=(y,x))

I also tried defining the function such that 我也尝试过定义函数

  def f(param1,param2,x):
    if(param2 < x):
        p = 1
    else:
        p = param1*x + param2
    return p

  def residual(params, y, x):
    param1 = params['one']
    param2 = params['two']
    return f(param1,param2,x) - y

I have also tried inline using a lambda function. 我也尝试使用lambda函数进行内联。

I am getting an error 'The truth value of an array with more than one element is ambiguous.' 我收到一个错误“一个元素多的数组的真值不明确。” When I got the error, it made sense why it happened, because (param2 < x) would produce a logical array. 当我得到该错误时,就可以理解为什么会发生,因为(param2 <x)会产生一个逻辑数组。 However, I can't seem to find a way to define the function in a piecewise fashion with the given case to get it fitted with the lmfit.minimize() function. 但是,我似乎找不到一种在给定的情况下以分段方式定义函数以使其与lmfit.minimize()函数相匹配的方法。 I have seen the answer done in Matlab, in which it's nlinfit function seems to evaluate the data element-wise without issue (I tried searching if Python has an equivalent operation to define element-wise computation such as .* or .+, but that doesn't seem to exist as explicitly). 我已经在Matlab中看到了答案,其中nlinfit函数似乎可以毫无问题地评估数据元素(我尝试搜索Python是否具有等效的操作来定义。*或。+之类的元素计算,但是似乎并不明确存在)。

lmfit also seems to operate a bit differently compared to nlinfit, because we have to always have our residuals return (model - y) while nlinfit outputs the result once the function is given, which I am not sure could be another issue. 与nlinfit相比,lmfit的工作方式似乎也有所不同,这是因为必须始终使残差返回(模型-y),而nlinfit在给出函数后才输出结果,我不确定这可能是另一个问题。

So to reiterate, my main question is if there is a method of defining the piecewise function such that it can compare the parameter to the data set. 重申一下,我的主要问题是是否存在一种定义分段函数的方法,以便可以将参数与数据集进行比较。

Any help or explanation would be appreciated, thank you! 任何帮助或解释将不胜感激,谢谢!

In place of (param2 < x) (where param2 is a float and x is an numpy array), you want to use numpy.where . 您想使用numpy.where来代替(param2 < x) (其中param2是一个浮点数, x是一个numpy数组)。 You might try: 您可以尝试:

def residual(params, y, x):
    param1 = params['one']
    param2 = params['two']
    p = param1 * x + param2
    p[np.where(param2 < x)] = 1.0 
    return p - y

I should also warn you about a potential problem with this approach to having a variable be a boundary for a piecewise function. 我还应该警告您有关使用这种方法将变量作为分段函数的边界的潜在问题。

In non-linear fits, variables are always floating point (continuous, non-discrete) values. 在非线性拟合中,变量始终是浮点(连续,离散)值。 As the fit proceeds, it will make small adjustments in the values and see how that small change alters the result. 随着拟合的进行,它将对值进行较小的调整,并查看该较小的变化如何改变结果。 In your approach, the parameter 'two' is used as both the transition between pieces and the offset for the line -- that is good. 在您的方法中,参数“ two”既用作零件之间的过渡,又用作线条的偏移量-很好。

If a parameter is used only as the transition, it may not work. 如果将参数用作过渡,则它可能不起作用。 Consider, say, x=np.array([0, 1., 2., 3., 4., ..., 20.0]) . 考虑x=np.array([0, 1., 2., 3., 4., ..., 20.0]) Having two = 10.5 and two=10.4 would then give the same result. two = 10.5two=10.4将会得到相同的结果。 In that case, the fit would not be able to alter the value of two : it would try a very small change, see no change in the result and give up. 在这种情况下,适合将无法改变的值two :它会尝试一个非常小的变化,看到在结果没有变化,放弃。

So, either make sure that two is also used elsewhere in your real model (assuming your real model is more complicated than the example given), or consider using a more gentle transition rather than a hard change in pieces. 因此,要么确保在真实模型的其他地方也使用了two (假设真实模型比给出的示例更复杂),要么考虑使用更平缓的过渡而不是分块地进行困难的更改。 I find an error-function of width ~spacing between x points often works. 我发现x点之间的宽度〜间距的误差函数经常起作用。 Depending on the nature of your problem, you might try something like this: 根据问题的性质,您可以尝试如下操作:

 from scipy.special import erf, erfc
 def residual(params, y, x):
    param1 = params['one']
    param2 = params['two']
    dx = (max(x) - min(x))/(len(x)-1)
    xhi = (erf((x-param2)/dx) + 1)/2.0
    xlo = (erfc((x-param2)/dx) + 1)/2.0
    p = xlo*1.0 + xhi*(param1*x + param2)
    # note: did you really want?
    # p = xlo*param + xhi*(param1*x + param2)
    # p = param2 + xhi*param1*x
    return p - y

Hope that helps. 希望能有所帮助。

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

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