@@ -848,18 +848,21 @@ function objectiveFunctionDefinition!(
848
848
auxVariables[i] >= - parametersVectorExtended[i]
849
849
end
850
850
)
851
- λ = 1 / sqrt (T)
852
- @objective (jumpModel, Min, sum (jumpModel[:ϵ ] .^ 2 ) + λ * sum (auxVariables))
851
+ # Make lambda a model parameter
852
+ @variable (jumpModel, λ in Parameter (1.0 ))
853
+ set_parameter_value (jumpModel[:λ ], 1 / sqrt (T))
854
+ @objective (jumpModel, Min, sum (jumpModel[:ϵ ] .^ 2 ) + jumpModel[:λ ] * sum (auxVariables))
853
855
end
854
856
elseif objectiveFunction == " ridge"
855
857
if length (parametersVectorExtended) == 0
856
858
@objective (jumpModel, Min, sum (jumpModel[:ϵ ] .^ 2 ))
857
859
else
858
- λ = 1 / sqrt (T)
860
+ @variable (jumpModel, λ in Parameter (1.0 ))
861
+ set_parameter_value (jumpModel[:λ ], 1 / sqrt (T))
859
862
@objective (
860
863
jumpModel,
861
864
Min,
862
- sum (jumpModel[:ϵ ] .^ 2 ) + λ * sum (parametersVectorExtended .^ 2 )
865
+ sum (jumpModel[:ϵ ] .^ 2 ) + jumpModel[ :λ ] * sum (parametersVectorExtended .^ 2 )
863
866
)
864
867
end
865
868
elseif objectiveFunction == " ml"
@@ -893,7 +896,43 @@ Optimizes the SARIMA model using the specified objective function.
893
896
function optimizeModel! (jumpModel:: Model , model:: SARIMAModel , objectiveFunction:: String )
894
897
JuMP. optimize! (jumpModel)
895
898
896
- if objectiveFunction == " bilevel"
899
+ if objectiveFunction == " lasso" || objectiveFunction == " ridge"
900
+ lambdaPath = getLambdaPath (values (model. y), getHyperparametersNumber (model))
901
+ # Based on the lambda path, select the best lambda value according to the information
902
+ # criteria BIC
903
+ bestLambda = 1
904
+ best_bic = Inf
905
+ for i in eachindex (lambdaPath)
906
+ # set the lambda value
907
+ set_parameter_value (jumpModel[:λ ], lambdaPath[i])
908
+ JuMP. optimize! (jumpModel)
909
+
910
+ # Calculate residuals variance for BIC computation
911
+ model_variance = computeSARIMAModelVariance (
912
+ jumpModel,
913
+ objectiveFunction,
914
+ getHyperparametersNumber (model),
915
+ 1 ,
916
+ )
917
+
918
+ # Calculate BIC for this lambda
919
+ T = length (jumpModel[:ϵ ])
920
+ df = sum (value .(jumpModel[:ϵ ]) .!= 0 ) # Effective degrees of freedom
921
+ current_bic = T * log (model_variance) + log (T) * df
922
+ if current_bic < best_bic
923
+ bestLambda = i
924
+ best_bic = current_bic
925
+ end
926
+ aux_variables = all_variables (jumpModel)
927
+ aux_solutions = value .(aux_variables)
928
+ set_start_value .(aux_variables, aux_solutions)
929
+ end
930
+ @info " Best lambda value: $(lambdaPath[bestLambda]) "
931
+ @info " Best BIC value: $(best_bic) "
932
+ set_parameter_value (jumpModel[:λ ], lambdaPath[bestLambda])
933
+ JuMP. optimize! (jumpModel)
934
+
935
+ elseif objectiveFunction == " bilevel"
897
936
898
937
function optimizeMA (coefficients)
899
938
maCoefficients = coefficients[1 : model. q]
@@ -3818,3 +3857,70 @@ function gridSearch(
3818
3857
end
3819
3858
return bestModel
3820
3859
end
3860
+
3861
+ """
3862
+ getLambdaPath(yValues::Vector{T}, parametersVector::Vector,
3863
+ nλ::Int=10, λminratio::Union{Nothing,Float64}=nothing) where T <: AbstractFloat
3864
+
3865
+ Generates a path of lambda values following the Lasso.jl approach.
3866
+
3867
+ # Arguments
3868
+ - `yValues`: Vector of response values (differenced time series)
3869
+ - `nparameters::Int`: Number of model parameters to be penalized
3870
+ - `nλ::Int`: Number of lambda values to try in the path (default: 10)
3871
+ - `λminratio::Union{Nothing,Float64}`: Ratio of minimum lambda to maximum lambda (default: 0.0001 for n > p, 0.01 for n ≤ p)
3872
+
3873
+ # Returns
3874
+ - `Vector{T}`: The path of lambda values
3875
+ """
3876
+ function getLambdaPath (yValues:: Vector{T} , nparameters:: Int ;
3877
+ nλ:: Int = 10 , λminratio:: Union{Nothing,Float64} = nothing ) where T <: AbstractFloat
3878
+ # Number of observations
3879
+ n = length (yValues)
3880
+
3881
+ # Number of parameters
3882
+ p = nparameters
3883
+
3884
+ # Adjust λminratio based on number of observations vs parameters
3885
+ if isnothing (λminratio)
3886
+ λminratio = n > p ? 0.0001 : 0.01
3887
+ end
3888
+
3889
+ # Calculate mean of series (null model prediction)
3890
+ nullPrediction = mean (yValues)
3891
+
3892
+ # Calculate residuals from null model
3893
+ residuals = yValues .- nullPrediction
3894
+
3895
+ # Create a simple design matrix for AR terms
3896
+ # For time series, we'll use lagged values as predictors
3897
+ X = zeros (T, n- p, p)
3898
+ for i in 1 : p
3899
+ for j in 1 : (n- p)
3900
+ if j+ p- i > 0 && j+ p- i <= length (residuals)
3901
+ X[j, i] = residuals[j+ p- i]
3902
+ end
3903
+ end
3904
+ end
3905
+
3906
+ # Calculate X'y (correlation between predictors and response)
3907
+ Xy = zeros (T, p)
3908
+ for i in 1 : p
3909
+ if p+ 1 <= length (residuals)
3910
+ Xy[i] = dot (X[:, i], residuals[p+ 1 : end ])
3911
+ end
3912
+ end
3913
+
3914
+ # Compute λmax as the maximum absolute correlation
3915
+ λmax = maximum (abs .(Xy)) / n
3916
+
3917
+ # Ensure λmax is not zero
3918
+ if λmax < eps (T)
3919
+ λmax = one (T)
3920
+ end
3921
+
3922
+ # Generate lambda path following Lasso.jl approach
3923
+ logλmax = log (λmax)
3924
+ λpath = exp .(range (logλmax, stop= logλmax + log (λminratio), length= nλ))
3925
+ return λpath
3926
+ end
0 commit comments