InterviewPrepKit

Home / Coding / Machine Learning Coding / Linear Models / Linear Regression (Gradient Descent)

Linear Regression (Gradient Descent)

medium 00:00
Solving tips
  • Prepend a column of ones to X so the bias becomes just another weight; then a single X @ w handles predictions and a single X.T @ residual handles the whole gradient.
  • The MSE gradient is (2/n) * X.T @ (X @ w - y). Get the shapes right: X is (n, d+1), w is (d+1,), residual is (n,), and the gradient is (d+1,).
  • One learning-rate times the gradient, subtracted from w, per iteration. If the loss diverges to nan, the learning rate is too large for the scale of the features.

Fit an ordinary least squares linear regression from scratch using batch gradient descent. Rather than solving the normal equations in closed form, you iteratively step the weights downhill along the gradient of the mean squared error. Interviewers use this to check that you can derive the MSE gradient, wire in a bias term correctly, and keep the matrix shapes straight in vectorized NumPy.

Definition

The model predicts y_hat = X_b @ w, where X_b is X with a leading column of ones so that w[0] acts as the bias. The mean squared error and its gradient are:

loss(w)  = (1/n) * sum((X_b @ w - y) ** 2)
grad(w)  = (2/n) * X_b.T @ (X_b @ w - y)

Each gradient-descent step moves the weights against the gradient:

w <- w - lr * grad(w)

Repeat this n_iters times starting from w = 0.

Task

Complete linear_regression_gd(X, y, lr, n_iters) so it returns the learned weight vector of length d + 1, where index 0 is the bias and indices 1..d are the feature coefficients. Prepend the bias column yourself, initialize w to zeros, and run exactly n_iters full-batch updates using the MSE gradient above. Do not call sklearn, scipy, or a closed-form np.linalg solver.

Example

rng = np.random.default_rng(0)
X = rng.normal(size=(200, 1))
y = 3.0 * X[:, 0] + 2.0 + rng.normal(scale=0.1, size=200)  # true bias 2, slope 3

w = linear_regression_gd(X, y, lr=0.1, n_iters=2000)
w            # -> array([~2.0, ~3.0])   (bias first, then slope)
round(w[0], 1), round(w[1], 1)  # -> (2.0, 3.0)

The recovered weights converge to the true bias 2.0 and slope 3.0 that generated the data.

Constraints

  • 1 <= n <= 10^5, 1 <= d <= 100; use vectorized NumPy, not Python loops over rows.
  • The only loop is over n_iters gradient steps.
  • lr is small enough that the loss converges (does not diverge to inf/nan) for reasonably scaled features.
  • Values fit in float64.

Write your solution, then hit Run tests to check it — or get a mock grade from the AI coach.

The coach remembers this session — revise your code and ask again, and it grades your progress. It gives hints, not the answer.
Report a bug