Elastic net
Combine L1 and L2 to get sparsity with correlated-feature stability.
LASSO is great until features are correlated. Then it picks one of the correlated pair almost at random and discards the rest, which is unstable across resamples and uninterpretable. Elastic net mixes L1 and L2 so the selection is sparse and the correlated coefficients stay together.
The objective
[1]with controlling the L1/L2 mix:
- : pure LASSO.
- : pure ridge.
- : equal mix, a common default.
The L1 piece gives sparsity (corners of the penalty ball lie on axes), and the L2 piece smooths the geometry along correlated directions, so the path is stable.
Proximal solver
Splitting elastic net into a smooth and a nonsmooth part:
- Smooth part: .
- Nonsmooth part: .
The smooth gradient is ; the prox of the L1 piece is still soft-thresholding at level . The combined ISTA update is:
The L2 term acts as additional shrinkage before the soft threshold, which is what stabilizes the correlated-feature behavior.
Grouping effect
For two perfectly correlated columns, LASSO assigns the entire weight to one and zero to the other. Elastic net spreads the weight evenly across them because the L2 piece penalizes unequal magnitudes among correlated features. Formally: if , the elastic-net solution satisfies (no such guarantee for LASSO)[2].
Choosing the hyperparameters
Two knobs: (overall strength) and (sparsity vs grouping). The pragmatic approach is to fix at a reasonable value (0.5 is a common default) and cross-validate over . For genuinely sparse problems with uncorrelated features, closer to 1 is fine. With many correlated groups, lower .
Check it on arrays
import numpy as np
rng = np.random.default_rng(0)
n, d = 200, 50
# Two correlated columns + sparse signal
A = rng.normal(size=(n, d)) / np.sqrt(n)
A[:, 1] = A[:, 0] + 0.01 * rng.normal(size=n) # nearly identical to col 0
beta_true = np.zeros(d)
beta_true[0] = 2.0
beta_true[1] = 2.0 # equal weight on the pair
beta_true[5] = -1.5
beta_true[20] = 1.0
y = A @ beta_true + 0.05 * rng.normal(size=n)
def soft(v, t): return np.sign(v) * np.maximum(np.abs(v) - t, 0.0)
def elastic_net(A, y, lam, alpha, steps=2000):
n = A.shape[0]
L = np.linalg.eigvalsh(A.T @ A / n).max() + lam * (1 - alpha)
eta = 1.0 / L
b = np.zeros(A.shape[1])
for _ in range(steps):
grad = A.T @ (A @ b - y) / n + lam * (1 - alpha) * b
b = soft(b - eta * grad, eta * lam * alpha)
return b
beta_lasso = elastic_net(A, y, lam=0.05, alpha=1.0) # pure LASSO
beta_enet = elastic_net(A, y, lam=0.05, alpha=0.5) # elastic net
print("LASSO coef[0,1]:", np.round(beta_lasso[:2], 3), " (often one ~0)")
print("Elastic net coef[0,1]:", np.round(beta_enet[:2], 3), " (split evenly)")
# Total magnitude on the correlated pair: same for both, but elastic net spreads it
print(f"LASSO |b0|+|b1| = {np.abs(beta_lasso[:2]).sum():.3f}")
print(f"Elastic net |b0|+|b1| = {np.abs(beta_enet[:2]).sum():.3f}")
print(f"LASSO diff(b0,b1) = {abs(beta_lasso[0] - beta_lasso[1]):.3f}")
print(f"Elastic net diff(b0,b1) = {abs(beta_enet[0] - beta_enet[1]):.3f} (smaller)")LASSO collapses the correlated pair onto one coefficient; elastic net splits them evenly, recovering the grouping.
Exercises
Exercise 1. At elastic net is pure ridge. Using the objective in the lesson with , derive the closed-form solution and confirm it is the standard ridge estimator. State the effective ridge penalty in terms of .
Solution
Step 1. Set in the objective. The L1 term drops out and the L2 term becomes :
Step 2. The objective is smooth and convex. Its gradient is . Setting it to zero,
Step 3. Solving gives , the ridge estimator with effective penalty . The factor in the elastic-net penalty is what makes reproduce ridge cleanly.
Exercise 2. Prove the grouping property: if two columns are identical, , then the elastic-net solution with satisfies . Show why the L2 term forces this and the pure-L1 case does not.
Solution
Step 1. Suppose an optimum had with . The data-fit term depends on only through , which depends on only via the sum (since the columns are equal). So the residual is unchanged by any redistribution of across the pair.
Step 2. Among all splits with fixed sum , the L2 penalty is strictly convex and minimized at the equal split , by the QM-AM inequality with equality iff . The L1 part is also minimized by any same-sign split, so it does not break the tie.
Step 3. With the strict convexity of the L2 term makes the equal split the unique minimizer, forcing . At (pure LASSO) the L2 term is absent, every same-sign split of ties on penalty and fit, and the solution is non-unique: LASSO may load all of onto one column.
Exercise 3 (code). Verify the grouping effect with exactly identical columns. Build a design where column 1 is a copy of column 0, fit elastic net at , and assert the two coefficients come out equal.
Solution
import numpy as np
def soft(v, t):
return np.sign(v) * np.maximum(np.abs(v) - t, 0.0)
def enet(A, y, lam, alpha, steps=4000):
n = A.shape[0]
L = np.linalg.eigvalsh(A.T @ A / n).max() + lam * (1 - alpha)
eta = 1.0 / L
b = np.zeros(A.shape[1])
for _ in range(steps):
grad = A.T @ (A @ b - y) / n + lam * (1 - alpha) * b
b = soft(b - eta * grad, eta * lam * alpha)
return b
rng = np.random.default_rng(0)
n, d = 100, 6
A = rng.normal(size=(n, d)) / np.sqrt(n)
A[:, 1] = A[:, 0] # column 1 is an exact copy of column 0
beta_true = np.zeros(d); beta_true[0] = 3.0; beta_true[3] = -1.0
y = A @ beta_true + 0.01 * rng.normal(size=n)
b = enet(A, y, lam=0.05, alpha=0.5)
assert np.isclose(b[0], b[1], atol=1e-2) # grouping: equal coefficients on the pair
print("coef[0], coef[1] =", np.round(b[:2], 4), " diff =", round(abs(b[0] - b[1]), 5))The two coefficients on the identical pair come out equal to within solver tolerance, the grouping effect the L2 term guarantees and pure LASSO does not.
The next lesson switches from regression to classification with logistic regression.
References
- [1]Zou, H., & Hastie, T. (2005). "Regularization and variable selection via the elastic net". JRSS-B, 67(2), 301-320. doi:10.1111/j.1467-9868.2005.00503.x↩
- [2]Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning (2nd ed.), §3.4. Springer. doi:10.1007/978-0-387-84858-7. Elastic net and the grouping effect on correlated features.↩