Path algorithm

The solution path algorithm is useful when the user does not have a pre-specified grid of tuning parameter values and the cofficient estimates at more than a handful of values of the tuning parameter are desired.

Sum-to-zero constraint

In this example, we will solve a problem defined by

Note that we can re-write the constraint as $\boldsymbol{A\beta} = \boldsymbol{b}$ where

First let's generate the predictor matrix X and response vector y. To do so, we need a true parameter vector β whose sum equals to 0. Note n is the number of observations n and p is the number of predictors.

n, p = 50, 100  
β = zeros(p)
β[1:round(Int, p / 4)] = 0
β[(round(Int, p / 4) + 1):round(Int, p / 2)] = 1
β[(round(Int, p / 2) + 1):round(Int, 3p / 4)] = 0
β[(round(Int, 3p / 4) + 1):p] = -1
srand(41)
X = randn(n, p)
50×100 Array{Float64,2}:
  1.21212    -0.153889    0.141533  …  -0.458125    0.0951976  -2.14019   
  0.345895    1.30676     1.60944      -0.409901    0.323719    0.989333  
 -1.27859    -1.18894     0.512064      1.80509     1.62606    -1.44251   
  0.230616    2.54741    -0.523533      2.73358     1.07999     0.432834  
 -1.17103    -0.39082     0.441921     -0.179239   -0.158189   -0.640611  
  1.67135     0.0829011   0.964089  …  -0.720038    1.99359    -0.671572  
 -0.614717    2.16204    -0.0602       -0.324456   -0.616887    1.11243   
 -0.810535    0.974719   -0.045405      0.881578    1.29611     0.696869  
 -1.10879    -1.32489    -1.18272       0.579381   -0.971269   -0.687591  
 -0.219752   -0.447897   -0.974186     -0.880804   -0.480702   -1.36887   
  0.0952544  -0.126203   -0.273737  …  -0.264421    0.565684   -0.798719  
  1.4126      0.295896   -0.213161     -1.46343    -1.27144    -0.0589753 
 -0.418407   -0.479389    0.324243      1.96976     0.867659   -1.2999    
  ⋮                                 ⋱                                     
  0.504861   -1.03911    -0.357771      0.815027    0.919037    1.07463   
 -0.820358   -0.955319    0.097768      0.553219    1.56424     0.10535   
  1.39684     1.93183     0.706641  …  -0.0222014   0.987281   -0.0646814 
 -1.55206     0.446778    1.48206      -1.42384    -1.04209     0.0460478 
  0.928527    0.933087   -0.641975     -1.16347    -0.313851   -1.20434   
  0.380879   -0.144713    1.54374      -0.605637    0.408246    0.632131  
 -1.30233    -2.31664     1.51324       0.765034   -0.515553    0.984551  
  1.36747     1.34059    -0.114778  …   0.846682   -0.565511   -0.539113  
 -2.82496    -0.0447351   0.426242     -0.353497   -0.14583    -0.00304009
 -0.847741    1.49306     1.15522       0.637659    1.70818     0.641035  
 -0.22286    -0.43932    -0.373259      0.788337    0.223785   -0.343495  
  1.32145     0.104516   -0.993017     -0.272744   -0.133748    0.968627
y = X * β + randn(n)
50-element Array{Float64,1}:
  -9.90585 
  -5.40562 
   5.24289 
  -6.29951 
  -4.9586  
  -6.1342  
  -7.90981 
   2.51009 
  -5.79548 
   1.61355 
  -0.722766
  10.4522  
   4.03935 
   ⋮       
   0.397781
  -2.6661  
   5.36896 
  -3.56537 
  -2.402   
   0.11478 
  -5.39248 
   4.38391 
   0.706801
 -10.1066  
  -1.12558 
  14.2473

Since the problem has equality constraints only, we define the constraints as below.

beq = 0.0
Aeq = ones(1, p)
1×100 Array{Float64,2}:
 1.0  1.0  1.0  1.0  1.0  1.0  1.0  1.0  …  1.0  1.0  1.0  1.0  1.0  1.0  1.0
using ConstrainedLasso
β̂path1, ρpath1, objpath, = lsq_classopath(X, y; Aeq = Aeq, beq = beq);

Now we are ready to obtain the solution path using the path algorithm.

