lasso_fit <- glmnet(X, y, alpha = 1)
plot(lasso_fit, xvar = "lambda", label = TRUE,
main = "LASSO coefficient paths (NHANES → SBP)")
LASSO (Least Absolute Shrinkage and Selection Operator) uses an \(L_1\) penalty:
\[\hat{\boldsymbol{\beta}}^{\text{lasso}} = \arg\min_{\boldsymbol{\beta}} \left\{ \sum_{i=1}^n (y_i - \mathbf{x}_i^\top\boldsymbol{\beta})^2 + \lambda \sum_{j=1}^p |\beta_j| \right\}\]
The key difference from ridge: the \(L_1\) penalty produces sparse solutions — many \(\hat{\beta}_j = 0\) exactly. LASSO does variable selection automatically.
Geometrically, the \(L_1\) constraint region (a diamond in 2D) has corners on the axes. The OLS ellipsoidal contours are likely to first touch one of these corners, where one or more \(\beta_j = 0\). The \(L_2\) constraint (a circle) has no corners, so the solution is rarely exactly zero.
| LASSO | Ridge | |
|---|---|---|
| Penalty | \(\lambda \sum |\beta_j|\) | \(\lambda \sum \beta_j^2\) |
| Sparsity | Yes — sets coefficients to exactly 0 | No — shrinks toward 0 but not to 0 |
| Variable selection | Yes | No |
| Best when | Few predictors truly matter | Many predictors with small effects |
| Correlated predictors | Selects one arbitrarily | Shrinks all equally |
The elastic net combines both penalties:
\[\lambda \left[\alpha \sum |\beta_j| + (1-\alpha) \sum \beta_j^2 \right]\]
With \(\alpha=1\) this is LASSO; \(\alpha=0\) is ridge. Elastic net handles correlated predictors better than pure LASSO. In glmnet(), alpha controls the mix.


lambda.min: 0.0229
lambda.1se: 2.6356
Non-zero coefficients at lambda.1se:
2 x 1 sparse Matrix of class "dgCMatrix"
lambda.1se
(Intercept) 114.7632
Age 0.2344
Number of non-zero predictors: 1
# Compare LASSO, Ridge, and OLS on train/test
set.seed(42)
tr_idx <- sample(nrow(nhanes_cc), round(0.7 * nrow(nhanes_cc)))
X_tr <- X[tr_idx, ]; y_tr <- y[tr_idx]
X_te <- X[-tr_idx, ]; y_te <- y[-tr_idx]
cv_l <- cv.glmnet(X_tr, y_tr, alpha = 1, nfolds = 10)
cv_r <- cv.glmnet(X_tr, y_tr, alpha = 0, nfolds = 10)
ols <- lm(y_tr ~ X_tr)
rmspe <- function(pred, ytrue) sqrt(mean((ytrue - pred)^2))
cat("OLS test RMSPE: ", round(rmspe(cbind(1, X_te) %*% coef(ols), y_te), 3), "\n")OLS test RMSPE: 17.368
Ridge test RMSPE: 17.398
LASSO test RMSPE: 17.373
R is loading in the background — exercises below will be interactive once ready.
With n=200 and p=20, LASSO should recover X2, X5, X11 reasonably well. lambda.1se tends to be more conservative (fewer predictors) and may miss weak signals (X11 with β=1.5). lambda.min includes more predictors and is more likely to recover all three but may also include false positives.
James et al. (2021). An Introduction to Statistical Learning. — Chapter 6.2