Skip to content
ExponaBLOG
PRACTICAL AI & MACHINE LEARNING · DAY 011 / 100

Linear regression explained: what developers should know

The simplest model — and still useful.

Expona Admin7 min read

Why linear regression still matters

Linear regression explained: what developers should know is not about nostalgia for statistical methods from the 1990s. It's about having a rock-solid baseline model that trains in milliseconds, runs on a single CPU core, and produces coefficients you can actually explain to stakeholders. We've built countless production systems where a simple linear model beat complex alternatives because it captured the signal without the noise.

In this guide, we'll walk through what linear regression does, why its interpretability matters in real systems, which assumptions you need to validate, and how regularization techniques prevent the overfitting that catches junior engineers off guard.

The core idea: fit a line that minimizes squared error

Linear regression finds the best-fit line (or hyperplane in multiple dimensions) by minimizing the sum of squared errors between predicted and actual values. That's it. No gradient descent gymnastics, no mysterious hyperparameters—just a closed-form solution or a straightforward optimization problem.

Imagine we're predicting delivery time for an e-commerce platform. We collect data: distance (km), number of stops, and time taken (minutes). Linear regression tries to find weights for each feature such that:

python
predicted_time = intercept + (coefficient_distance * distance) + (coefficient_stops * stops)

The model minimizes the cost function:

python
J(w) = (1/2m) * sum((y_pred - y_actual)^2)

where m is the number of samples and w represents all coefficients. This is called the Mean Squared Error (MSE).

In practice, we use libraries that solve this algebraically or iteratively. Here's a minimal example using scikit-learn:

python
from sklearn.linear_model import LinearRegression
import numpy as np

# Sample data: distance, stops -> delivery time
X = np.array([[10, 2], [25, 5], [15, 3], [30, 6]])  # features
y = np.array([20, 45, 25, 55])  # target

model = LinearRegression()
model.fit(X, y)

# Predict new delivery time
new_sample = np.array([[20, 4]])
predicted_time = model.predict(new_sample)
print(f"Predicted time: {predicted_time[0]:.2f} minutes")
print(f"Coefficients: distance={model.coef_[0]:.2f}, stops={model.coef_[1]:.2f}")
print(f"Intercept: {model.intercept_:.2f}")

The output gives you interpretable numbers: "each kilometer adds 1.5 minutes, and each stop adds 3.2 minutes." That directness is why teams reach for linear regression first.

Interpretability: coefficients tell a story

Unlike neural networks or tree ensembles, linear regression coefficients have a clear meaning. A coefficient of 2.0 for a feature means that a one-unit increase in that feature increases the prediction by 2.0 units, holding everything else constant.

This matters enormously in regulated industries. When a lending platform denies a loan, the regulator may demand an explanation. Linear coefficients give you that explanation directly. A coefficient on credit score of 0.15 means the model increases approval probability by 0.15 percentage points per point of credit score.

However, interpretability depends on feature scale. If one feature ranges from 0–10 and another from 0–10,000, their raw coefficients aren't comparable. Standardize your features first:

python
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# Standardize, then fit
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model', LinearRegression())
])

pipeline.fit(X, y)

# Now coefficients reflect relative importance
# A coefficient of 0.8 is "larger" than 0.2 in meaningful terms
print(pipeline.named_steps['model'].coef_)

After standardization, you can rank features by the magnitude of their coefficients. This helps product teams understand which levers drive outcomes.

Assumptions: what can go wrong

Linear regression makes four core assumptions. Violating them doesn't break the math, but it breaks your model's reliability.

1. Linearity

The relationship between features and target must be approximately linear. If you're predicting house price from square footage, and the true relationship is exponential, linear regression will systematically underestimate large houses.

2. Independence of errors

Residuals (prediction errors) must be independent. Time-series data often violates this: today's error correlates with yesterday's. If you're forecasting stock prices or page load times, autocorrelated errors will give you false confidence in the model.

3. Homoscedasticity

Error variance should be constant across all values of the features. If errors grow larger for high values of the target, your confidence intervals will be wrong. Plot residuals versus predictions to check:

python
import matplotlib.pyplot as plt

# Fit model
model = LinearRegression()
model.fit(X, y)
predictions = model.predict(X)
residuals = y - predictions

