Multi variables in lsqfit

using XLSX, DataFrames, LsqFit

df = DataFrame(XLSX.readtable("SMB.xlsx","平衡吸附量", infer_eltypes = true))

function Com_Langmuir(p, x)
    Ha, bA, bC, Hc = p
    CA = @view x[:, 1]
    CC = @view x[:, 2]
    @. qA = Ha*CA / (1 + bA*CA + bC*CC)
    @. qC = Hc*CC / (1 + bA*CA + bC*CC)
    vcat(qA, qC)   #返回一个列向量
end

xdata = [df.CA df.CC]

ydata = vcat(df.qA_303K, df.qC_303K)

p0 = [1.983, 0.0067, 0.1951, 1.61]

ret = curve_fit(Com_Langmuir, xdata, ydata, p0)
ERROR: BoundsError: attempt to access 4-element Vector{Float64} at index [1:4, 2]
Stacktrace:
  [1] throw_boundserror(A::Vector{Float64}, I::Tuple{Base.Slice{Base.OneTo{Int64}}, Int64})    @ Base .\abstractarray.jl:737
  [2] checkbounds
    @ .\abstractarray.jl:702 [inlined]
  [3] view
    @ .\subarray.jl:184 [inlined]
  [4] Com_Langmuir(p::Matrix{Float64}, x::Vector{Float64})
    @ Main e:\06325\Julialang\test.jl:30
  [5] #18
    @ C:\Users\admin\.julia\packages\LsqFit\OglWj\src\curve_fit.jl:139 [inlined]
  [6] lmfit(f::LsqFit.var"#18#20"{…}, p0::Vector{…}, wt::Vector{…}; autodiff::Symbol, kwargs::@Kwargs{})
    @ LsqFit C:\Users\admin\.julia\packages\LsqFit\OglWj\src\curve_fit.jl:69
  [7] lmfit
    @ C:\Users\admin\.julia\packages\LsqFit\OglWj\src\curve_fit.jl:54 [inlined]
  [8] curve_fit(model::typeof(Com_Langmuir), xdata::Matrix{…}, ydata::Vector{…}, p0::Vector{…}; inplace::Bool, kwargs::@Kwargs{})
    @ LsqFit C:\Users\admin\.julia\packages\LsqFit\OglWj\src\curve_fit.jl:140
  [9] curve_fit(model::Function, xdata::Matrix{Float64}, ydata::Vector{Float64}, p0::Vector{Float64})
    @ LsqFit C:\Users\admin\.julia\packages\LsqFit\OglWj\src\curve_fit.jl:123
 [10] top-level scope
    @ e:\06325\Julialang\test.jl:42
Some type information was truncated. Use `show(err)` to see complete types.

In this function,there is two variables: CA & CC, both are vectors, what syntax should I use?

Question reposted from: Least square with multi-value function - #3 by Stephen

Take a look at what the input to Com_Langmuir is. The error is saying that x is a vector, and you are trying to access the second column.

Do you mean function Com_Langmuir(x, p)?

Yes, CC & CA has number values, Shouldn’t I use matrix in function definition? Just leave x as a vector? But how to pass the valuse of CC & CA to Com_Langmuir function in curve_fit ?

here is the data:

Column 1 Column 2 Column 3 Column 4 E F G H
CA CC qA_293k qA_303K qA_313K qC_293K qC_303K qC_313K
3.46 0.34 7.27 7.00 5.50 0.54 0.51 0.48
5.19 0.51 9.67 9.36 7.80 0.77 0.69 0.64
6.93 0.68 12.70 11.44 9.99 1.02 0.94 0.89
8.66 0.85 15.09 13.96 12.44 1.22 1.12 1.03
10.39 1.02 16.88 15.67 14.81 1.42 1.25 1.22
12.12 1.19 20.01 19.36 17.46 1.61 1.51 1.42

If I change the code as:

function Com_Langmuir(p, x)
    Ha, bA, bC, Hc = p
    CA = x[1]
    CC = x[2]
    qA = Ha*CA ./ (1 .+ bA*CA .+ bC*CC)
    qC = Hc*CC ./ (1 .+ bA*CA .+ bC*CC)
    vcat(qA, qC)   #返回一个列向量
end

xdata = [df.CA, df.CC]

new error appears:

ERROR: MethodError: no method matching isinf(::Vector{Float64})

Closest candidates are:
  isinf(::BigFloat)
   @ Base mpfr.jl:978
  isinf(::Missing)
   @ Base missing.jl:101
  isinf(::ForwardDiff.Dual)
   @ ForwardDiff C:\Users\admin\.julia\packages\ForwardDiff\PcZ48\src\dual.jl:386
  ...

Stacktrace:
 [1] _any
   @ .\reduce.jl:1220 [inlined]
 [2] any
   @ .\reducedim.jl:1020 [inlined]
 [3] check_data_health(xdata::Vector{Vector{Float64}}, ydata::Vector{Float64})
   @ LsqFit C:\Users\admin\.julia\packages\LsqFit\OglWj\src\curve_fit.jl:23
 [4] curve_fit(model::typeof(Com_Langmuir), xdata::Vector{…}, ydata::Vector{…}, p0::Vector{…}; inplace::Bool, kwargs::@Kwargs{})
   @ LsqFit C:\Users\admin\.julia\packages\LsqFit\OglWj\src\curve_fit.jl:131
 [5] curve_fit(model::Function, xdata::Vector{Vector{Float64}}, ydata::Vector{Float64}, p0::Vector{Float64})
   @ LsqFit C:\Users\admin\.julia\packages\LsqFit\OglWj\src\curve_fit.jl:123
 [6] top-level scope
   @ e:\06325\Julialang\test.jl:42
Some type information was truncated. Use `show(err)` to see complete types.

Do you mean function Com_Langmuir(x, p) ?

The syntax for the model is foo(x, params). See the documentation: GitHub - JuliaNLSolvers/LsqFit.jl: Simple curve fitting in Julia

julia> import CSV, DataFrames, LsqFit

julia> data = """
       CA,CC,qA_293k,qA_303K,qA_313K,qC_293K,qC_303K,qC_313K
       3.46,0.34,7.27,7.00,5.50,0.54,0.51,0.48
       5.19,0.51,9.67,9.36,7.80,0.77,0.69,0.64
       6.93,0.68,12.70,11.44,9.99,1.02,0.94,0.89
       8.66,0.85,15.09,13.96,12.44,1.22,1.12,1.03
       10.39,1.02,16.88,15.67,14.81,1.42,1.25,1.22
       12.12,1.19,20.01,19.36,17.46,1.61,1.51,1.42
       """
"CA,CC,qA_293k,qA_303K,qA_313K,qC_293K,qC_303K,qC_313K\n3.46,0.34,7.27,7.00,5.50,0.54,0.51,0.48\n5.19,0.51,9.67,9.36,7.80,0.77,0.69,0.64\n6.93,0.68,12.70,11.44,9.99,1.02,0.94,0.89\n8.66,0.85,15.09,13.96,12.44,1.22,1.12,1.03\n10.39,1.02,16.88,15.67,14.81,1.42,1.25,1.22\n12.12,1.19,20.01,19.36,17.46,1.61,1.51,1.42\n"

julia> df = CSV.read(IOBuffer(data), DataFrames.DataFrame)
6×8 DataFrame
 Row │ CA       CC       qA_293k  qA_303K  qA_313K  qC_293K  qC_303K  qC_313K 
     │ Float64  Float64  Float64  Float64  Float64  Float64  Float64  Float64 
─────┼────────────────────────────────────────────────────────────────────────
   1 │    3.46     0.34     7.27     7.0      5.5      0.54     0.51     0.48
   2 │    5.19     0.51     9.67     9.36     7.8      0.77     0.69     0.64
   3 │    6.93     0.68    12.7     11.44     9.99     1.02     0.94     0.89
   4 │    8.66     0.85    15.09    13.96    12.44     1.22     1.12     1.03
   5 │   10.39     1.02    16.88    15.67    14.81     1.42     1.25     1.22
   6 │   12.12     1.19    20.01    19.36    17.46     1.61     1.51     1.42

julia> function Com_Langmuir(x, p)
           Ha, bA, bC, Hc = p
           CA = @view x[:, 1]
           CC = @view x[:, 2]
           qA = @. Ha * CA / (1 + bA*CA + bC*CC)
           qC = @. Hc * CC / (1 + bA*CA + bC*CC)
           return vcat(qA, qC)
       end
Com_Langmuir (generic function with 1 method)

julia> xdata = [df.CA df.CC]
6×2 Matrix{Float64}:
  3.46  0.34
  5.19  0.51
  6.93  0.68
  8.66  0.85
 10.39  1.02
 12.12  1.19

julia> ydata = vcat(df.qA_303K, df.qC_303K)
12-element Vector{Float64}:
  7.0
  9.36
 11.44
 13.96
 15.67
 19.36
  0.51
  0.69
  0.94
  1.12
  1.25
  1.51

julia> p0 = [1.983, 0.0067, 0.1951, 1.61]
4-element Vector{Float64}:
 1.983
 0.0067
 0.1951
 1.61

julia> ret = LsqFit.curve_fit(Com_Langmuir, xdata, ydata, p0)
LsqFit.LsqFitResult{Vector{Float64}, Vector{Float64}, Matrix{Float64}, Vector{Float64}, Vector{LsqFit.LMState{LsqFit.LevenbergMarquardt}}}([1.9591016841592197, 13.58216904773464, -138.11627273117097, 1.571176537116358], [-0.44929059679496763, 0.30369611921302386, -0.1765545568040796, -0.08488979377925254, 0.7435466251881575, -0.4782080120029555, 0.006248923887321234, 0.0715774743231512, -0.0536302114136612, -0.027791676070707094, 0.04227536237120133, -0.023189712036286503], [3.3437311886808767 -21.903812996616832 -2.1523978086444178 0.0; 4.932717988715785 -47.668295531028825 -4.68416776783525 0.0; … ; 0.0 -10.826815246805841 -1.0628827270494086 0.8224889640699448; 0.0 -14.329863758728356 -1.4069750692351175 0.9463037748263273], true, Iter     Function value   Gradient norm 
------   --------------   --------------
, Float64[])

julia> ret.param
4-element Vector{Float64}:
    1.9591016841592197
   13.58216904773464
 -138.11627273117097
    1.571176537116358
1 Like

I found that the parameters obtained is different from the article, In fact, the object function is in this form:

I’m wondering whether the function definition here is correct or not?

It’s a little hard to tell what you are referring to by a single screenshot, but I assume S is the sum of squares model for fitting that you are trying to replicate. In which case, it probably is correct.

The question should not be whether you find identical parameters, but whether the loss function (the value of S is similar). There might be many parameter settings that lead to near identical loss values.

1 Like