diff --git a/src/Lasso.jl b/src/Lasso.jl index a3625d8..df8981a 100644 --- a/src/Lasso.jl +++ b/src/Lasso.jl @@ -209,6 +209,10 @@ const MAX_DEV_FRAC = 0.999 # Compute automatic λ values based on λmax and λminratio function computeλ(λmax, λminratio, α, nλ) λmax /= α + if isapprox(λmax, 0; atol=1e-10) # then assuming λmax = 0 + @info "The penalized coefficients equal zero for all values of the regularization parameter λ." + return [0] + end logλmax = log(λmax) exp.(range(logλmax, stop=logλmax + log(λminratio), length=nλ)) end diff --git a/src/coordinate_descent.jl b/src/coordinate_descent.jl index f8d71ee..67f69ea 100644 --- a/src/coordinate_descent.jl +++ b/src/coordinate_descent.jl @@ -685,7 +685,7 @@ function StatsBase.fit!(path::RegularizationPath{S,T}; verbose::Bool=false, irls niter = 0 if nλ == 0 i = 0 - else + elseif i <= nλ # need this check because it is possible that autoλ is true and nλ is 1 while true # outer loop obj = convert(T, Inf) last_dev_ratio = dev_ratio @@ -776,6 +776,7 @@ function StatsBase.fit!(path::RegularizationPath{S,T}; verbose::Bool=false, irls end end + i = min(i, nλ) path.λ = path.λ[1:i] path.pct_dev = pct_dev[1:i] path.coefs = coefs[:, 1:i] @@ -819,29 +820,32 @@ function StatsBase.fit!(path::RegularizationPath{S,T}; verbose::Bool=false, i = 1 end - while true # outer loop - last_dev_ratio = dev_ratio - curλ = λ[i] + if i <= nλ # need this check because it is possible that autoλ is true and nλ is 1 + while true # outer loop + last_dev_ratio = dev_ratio + curλ = λ[i] - # Run coordinate descent - niter += cdfit!(newcoef, cd, curλ, criterion) + # Run coordinate descent + niter += cdfit!(newcoef, cd, curλ, criterion) - dev_ratio = cd.dev/nulldev - pct_dev[i] = 1 - dev_ratio - addcoefs!(coefs, newcoef, i) - b0s[i] = intercept(newcoef, cd) + dev_ratio = cd.dev/nulldev + pct_dev[i] = 1 - dev_ratio + addcoefs!(coefs, newcoef, i) + b0s[i] = intercept(newcoef, cd) - # Test whether we should continue - if i == nλ || (stopearly && autoλ && (last_dev_ratio - dev_ratio < MIN_DEV_FRAC_DIFF || - pct_dev[i] > MAX_DEV_FRAC)) - break - end + # Test whether we should continue + if i == nλ || (stopearly && autoλ && (last_dev_ratio - dev_ratio < MIN_DEV_FRAC_DIFF || + pct_dev[i] > MAX_DEV_FRAC)) + break + end - verbose && println("$i: λ=$curλ, pct_dev=$(pct_dev[i])") - poststep(path, cd, i, newcoef) - i += 1 + verbose && println("$i: λ=$curλ, pct_dev=$(pct_dev[i])") + poststep(path, cd, i, newcoef) + i += 1 + end end + i = min(i, nλ) path.λ = path.λ[1:i] path.pct_dev = pct_dev[1:i] path.coefs = coefs[:, 1:i] diff --git a/test/lasso.jl b/test/lasso.jl index 0b4917b..4f6d7ed 100644 --- a/test/lasso.jl +++ b/test/lasso.jl @@ -154,6 +154,24 @@ end end end +# Test case with zero variation in y is handled correctly +function zero_variation_test() + X = [ + 0.5472502169628388 0.37660447632078875 0.06669114126498532 0.4950818154768257; + 0.5142931961160688 0.520205941129849 0.4052730635141131 0.6700530909562794; + 0.5831846867316071 0.3174143498124731 0.772131243876973 0.03386847158881201; + 0.8802489459954292 0.6742158685234003 0.3849775799923969 0.7773264968613842; + 0.9216786846192617 0.7888303438159934 0.09788865152005011 0.34950775139369905 + ] + y = 0.2937233091452627 .+ zeros(size(X, 1)) + path = fit(LassoPath, X, y) + (path.λ == eltype(path.λ)[0]) || return false + (length(path.coefs.nzval) == 0) || return false + return true +end + +@test zero_variation_test() == true + # Test for sparse matrices # @testset "LassoPath Zero in" begin