β̂path1
100×64 Array{Float64,2}:
 0.0  0.0   0.0         0.0        …   0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.2093     0.215544   0.222576
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 0.0  0.0   0.0         0.0           -0.375203  -0.411589  -0.41253 
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 0.0  0.0   0.0         0.0        …   0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.326206   0.349339   0.355867
 0.0  0.0   0.0         0.0           -0.199751  -0.18084   -0.180896
 0.0  0.0   0.0         0.0        …   0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 ⋮                                 ⋱                                 
 0.0  0.0   0.0         0.0           -0.466409  -0.455344  -0.458507
 0.0  0.0   0.0         0.0           -0.40513   -0.358767  -0.358448
 0.0  0.0   0.0         0.0        …   0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 0.0  0.0  -0.0558231  -0.0953907     -0.852347  -0.877741  -0.88212 
 0.0  0.0   0.0         0.0           -1.08109   -1.05576   -1.06659 
 0.0  0.0   0.0         0.0           -0.679306  -0.621053  -0.621533
 0.0  0.0   0.0         0.0        …   0.0        0.0        0.0     
 0.0  0.0   0.0         0.0           -1.25803   -1.20411   -1.20696 
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.0        0.0        0.0     
 0.0  0.0   0.0         0.0            0.0        0.0        0.0

Let's see if sums of coefficients at all $\rho$ values are approximately 0.

all(abs.(sum(β̂path1, 1)) .< 1e-8)
true

We plot the solution path below.

using Plots; pyplot();
plot(ρpath1, β̂path1', label="", xaxis = ("ρ", (minimum(ρpath1),
      maximum(ρpath1))), yaxis = ("β̂(ρ)"), width=0.5) 
title!("Simulation 1: Solution Path via Constrained Lasso") 

savefig("misc/sumtozero.svg")

Note the figure above is markedly smoother than in the figure obtained from passing in a sequence of tuning parameter values. This is because the solution path algorithm captures all events.

Non-negativity constraint

In this example, the problem is defined by

We can re-write the inequality constraint as $\boldsymbol{C\beta} \leq \boldsymbol{d}$ where

First we define a true parameter vector β that is sparse with a few non-zero coefficients. Let n and p be the number of observations and predictors, respectively.

n, p = 50, 100   
β = zeros(p)
β[1:10] = 1:10
srand(41)
X = randn(n, p)
50×100 Array{Float64,2}:
  1.21212    -0.153889    0.141533  …  -0.458125    0.0951976  -2.14019   
  0.345895    1.30676     1.60944      -0.409901    0.323719    0.989333  
 -1.27859    -1.18894     0.512064      1.80509     1.62606    -1.44251   
  0.230616    2.54741    -0.523533      2.73358     1.07999     0.432834  
 -1.17103    -0.39082     0.441921     -0.179239   -0.158189   -0.640611  
  1.67135     0.0829011   0.964089  …  -0.720038    1.99359    -0.671572  
 -0.614717    2.16204    -0.0602       -0.324456   -0.616887    1.11243   
 -0.810535    0.974719   -0.045405      0.881578    1.29611     0.696869  
 -1.10879    -1.32489    -1.18272       0.579381   -0.971269   -0.687591  
 -0.219752   -0.447897   -0.974186     -0.880804   -0.480702   -1.36887   
  0.0952544  -0.126203   -0.273737  …  -0.264421    0.565684   -0.798719  
  1.4126      0.295896   -0.213161     -1.46343    -1.27144    -0.0589753 
 -0.418407   -0.479389    0.324243      1.96976     0.867659   -1.2999    
  ⋮                                 ⋱                                     
  0.504861   -1.03911    -0.357771      0.815027    0.919037    1.07463   
 -0.820358   -0.955319    0.097768      0.553219    1.56424     0.10535   
  1.39684     1.93183     0.706641  …  -0.0222014   0.987281   -0.0646814 
 -1.55206     0.446778    1.48206      -1.42384    -1.04209     0.0460478 
  0.928527    0.933087   -0.641975     -1.16347    -0.313851   -1.20434   
  0.380879   -0.144713    1.54374      -0.605637    0.408246    0.632131  
 -1.30233    -2.31664     1.51324       0.765034   -0.515553    0.984551  
  1.36747     1.34059    -0.114778  …   0.846682   -0.565511   -0.539113  
 -2.82496    -0.0447351   0.426242     -0.353497   -0.14583    -0.00304009
 -0.847741    1.49306     1.15522       0.637659    1.70818     0.641035  
 -0.22286    -0.43932    -0.373259      0.788337    0.223785   -0.343495  
  1.32145     0.104516   -0.993017     -0.272744   -0.133748    0.968627
