在Julia中使用Lsq拟合

在Julia中使用Lsq拟合,julia,curve-fitting,Julia,Curve Fitting,我尝试在Julia中使用Lsq拟合函数进行拟合。 参数为\gamma和x_0的柯西分布的导数。 按照手册我试过了 f(x, x_0, γ) = -2*(x - x_0)*(π * γ^3 * (1 + ((x - x_0)/γ)^2)^2)^(-1) x_0 = 3350 γ = 50 xarr = range(3000, length = 5000, stop = 4000) yarr = [f(x, x_0, γ) for x in xarr] using LsqFit # p ≡ [x_

我尝试在Julia中使用Lsq拟合函数进行拟合。 参数为\gamma和x_0的柯西分布的导数。 按照手册我试过了

f(x, x_0, γ) = -2*(x - x_0)*(π * γ^3 * (1 + ((x - x_0)/γ)^2)^2)^(-1)
x_0 = 3350
γ = 50
xarr = range(3000, length = 5000, stop = 4000)
yarr = [f(x, x_0, γ) for x in xarr]

using LsqFit
# p ≡ [x_0, γ]
model(x, p) = -2*(x - p[1])*(π * (p[2])^3 * (1 + ((x - p[1])/p[2])^2)^2)^(-1)
p0 = [3349, 49]
curve_fit(model, xarr, yarr, p0)
param = fit.param
。。。它不起作用,给出了一个
方法错误:没有方法匹配-(::StepRangeLen[…]
,让我感到困惑。
谁能告诉我我做错了什么吗?

你写的东西有几个问题:

  • 调用
    model
    函数时,其第一个参数(
    x
    )是自变量的完整向量,而不仅仅是一个值。这就是您提到的错误的来源:

    julia> model(x, p) = -2*(x - p[1])*(π * (p[2])^3 * (1 + ((x - p[1])/p[2])^2)^2)^(-1);
    julia> p0 = [3349, 49];
    julia> model(xarr, p0);
    ERROR: MethodError: no method matching -(::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}, ::Float64)
    
    解决此问题的一种方法是对所有运算符使用点表示法,以便它们在元素方面工作:

    julia> model(x, p) = -2*(x .- p[1]) ./ (π * (p[2])^3 * (1 .+ ((x .- p[1])/p[2]).^2).^2);
    julia> model(xarr, p0); # => No error
    
    但如果这太单调,您可以让宏为您完成工作:

    # just put @. in front of the expression to transform every
    # occurrence of a-b into a.-b (and likewise for all operators)
    # which means to compute the operation elementwise
    julia> model(x, p) = @. -2*(x - p[1])*(π * (p[2])^3 * (1 + ((x - p[1])/p[2])^2)^2)^(-1);
    julia> model(xarr, p0); # => No error
    
  • 另一个问题是,您要查找的参数是浮点值。但是您最初的猜测
    p0
    是用整数初始化的,这会混淆
    曲线拟合
    。有两种方法可以解决此问题。将浮点值放入
    p0

    julia> p0 = [3349.0, 49.0]
    2-element Array{Float64,1}:
     3349.0
       49.0
    
    或使用显式指定元素类型:

    julia> p0 = Float64[3349, 49]
    2-element Array{Float64,1}:
     3349.0
       49.0
    
  • 这不是一个真正的错误,但我会发现计算
    a/b
    比计算
    a*b^(-1)
    更直观。此外,
    yarr
    可以通过简单的广播而不是理解来计算

  • 总括起来:

    f(x, x_0, γ) = -2*(x - x_0)*(π * γ^3 * (1 + ((x - x_0)/γ)^2)^2)^(-1)
    (x_0, γ) = (3350, 50)
    
    xarr = range(3000, length = 5000, stop = 4000);
    # use dot-notation to "broadcast" f and map it
    # elementwise to elements of xarr
    yarr = f.(xarr, x_0, γ);
    
    using LsqFit
    model(x, p) = @. -2*(x - p[1]) / (π * (p[2])^3 * (1 + ((x - p[1])/p[2])^2)^2)
    p0 = Float64[3300, 10]
    
    fit = curve_fit(model, xarr, yarr, p0)
    
    收益率:

    julia> fit.param
    2-element Array{Float64,1}:
     3349.999986535933  
       49.99999203625603
    

    你太棒了!非常感谢!:D在完成你的回答时,我还注意到我在第一次尝试中忘记初始化“fit”,我们称之为“code”-尝试。它现在工作正常。:-)我遇到的另一个问题是:如果方程式符号旁边没有“@”,我如何编写模型函数?我试着用它的点模拟来替换每个操作(+、-、/、*、^),但似乎没有成功?你尝试的应该成功。它编辑了我的答案,为所有必要的运算符显示了一个手动点表示法的示例。还请注意,您可以始终使用
    @macroexpand@。a+b
    以准确了解
    @
    执行的转换类型(这当然适用于任何宏)