# Plot residuals
plt.scatter(predictions, residuals)
plt.axhline(y=0, color='r', linestyle='--')
plt.xlabel('Predicted value')
plt.ylabel('Residual')
plt.title('Residual plot: check for patterns')
plt.show()

# Ideally, residuals scatter randomly around zero

4. No multicollinearity

Features should not be highly correlated with each other. If two features are nearly identical, the model can't separate their effects, and coefficients become unstable and hard to interpret. Calculate correlation matrices during exploratory data analysis:

python
import pandas as pd

df = pd.DataFrame(X, columns=['distance', 'stops'])
correlation_matrix = df.corr()
print(correlation_matrix)
# If abs(correlation) > 0.8, you have a problem

Regularization: preventing overfitting and selecting features

In production systems, we rarely use plain linear regression. We use regularization to prevent overfitting and stabilize coefficients.

Ridge regression (L2 regularization)

Ridge adds a penalty for large coefficients to the cost function:

python
J(w) = (1/2m) * sum((y_pred - y_actual)^2) + (lambda / 2m) * sum(w^2)

This shrinks coefficients toward zero, reducing variance without eliminating features. The strength is controlled by the hyperparameter lambda. Higher lambda means stronger shrinkage.

python
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score

# Ridge with lambda = 1.0
model = Ridge(alpha=1.0)  # alpha is lambda in sklearn
model.fit(X, y)

# Cross-validate to pick the best lambda
lambdas = [0.01, 0.1, 1.0, 10.0, 100.0]
for lam in lambdas:
    model = Ridge(alpha=lam)
    scores = cross_val_score(model, X, y, cv=5, scoring='r2')
    print(f"Lambda {lam}: mean R² = {scores.mean():.3f}")

Lasso regression (L1 regularization)

Lasso adds an absolute-value penalty:

python
J(w) = (1/2m) * sum((y_pred - y_actual)^2) + (lambda / m) * sum(|w|)

The absolute value penalty has a unique property: it can shrink coefficients all the way to zero, performing automatic feature selection. This is valuable when you have many features and suspect most are noise.

python
from sklearn.linear_model import Lasso

model = Lasso(alpha=0.1)
model.fit(X, y)

# Inspect coefficients; zeros mean dropped features
for i, coef in enumerate(model.coef_):
    if coef != 0:
        print(f"Feature {i}: {coef:.4f}")
    else:
        print(f"Feature {i}: dropped")

We've used Lasso in fraud detection pipelines where we had hundreds of raw features. It naturally selected the 20–30 most predictive ones, reducing model complexity and improving inference speed.

Elastic Net: hybrid approach

Elastic Net combines L1 and L2:

python
from sklearn.linear_model import ElasticNet

# l1_ratio = 0.5 means 50% L1, 50% L2
model = ElasticNet(alpha=0.1, l1_ratio=0.5)
model.fit(X, y)

This gives you feature selection (L1) and coefficient shrinkage (L2) at the same time. Tune both alpha and l1_ratio with cross-validation.

Common mistakes

  • Forgetting to scale features before regularization. Regularization penalizes large coefficients uniformly, so unscaled features with large natural ranges will be under-penalized. Always use a pipeline with StandardScaler first.
  • Using raw R² to compare models. R² increases with model complexity, even if new features add no signal. Use cross-validated R² or other metrics like MAE.
  • Ignoring multicollinearity. High correlation between features makes coefficients unstable and interpretation unreliable. Check a correlation matrix before training.
  • Selecting lambda on the test set. Use cross-validation on the training set to select hyperparameters, then evaluate on a held-out test set. Tuning on the test set causes overfitting to the test set itself.
  • Assuming linearity without inspection. Plot predicted versus actual values and residuals versus predictions. If patterns emerge, your model violates the linearity assumption.

Key takeaways

  • Linear regression minimizes squared error and produces interpretable coefficients—a huge advantage in regulated or business-critical systems.
  • Validate the four core assumptions: linearity, error independence, homoscedasticity, and low multicollinearity. Violations don't break the code, but they break the model's trustworthiness.
  • Use Ridge for stable coefficient estimates when you expect all features to matter. Use Lasso for automatic feature selection when most features are noise. Use Elastic Net when you want both.
  • Scale features and tune regularization hyperparameters via cross-validation on the training set alone. Evaluate on a separate test set.
  • Linear models train and predict in milliseconds and require minimal computational resources—a practical win for real-time systems and edge deployments.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles