Loop for minimizing functions with a varying number of arguments

I have to build a loop where each iteration consists in building a function to minimize. At each iteration, the number of arguments is variable. To start, I have two matrices:


X=rand(150,100)
Y=rand(150,1)

At each iteration I select randomly some columns of X to build my function.


k=sample(1:size(X,2))
m=sample(1:size(X,2),k,replace=false)

Let’s say that k=6 columns were selected. I have then to build a function with k=6 arguments:

using Optim
Xsub=X[:,m]
h(beta1,beta2,beta3,beta4,beta5,beta6)=-sum(Y.*Xsub*[beta1,beta2,beta3,beta4,beta5,beta6])+
                                        sum(log.(1 .+exp.(Xsub*[beta1,beta2,beta3,beta4,beta5,beta6])))+(size(Xsub,2)+1)/2*log(2*pi)+1/2*sum([beta1^2,beta2^2,beta3^2,beta4^2,beta5^2,beta6^2])
f(betas) = h(betas...)
betasestim=optimize(f,zeros(size(Xsub,2)),method = ConjugateGradient(),autodiff = :forward,x_tol = 1e-7).minimizer

That’s an example for one particular iteration. But how can I do to build such a function for each iteration, provided that the number k of selected columns is different at each time as they are randomly selected. How can I do to create the arguments beta1, beta2, ..., betak as they are different at each time? I also tried an approach of creating a unique function that will be called at each iteration, such as:

function funcoptim(arguments)

end

where arguments can vary every time the function is called inside of the loop, but I’m stuck…

Look into macros.

@Joris_Pinkse Into macros? :thinking:

Why not pass the vector of arguments as a single argument.

Ok myabe not, why not splatting the arguments?

h(betas...) = -sum(Y .* Xsub .* betas) +  sum(log.(1 .+ exp.(Xsub .* betas))) 
              + (size(Xsub, 2)+1)/2*log(2*pi) + 1/2 * sum(betas .^ 2)

Yes, but at each iteration the vector of arguments is different. For exemple, if k=6 I have the vector beta1,beta2,beta3,beta4,beta5,beta6 but if k=50 the vector wil be beta1,beta2, ..., beta50 (I don’t know how to create an argument with so many variables btw… :frowning: ). I need all the components of the vector to appear as they are the arguments to minimize the function.

yeah sorry I realised that while you were typing. See my edited answer: use splats

Yes I just saw! I’ll try your suggestion and keep you in touch! Just one detail: I must multiply each row of Xsub with betas. It’s a matrix multiplication and not an element-wise multiplication. It shoud be Xsub*betas instead of Xsub .* betas as I had in my code.

It does not work :frowning: I get a ERROR: MethodError: no method matching exp(::Array{Float64,1}) error. Even with a simple case as

h(betas...)=(betas .- 1)^2
optimize(h,zeros(size(Xsub,2)),method = ConjugateGradient(),autodiff = :forward,x_tol = 1e-7).minimizer

use

h(betas...)=(betas .- 1) .^ 2

Are you really sure you need your function to have k arguments though? I seriously think you should be using a vector for this.

2 Likes

Yes… The number of arguments changes at each iteration. The number of arguments is indicated by k. And it doesn’t work even with h(betas...)=(betas .- 1) .^ 2. I get ERROR: MethodError: no method matching -(::Array{Float64,1}, ::Int64).

I get ERROR: MethodError: no method matching -(::Array{Float64,1}, ::Int64) .

Then look for the line (it should be indicated in your stacktrace) where that error come from. There’s probabably a v - 1 that should be v .- 1 for some v::Vector.

Yes… The number of arguments changes at each iteration. The number of arguments is indicated by k .

Does it need to be that way though? I still don’t understand why you can’t just have a function of a single vector and have the length of that vector change in each iteration? This will likely be a lot more efficient than writing a function of 50 variables (in terms of compile time, runtime and writing time).

5 Likes

Ok I’ll check the error. Yes you’re right! It can be a vector whose length changes at each iteration. The important is to find the value of the vector which minimizes the function at each iteration because I need the minimizers.

1 Like

Ah I think I’m close to the solution with the single vector with varying length you proposed!