y = X * β + randn(n)
50-element Array{Float64,1}:
  12.6173  
  40.3776  
   2.2169  
  27.4631  
  38.592   
   7.82023 
  22.7367  
   7.88475 
  -7.47037 
   0.621035
  -4.91899 
 -14.9363  
   8.26901 
   ⋮       
   7.83882 
  -9.30699 
 -29.7205  
  15.2482  
 -19.1784  
  14.9865  
   2.32728 
  -9.11988 
 -15.3472  
  22.9679  
  -0.997964
  42.6068

Now set up the inequality constraint for the problem.

bineq = zeros(p)
Aineq = - eye(p)
100×100 Array{Float64,2}:
 -1.0  -0.0  -0.0  -0.0  -0.0  -0.0  …  -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -1.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -1.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -1.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -1.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -1.0  …  -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0  …  -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
  ⋮                             ⋮    ⋱         ⋮                          
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0  …  -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -1.0  -0.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0  …  -0.0  -1.0  -0.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -1.0  -0.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -1.0  -0.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -1.0  -0.0
 -0.0  -0.0  -0.0  -0.0  -0.0  -0.0     -0.0  -0.0  -0.0  -0.0  -0.0  -1.0

Now we are ready to obtain the solution path using the path algorithm.

β̂path2, ρpath2, = lsq_classopath(X, y; Aineq = Aineq, bineq = bineq) 
β̂path2
100×183 Array{Float64,2}:
 0.0         0.0      0.0      0.0      …  0.783939   0.791708   0.796529 
 0.0         0.0      0.0      0.0         2.17561    2.18099    2.18875  
 0.0         0.0      0.0      0.0         2.99935    3.008      3.01471  
 0.0         0.0      0.0      0.0         4.30984    4.31056    4.30849  
 0.0         0.0      0.0      0.0         4.98995    4.99358    4.9955   
 0.0         0.0      0.0      0.0      …  6.18666    6.18814    6.18596  
 0.0         0.0      0.0      0.0         6.92076    6.92371    6.92749  
 0.0         0.0      0.0      0.0         8.56963    8.55907    8.54642  
 0.0         0.0      0.0      0.0         8.86323    8.864      8.86137  
 0.00616069  2.01444  2.41323  2.42264     9.8864     9.89486    9.90491  
 0.0         0.0      0.0      0.0      …  0.0        0.0        0.0      
 0.0         0.0      0.0      0.0         0.0        0.0        0.0      
 0.0         0.0      0.0      0.0         0.0        0.0        0.0      
 ⋮                                      ⋱  ⋮                              
 0.0         0.0      0.0      0.0         0.127693   0.122633   0.114126 
 0.0         0.0      0.0      0.0         0.257807   0.261246   0.265255 
 0.0         0.0      0.0      0.0      …  0.294213   0.285664   0.272772 
 0.0         0.0      0.0      0.0         0.0        0.0        0.0      
 0.0         0.0      0.0      0.0         0.0        0.0        0.0      
 0.0         0.0      0.0      0.0         0.0        0.0        0.0      
 0.0         0.0      0.0      0.0         0.0        0.0        0.0      
 0.0         0.0      0.0      0.0      …  0.0        0.0        0.0      
 0.0         0.0      0.0      0.0         0.0838146  0.0914735  0.0978112
 0.0         0.0      0.0      0.0         0.200482   0.202642   0.201151 
 0.0         0.0      0.0      0.0         0.0        0.0        0.0      
 0.0         0.0      0.0      0.0         0.0        0.0        0.0

We plot the solution path below.

plot(ρpath2, β̂path2', label="", xaxis = ("ρ", (minimum(ρpath2),
      maximum(ρpath2))), yaxis = ("β̂(ρ)"), width=0.5) 
title!("Simulation 2: Solution Path via Constrained Lasso") 
savefig("misc/nonneg.svg")

Follow the link to access the .ipynb file of this page.