Skip to content
Laviyx Learn

Try

Machine Learning course menu

Ridge and Lasso Regression: Regularisation Explained

Learn regularisation for linear models: why large coefficients overfit, Ridge (L2) and Lasso (L1) penalties, the alpha parameter, how Lasso selects features by setting coefficients to zero, ElasticNet, and why scaling matters.

Intermediate7 min readUpdated
On this page

A linear model with many features, especially compared with the number of rows, can fit noise by giving some features huge coefficients. Regularisation adds a penalty for large coefficients to the training objective, so the model prefers simpler explanations. It usually improves performance on new data.

The two penalties#

  • Ridge (L2) adds alpha × (sum of squared coefficients). It shrinks all coefficients towards zero, but rarely to exactly zero.
  • Lasso (L1) adds alpha × (sum of absolute coefficients). It can shrink coefficients to exactly zero, removing features: built-in feature selection.

alpha controls the strength: 0 means ordinary linear regression; larger values mean a simpler model.

Seeing the effect#

The data below has only 50 training rows but 30 features, and only 5 features truly matter; the rest are noise. That is exactly the situation where plain linear regression overfits:

Python
import numpy as np
from sklearn.linear_model import Lasso, LinearRegression, Ridge
from sklearn.model_selection import train_test_split

rng = np.random.default_rng(7)
X = rng.normal(size=(80, 30))
true_coef = np.zeros(30)
true_coef[:5] = [4, -3, 2.5, 2, -1.5]
y = X @ true_coef + rng.normal(0, 2, 80)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=30, random_state=0)

for name, model in [("linear", LinearRegression()), ("ridge", Ridge(alpha=1)), ("lasso", Lasso(alpha=0.3))]:
    model.fit(X_train, y_train)
    nonzero = int((np.abs(model.coef_) > 1e-6).sum())
    print(f"{name:>6}: train R² {model.score(X_train, y_train):.3f}, test R² {model.score(X_test, y_test):.3f}, non-zero coefficients {nonzero}")
Output
linear: train R² 0.956, test R² 0.748, non-zero coefficients 30
 ridge: train R² 0.955, test R² 0.772, non-zero coefficients 30
 lasso: train R² 0.921, test R² 0.855, non-zero coefficients 9

Plain linear regression fits the training data best but generalises worst. Both regularised models do better on the test set, and Lasso, which matches this data (only a few features matter), does best while keeping only a handful of features. As the next sections show, the right alpha matters: too much regularisation makes things worse.

What Lasso keeps#

Python
import numpy as np
from sklearn.linear_model import Lasso
from sklearn.model_selection import train_test_split

rng = np.random.default_rng(7)
X = rng.normal(size=(80, 30))
true_coef = np.zeros(30)
true_coef[:5] = [4, -3, 2.5, 2, -1.5]
y = X @ true_coef + rng.normal(0, 2, 80)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=30, random_state=0)

lasso = Lasso(alpha=0.3).fit(X_train, y_train)
kept = np.flatnonzero(np.abs(lasso.coef_) > 1e-6)
print("features kept:", kept.tolist())
print("their coefficients:", lasso.coef_[kept].round(2).tolist())
Output
features kept: [0, 1, 2, 3, 4, 5, 7, 23, 26]
their coefficients: [3.16, -2.54, 2.46, 1.69, -0.92, 0.01, -0.05, -0.02, 0.09]

The first five features, the ones that really matter, are kept with coefficients somewhat shrunk towards zero (that shrinking is the price of regularisation). Any other kept feature has a small coefficient.

Choosing alpha#

Too small an alpha barely regularises; too large shrinks everything and underfits. Try a range and compare on validation data, or let RidgeCV / LassoCV choose with cross-validation:

Python
import numpy as np
from sklearn.linear_model import LassoCV, Ridge
from sklearn.model_selection import train_test_split

rng = np.random.default_rng(7)
X = rng.normal(size=(80, 30))
true_coef = np.zeros(30)
true_coef[:5] = [4, -3, 2.5, 2, -1.5]
y = X @ true_coef + rng.normal(0, 2, 80)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=30, random_state=0)

for alpha in [0.1, 1, 10, 100, 1000]:
    score = Ridge(alpha=alpha).fit(X_train, y_train).score(X_test, y_test)
    print(f"ridge alpha={alpha:>6}: test R² {score:.3f}")

cv = LassoCV(cv=5, random_state=0).fit(X_train, y_train)
print("LassoCV chose alpha =", round(cv.alpha_, 3), "test R²", round(cv.score(X_test, y_test), 3))
Output
ridge alpha=   0.1: test R² 0.752
ridge alpha=     1: test R² 0.772
ridge alpha=    10: test R² 0.686
ridge alpha=   100: test R² 0.349
ridge alpha=  1000: test R² 0.035
LassoCV chose alpha = 0.39 test R² 0.851

Scale your features first#

The penalty treats every coefficient equally, but coefficients depend on feature units. Without scaling, a feature measured in rupees and one measured in lakhs would be penalised very differently. Always standardise before Ridge or Lasso, ideally inside a pipeline: make_pipeline(StandardScaler(), Ridge(alpha=1.0)).

ElasticNet#

ElasticNet mixes both penalties (l1_ratio sets the mix). It keeps Lasso's feature selection while behaving better when several features are strongly correlated, where Lasso tends to pick one at random.

Common mistakes#

Practice#

Practice exercise

On load_diabetes(return_X_y=True) split 75/25 with random_state=1, compare LinearRegression, Ridge(alpha=1) and Lasso(alpha=0.5) by test R² (3 decimals), and print how many coefficients Lasso set to zero.

Show hint

Loop over the three models, fit, score on the test set, then count lasso.coef_ == 0.

Show solution
Python
import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.linear_model import Lasso, LinearRegression, Ridge
from sklearn.model_selection import train_test_split

X, y = load_diabetes(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=1)
models = {"linear": LinearRegression(), "ridge": Ridge(alpha=1), "lasso": Lasso(alpha=0.5)}
for name, m in models.items():
    print(name, round(m.fit(X_train, y_train).score(X_test, y_test), 3))
print("lasso zero coefficients:", int(np.sum(models["lasso"].coef_ == 0)))
Output
linear 0.444
ridge 0.384
lasso 0.383
lasso zero coefficients: 6

Here regularisation does not help: both regularised models score slightly lower. With only 10 features and over 300 training rows, the plain model has little room to overfit, so these penalties mostly shrink useful coefficients. Regularisation pays off when features are many relative to rows, as in the first example; always check on held-out data rather than assuming.

Key takeaway#

Next: Regression Metrics.

Finished this lesson?