Unit 5 · Tutorial 04
Fitting the Model
T-02 gave you the model form and T-03 the geometry of its decisions. Neither said where the coefficients come from. This tutorial answers that question: how logistic regression chooses its parameters, why the obvious approach fails, and why the method that works is both elegant and guaranteed to succeed.
01 Learning objectives
By the end of this tutorial you will be able to
- Explain why least squares is not the right criterion for fitting a logistic regression.
- Derive the likelihood and log-likelihood for a binary classification model.
- Write down the log loss (cross-entropy) and explain why it penalises confident mistakes so heavily.
- Compute the gradient of the log-likelihood and explain why it has the form
Xᵀ(y − p). - Explain why there is no closed-form solution, in contrast to ordinary least squares.
- Describe gradient ascent and Newton–Raphson as two ways of finding the maximum, and compare their convergence behaviour.
- Explain why the log-likelihood is concave, and why this guarantees that any local maximum is the global maximum.
Position in the unit
This tutorial supplies the estimation machinery. T-05 develops the interpretation of the fitted coefficients in depth, T-06 examines what happens when the threshold interacts with imbalanced data, and T-07 introduces regularisation as a modification of the criterion developed here. The convexity result in Section 3.9 also underpins the optimisation material in Module 5.
02 Motivating example
In T-02 you were handed a logistic regression with coefficients already attached:
z = −3 + 1.2 × hours
and used it to predict exam pass probabilities. In T-03 you took another set
of coefficients — z = −8 + 0.3x₁ + 0.5x₂ — and derived the
decision boundary. In both cases the coefficients were given.
This tutorial asks the obvious follow-up question: where did those numbers come from?
For linear regression, from Unit 4, the answer was clean. The coefficients are
the values that minimise the sum of squared residuals, and they can be written
down in closed form as β = (XᵀX)⁻¹Xᵀy. Substitute the data,
evaluate a matrix expression, and you have the answer. No iteration, no
tuning, no ambiguity.
It is natural to hope that logistic regression works the same way. Fit a line by least squares, then squash it through the sigmoid — or perhaps minimise the squared error between the predicted probability and the binary label. Either approach seems plausible, and both are wrong.
Two things go wrong. First, least squares is not the right criterion for a binary outcome — it treats a confident mistake and a cautious mistake as equally bad in a way that makes no sense for probabilities. Second, even with the right criterion, there is no closed form. The equations that define the optimal coefficients cannot be solved algebraically; they must be solved numerically, by iteration.
This tutorial works through both issues. You will see what the right criterion is, why it is the right one, what its gradient looks like, why an algebraic solution is impossible, and how the numerical methods that do the job actually work.
The tempting wrong answer
A common instinct is to fit by least squares and then apply the sigmoid to the result. This produces coefficients, a boundary, and probabilities — all of which look plausible. But the probabilities are wrong: they are systematically over-confident or under-confident, and the coefficients are biased. The model will appear to work while quietly misrepresenting its own uncertainty. Section 3.1 explains precisely why.
03 Concept explanation
3.1 Why least squares is the wrong criterion
Suppose we try to fit logistic regression by minimising the sum of squared differences between the predicted probability and the binary label:
J(β) = Σ ( y_i − σ(z_i) )²
This is sometimes called the "squared error" or "Brier score" criterion, and it is not absurd — it is a legitimate way to measure the quality of probabilistic predictions. But it has two problems as a fitting criterion for logistic regression.
It penalises confident mistakes weakly. Consider two predictions for a case whose true label is 1:
- Model A predicts
p = 0.9. Squared error:(1 − 0.9)² = 0.01. - Model B predicts
p = 0.6. Squared error:(1 − 0.6)² = 0.16.
Now consider two confident mistakes:
- Model C predicts
p = 0.1. Squared error:(1 − 0.1)² = 0.81. - Model D predicts
p = 0.01. Squared error:(1 − 0.01)² = 0.98.
The difference between C and D is only 0.17, yet D is ten times more confident in a wrong answer. Squared error grows towards a ceiling of 1 and cannot express the fact that being confidently wrong is qualitatively worse than being cautiously wrong.
It is not the criterion the model assumes. Logistic regression
models the probability that y = 1 as a Bernoulli random variable
with parameter p. The natural way to fit a probabilistic model is
by maximum likelihood, which asks: which parameter values make the
observed data most probable? Minimising squared error is not the same as
maximising likelihood, and the two produce different coefficient estimates.
The principle to remember
In statistical modelling, the criterion for fitting is derived from the probability model, not chosen by convenience. Logistic regression assumes a Bernoulli likelihood, so the fitting criterion is the Bernoulli likelihood. Everything else follows.
3.2 Maximum likelihood
The principle of maximum likelihood is straightforward:
Choose the parameter values that make the observed data most probable under the assumed model.
Applied to logistic regression, this means finding the coefficients
β that maximise the probability of the observed labels
y₁, …, yₙ, given the observed features
x₁, …, xₙ.
The likelihood function L(β) is exactly this probability, viewed
as a function of the parameters. We then find the β that makes
it as large as possible.
3.3 The likelihood for a single observation
For a single case with true label y ∈ {0, 1} and predicted
probability p = σ(z), the probability of observing that label is:
- If
y = 1: the probability isp. - If
y = 0: the probability is1 − p.
These two cases can be written as a single expression:
P(y | x, β) = p^y · (1 − p)^(1−y)
Check the two cases. When y = 1, the expression becomes
p¹ · (1 − p)⁰ = p. When y = 0, it becomes
p⁰ · (1 − p)¹ = 1 − p. This compact form — sometimes called the
Bernoulli likelihood — is worth recognising.
3.4 The log-likelihood and the log loss
Because the observations are assumed independent, the likelihood of the whole dataset is the product of the individual likelihoods:
L(β) = Π p_i^(y_i) · (1 − p_i)^(1−y_i)
Products are awkward to work with, and they underflow quickly on a computer. Taking the logarithm turns the product into a sum without changing the location of the maximum, because the logarithm is strictly increasing. This gives the log-likelihood:
ℓ(β) = Σ [ y_i log(p_i) + (1 − y_i) log(1 − p_i) ]
We maximise ℓ(β). Equivalently, we can minimise its negative:
J(β) = − Σ [ y_i log(p_i) + (1 − y_i) log(1 − p_i) ]
This quantity has several names: the negative log-likelihood,
the log loss, the cross-entropy loss, or
simply the logistic loss. They all refer to the same thing.
Most machine learning libraries, including scikit-learn, minimise a version of
this quantity (usually divided by n to give a mean rather than a
sum).
The log loss behaves very differently from squared error. For a single observation, the contribution is:
- If
y = 1:−log(p). This goes to+∞asp → 0, and to 0 asp → 1. - If
y = 0:−log(1 − p). This goes to+∞asp → 1, and to 0 asp → 0.
A confident mistake — y = 1 with p = 0.001 — incurs
a loss of −log(0.001) ≈ 6.9, and grows without bound as the
prediction becomes more confidently wrong. This is exactly the behaviour
squared error could not express, and it is why the log loss is the right
criterion for probabilistic classifiers.
The cost of over-confidence
The log loss punishes confident mistakes brutally — and that is a feature,
not a bug. A model that claims p = 0.999 and is wrong should
feel the consequences far more than one that claims p = 0.6 and
is wrong. This is what makes the log loss such a useful training signal for
probabilistic models.
3.5 The gradient
To find the maximum of ℓ(β), we need its gradient with respect to
each coefficient. The derivation uses three facts:
- The derivative of the sigmoid is
σ′(z) = σ(z)(1 − σ(z)). - The chain rule applies through
z_i = x_iᵀβ. - For a single observation, the log-likelihood simplifies dramatically.
Working through the calculus for a single observation:
∂ℓ_i/∂β_j = (y_i − p_i) · x_ij
Summing over all observations:
∂ℓ/∂β_j = Σ (y_i − p_i) · x_ij
In matrix form, with X the n × p design matrix,
y the vector of labels, and p the vector of
predicted probabilities:
∇ℓ(β) = Xᵀ (y − p)
This is a remarkably clean result, and it should look familiar. In linear
regression, the gradient of the residual sum of squares is
−2Xᵀ(y − Xβ). The structural form is identical: a matrix transpose
times a vector of residuals. The only difference is that where linear
regression uses the fitted values Xβ, logistic regression uses
the fitted probabilities p = σ(Xβ).
Reading the gradient
Each component of the gradient is a weighted sum of residuals:
Σ(y_i − p_i)x_ij. A positive residual
(y_i > p_i) means the model underestimated this case, and it
contributes positively to the gradient for feature j, pushing
β_j upward. A negative residual pushes it down. At the optimum,
the residuals are balanced — the model neither systematically under- nor
over-estimates any feature.
3.6 Why there is no closed-form solution
Setting the gradient to zero gives the normal equations for logistic regression:
Xᵀ (y − p) = 0
where p = σ(Xβ) depends non-linearly on β. Expanding:
Xᵀ y = Xᵀ p = Xᵀ σ(Xβ)
The left-hand side is a linear function of the data. The right-hand side is a
non-linear function of β, because σ is non-linear.
There is no algebraic rearrangement that isolates β.
This is worth contrasting with ordinary least squares. In linear regression,
the same gradient equation is Xᵀ(y − Xβ) = 0, which rearranges to
XᵀXβ = Xᵀy — a linear system in β, solvable in one
step. The difference is entirely due to the sigmoid: it introduces a
non-linearity that cannot be undone algebraically.
The consequence is that logistic regression coefficients must be found by iterative numerical optimisation. This is not a limitation of the software; it is a mathematical fact about the model.
3.7 Gradient ascent
The simplest way to find the maximum is gradient ascent: start with an initial guess, then repeatedly step in the direction of the gradient, which points uphill.
β ← β + α · ∇ℓ(β)
where α > 0 is the learning rate (or step
size). The algorithm terminates when the gradient is close enough to zero, or
after a fixed number of iterations.
Three practical considerations:
-
Choice of
α. Too small and convergence is glacial; too large and the iteration can oscillate or diverge. There is no universal safe value; it depends on the data. - Scaling. Features on different scales make the problem ill-conditioned, and gradient ascent becomes slow or unstable. Standardising features is almost always necessary in practice.
- Stopping rule. The iteration is usually stopped when the change in the log-likelihood (or the magnitude of the gradient) falls below a tolerance.
Gradient ascent is conceptually simple and easy to implement, but it can be slow. For logistic regression there is a much better method.
3.8 Newton–Raphson and IRLS
Newton's method uses second-order information — the curvature of the function — to take better steps. For maximisation, the update is:
β ← β − H⁻¹ ∇ℓ
where H is the Hessian matrix of second derivatives. For logistic
regression, the Hessian has a clean form:
H = − Xᵀ W X
where W is the diagonal matrix with entries
w_i = p_i(1 − p_i). Substituting into the update:
β ← β + (Xᵀ W X)⁻¹ Xᵀ (y − p)
This is the Newton–Raphson update for logistic regression, and it is also known as iteratively reweighted least squares (IRLS) because each step solves a weighted least squares problem with weights that change from iteration to iteration.
The practical difference from gradient ascent is striking. Newton–Raphson
typically converges in four to eight iterations, regardless of
the number of features, and requires no tuning of a learning rate. The price is
the computation of (XᵀWX)⁻¹, which is an p × p matrix
inversion performed once per iteration. For problems with thousands of features
this becomes expensive, which is why quasi-Newton methods like L-BFGS — which
approximate the Hessian without forming it — are the default in most
libraries.
3.9 Why the maximum is unique: convexity
Both gradient ascent and Newton–Raphson find a maximum. Do they find the maximum — the global one — or could there be multiple peaks, with the algorithm getting stuck in a lesser one?
For logistic regression, the answer is guaranteed. The Hessian is
−XᵀWX, and this matrix is always negative
semi-definite, because:
Wis diagonal with positive entriesp_i(1 − p_i) > 0.- For any vector
v,vᵀ XᵀWX v = (Xv)ᵀW(Xv) = Σ w_i (x_iᵀv)² ≥ 0.
A function whose Hessian is negative semi-definite everywhere is concave. A concave function has a single peak (or a flat plateau), with no local maxima and no saddle points. This means:
- Any local maximum is a global maximum.
- Gradient ascent will converge to the global maximum for a suitably small step size.
- Newton–Raphson, once it takes a step, converges rapidly and reliably.
- Different initialisations lead to the same answer (up to numerical precision).
This is a remarkable property, and it is not shared by all machine learning models. Neural networks, for example, have highly non-convex loss surfaces with many local minima. The convexity of logistic regression is what makes it such a reliable and well-understood model, and it is the reason the fitting procedure can be trusted to find the best answer.
The one exception
Convexity guarantees a unique maximum — provided the maximum exists. For perfectly separable data, the maximum does not exist: the log-likelihood can always be increased by making the coefficients larger, and the true optimum is at infinity. Regularisation (T-07) restores a finite optimum in this case, and is often necessary in practice for exactly this reason.
3.10 Practical notes: fitting in scikit-learn
In practice you will rarely implement the optimiser yourself. The
LogisticRegression class in scikit-learn provides a range of
solvers, and choosing between them is mostly a matter of problem size and
structure.
| Solver | Method | Notes |
|---|---|---|
lbfgs |
Quasi-Newton (L-BFGS) | Default. Fast and robust for most problems. Supports L2 and no penalty. |
newton-cg |
Newton–Raphson (conjugate gradient) | Uses the exact Hessian. Fast for moderate feature counts. |
newton-cholesky |
Newton–Raphson (Cholesky) | Exact Hessian; efficient when n is large and p is moderate. |
liblinear |
Coordinate descent | Good for small datasets. Supports L1 and L2 penalty. |
saga |
Stochastic average gradient | Supports L1, L2 and elasticnet. Good for large sparse problems. |
Two defaults are worth knowing. First, LogisticRegression applies
L2 regularisation by default (with strength controlled by
C = 1.0), so the coefficients are shrunk slightly relative to the
pure maximum-likelihood estimate. To obtain the unregularised MLE, set
penalty=None. Second, features are not scaled
automatically, so if your features differ substantially in magnitude you
should standardise them first — either with StandardScaler or by
using a pipeline.
If you see a ConvergenceWarning, the usual causes are unscaled
features, a small max_iter, or (less commonly) perfectly separable
data. Scaling almost always fixes the first two; the third is addressed by
regularisation.
04 Visual illustration
Two figures make the mathematics concrete. The first shows how the log loss penalises individual predictions; the second shows the shape of the log-likelihood surface for a small dataset.
Figure 1 explains why logistic regression punishes confident mistakes. A
prediction of p = 0.9 when y = 0 incurs a loss of
−log(0.1) ≈ 2.30, while a prediction of
p = 0.99 incurs −log(0.01) ≈ 4.61 — twice as much,
even though the two predictions differ by only 0.09 in probability. The loss
grows without bound as p approaches the wrong extreme.
Figure 2 shows the log-likelihood surface for a small dataset, as a function of a single coefficient. The curve is concave — one smooth peak, no other local maxima — which is the property that guarantees the fitting procedure succeeds.
β₁ with β₀ held at 0.
The curve is smooth and concave, rising from the left, peaking around 0.42,
and falling away on the right. The dashed line shows the log-likelihood at
β₁ = 0: the fit improves on the uninformative model, but only
modestly, because the data contains limited signal.
Two features of Figure 2 are worth noting. The curve is smooth — no kinks, no discontinuities — because both the sigmoid and the logarithm are infinitely differentiable. And it has exactly one peak, which is the convexity result of Section 3.9 made visible. A numerical optimiser started anywhere on this curve will climb to the same maximum.
05 Worked example
We work through a small dataset by hand to make the mechanics concrete. The dataset has four observations and a single feature:
| Observation | x | y |
|---|---|---|
| 1 | −2 | 0 |
| 2 | −1 | 1 |
| 3 | 1 | 0 |
| 4 | 2 | 1 |
The labels alternate with the feature, so the data is not
separable — no threshold on x perfectly separates the
classes. The model is z = β₀ + β₁x, with
p = σ(z).
Step 1 · Evaluate the log-likelihood at the origin
Start with β₀ = 0 and β₁ = 0. Then every score is
zero, so every probability is σ(0) = 0.5.
ℓ(0, 0) = Σ [ y_i log(0.5) + (1 − y_i) log(0.5) ]
= 4 × log(0.5)
= 4 × (−0.6931)
= −2.7726
This is the log-likelihood of a model that knows nothing — it predicts 0.5 for every case. Any useful model must beat this.
Step 2 · Compute the gradient at the origin
Using ∇ℓ = Xᵀ(y − p), with p_i = 0.5 for every
observation:
∂ℓ/∂β₀ = Σ (y_i − p_i)
= (0 − 0.5) + (1 − 0.5) + (0 − 0.5) + (1 − 0.5)
= −0.5 + 0.5 − 0.5 + 0.5
= 0
∂ℓ/∂β₁ = Σ (y_i − p_i) x_i
= (−0.5)(−2) + (0.5)(−1) + (−0.5)(1) + (0.5)(2)
= 1 − 0.5 − 0.5 + 1
= 1.0
The gradient with respect to β₀ is exactly zero, because the
data contains an equal number of positives and negatives. The gradient with
respect to β₁ is positive, indicating that increasing
β₁ will increase the log-likelihood.
This is a general property of this symmetric dataset: because the labels are
balanced and the features are symmetric about zero, the optimal
β₀ is exactly 0, and β₀ remains at 0 throughout
the iteration.
Step 3 · Take a gradient ascent step
With learning rate α = 0.5:
β₀ ← 0 + 0.5 × 0 = 0
β₁ ← 0 + 0.5 × 1 = 0.5
Now compute the fitted probabilities at β₁ = 0.5:
| x | y | z = 0.5x | p = σ(z) |
|---|---|---|---|
| −2 | 0 | −1.0 | 0.2689 |
| −1 | 1 | −0.5 | 0.3775 |
| 1 | 0 | 0.5 | 0.6225 |
| 2 | 1 | 1.0 | 0.7311 |
The gradient at this point:
∂ℓ/∂β₁ = (−0.2689)(−2) + (1 − 0.3775)(−1)
+ (−0.6225)(1) + (1 − 0.7311)(2)
= 0.5378 − 0.6225 − 0.6225 + 0.5378
= −0.1694
The gradient has changed sign: we have overshot. The next step corrects:
β₁ ← 0.5 + 0.5 × (−0.1694) = 0.4153
Step 4 · Converge
Repeating the update a few more times:
| Iteration | β₁ | ∂ℓ/∂β₁ | ℓ(β) |
|---|---|---|---|
| 0 | 0.0000 | +1.0000 | −2.7726 |
| 1 | 0.5000 | −0.1694 | −2.5748 |
| 2 | 0.4153 | +0.0092 | −2.5680 |
| 3 | 0.4199 | −0.0005 | −2.5679 |
The iteration converges to β₁ ≈ 0.42 after only three steps.
This is unusually fast for gradient ascent — the choice
α = 0.5 happens to be well matched to the curvature of this
particular problem. In general, gradient ascent requires more iterations
and a more careful choice of step size.
Step 5 · Compare with Newton–Raphson
Newton–Raphson uses the second derivative as well as the first. At
β₁ = 0, with p_i = 0.5 everywhere, the weights are
w_i = p_i(1 − p_i) = 0.25. The Hessian entry for β₁
is:
H₁₁ = − Σ w_i x_i²
= − 0.25 × ((−2)² + (−1)² + 1² + 2²)
= − 0.25 × 10
= −2.5
The Newton–Raphson update at β₁ = 0 is:
β₁ ← 0 − (1.0) / (−2.5) = 0.4
In a single step, Newton–Raphson lands at β₁ = 0.4, very close
to the optimum of 0.42. A second iteration refines this to
0.4197, and a third brings it to machine precision. This is the
power of using curvature information: one well-chosen step replaces many
small ones.
What the example shows
The log-likelihood improved from −2.7726 to
−2.5679 — a modest improvement, because the alternating labels
contain little signal about x. The model has learned something,
but not much. This is an honest reflection of the data: a model cannot
extract signal that is not there.
06 Interactive activity
Activity · Fit logistic regression from scratch
In this activity you will implement logistic regression fitting yourself, using both gradient ascent and a library optimiser. Comparing the two implementations builds intuition for what the library is doing under the hood.
-
Write a function
sigmoid(z)that returns1 / (1 + exp(−z)), using a numerically stable form for large negativez. -
Write a function
log_likelihood(X, y, beta)that computesΣ [y log p + (1−y) log(1−p)]. -
Write a function
gradient(X, y, beta)that returnsXᵀ(y − p). -
Implement gradient ascent with a loop. Try learning rates
0.001, 0.01, 0.1, 1.0and record how many iterations each takes to converge on a standard dataset. -
Now compare with
scipy.optimize.minimizeusingmethod='BFGS'and the negative log-likelihood. How many function evaluations does it use? -
Finally, fit with
sklearn.linear_model.LogisticRegression. Do the coefficients match your implementation? (Remember to handle regularisation.)
import numpy as np
def sigmoid(z):
# numerically stable for large |z|
return np.where(z >= 0,
1 / (1 + np.exp(-z)),
np.exp(z) / (1 + np.exp(z)))
def log_likelihood(X, y, beta):
p = sigmoid(X @ beta)
# clip to avoid log(0)
p = np.clip(p, 1e-12, 1 - 1e-12)
return np.sum(y * np.log(p) + (1 - y) * np.log(1 - p))
def gradient(X, y, beta):
p = sigmoid(X @ beta)
return X.T @ (y - p)
# Gradient ascent
def fit_gradient_ascent(X, y, alpha=0.1, n_iter=5000, tol=1e-8):
beta = np.zeros(X.shape[1])
ll_history = [log_likelihood(X, y, beta)]
for _ in range(n_iter):
beta = beta + alpha * gradient(X, y, beta)
ll = log_likelihood(X, y, beta)
ll_history.append(ll)
if abs(ll_history[-1] - ll_history[-2]) < tol:
break
return beta, ll_history
# Compare with scipy
from scipy.optimize import minimize
def neg_ll(beta, X, y):
return -log_likelihood(X, y, beta)
def neg_grad(beta, X, y):
return -gradient(X, y, beta)
result = minimize(neg_ll, np.zeros(X.shape[1]), args=(X, y),
jac=neg_grad, method='BFGS')
beta_scipy = result.x
Three things to notice as you run this. First, gradient ascent with a fixed
learning rate is sensitive to the choice of α; the same value
that converges quickly on one dataset may oscillate or crawl on another.
Second, scipy's BFGS reaches the same answer in far fewer
iterations, because it approximates the curvature of the loss surface. Third,
the coefficients from your implementation and from scikit-learn will match
closely only if you remember to disable regularisation — by default,
scikit-learn shrinks the coefficients.
07 Self-check questions
Answer each question before revealing the solution.
Question 1
Why is squared error a poor criterion for fitting logistic regression?
Show answer
Two reasons. First, squared error does not adequately penalise
confident mistakes: a prediction of p = 0.01 when
y = 1 incurs a loss of 0.98, not much more than a
prediction of p = 0.1 at 0.81 — yet the first is ten
times more confident and more wrong. Second, it does not correspond
to the likelihood of the assumed probability model. Logistic
regression assumes a Bernoulli likelihood, and maximum likelihood is
the principled criterion for fitting a probabilistic model.
Question 2
Write down the log-likelihood for a logistic regression model with
n observations.
Show answer
ℓ(β) = Σᵢ [ yᵢ log(pᵢ) + (1 − yᵢ) log(1 − pᵢ) ],
where pᵢ = σ(xᵢᵀβ).
Equivalently, the log loss to be minimised is the negative of this
expression: J(β) = −ℓ(β).
Question 3
What is the gradient of the log-likelihood with respect to β?
Why does this make intuitive sense?
Show answer
∇ℓ(β) = Xᵀ(y − p), where p = σ(Xβ).
Intuitively, each component is a weighted sum of residuals
yᵢ − pᵢ. A positive residual means the model
underestimated that case, and the gradient pushes the corresponding
coefficients in the direction that would increase pᵢ.
At the optimum, the residuals balance out and the gradient is zero.
Question 4
Why is there no closed-form solution for the logistic regression coefficients?
Show answer
Setting the gradient to zero gives Xᵀ(y − p) = 0, or
equivalently Xᵀy = Xᵀσ(Xβ). Because the sigmoid is a
non-linear function of β, the right-hand side cannot be
rearranged into a linear system in β. In linear
regression, by contrast, the fitted values are Xβ, which
is linear, and the normal equations can be solved algebraically.
Question 5
What does it mean that the log-likelihood is concave, and why does this matter for fitting?
Show answer
A concave function has a single peak — no local maxima, no saddle points. For logistic regression, this follows from the Hessian being negative semi-definite everywhere.
Practically, it means any optimisation method that climbs uphill will reach the global maximum. There is no risk of getting stuck in a worse local optimum, no dependence on initialisation, and no need for multiple restarts. This is what makes logistic regression a reliable model in practice.
Question 6
Why does scikit-learn's LogisticRegression apply
regularisation by default, and how do you turn it off?
Show answer
Regularisation is applied by default because it stabilises the fit in cases where the unregularised maximum-likelihood estimate is unstable or does not exist — in particular, when the data is perfectly separable, in which case the MLE diverges.
To obtain the unregularised MLE, set penalty=None in the
constructor. This is useful for pedagogical comparisons but is rarely
advisable in practice, since some regularisation almost always
improves generalisation.
08 Practice exercises
Work these by hand where possible, then verify computationally.
-
For the worked example dataset, compute the log-likelihood at
β₀ = 0, β₁ = 0.4and atβ₀ = 0, β₁ = 0.5. Which is higher? Does this match Figure 2? -
Compute the gradient
∂ℓ/∂β₁atβ₁ = 0.4for the worked example. Is it positive or negative? What does the sign tell you about whether to increase or decreaseβ₁? -
A single observation has
y = 1andp = 0.2. What is the log loss? What would it be ifp = 0.9? -
Compute the Hessian entry
H₁₁for the worked example atβ₁ = 0.4. Is it negative? What does this confirm? -
Starting from
β₁ = 0.4, take one Newton–Raphson step using the Hessian from exercise 4. How close does this get to the optimum of 0.42? - A logistic regression is fitted to a dataset with 200 observations and 3 features. What is the dimension of the Hessian matrix? How many entries does it have?
-
Show algebraically that
σ′(z) = σ(z)(1 − σ(z)). This is the fact used in deriving the Hessian. - Consider a dataset where every label is 1. What is the maximum-likelihood estimate of the intercept for an intercept-only model? What happens to the coefficients on the features?
09 Problem sets
These problems require reasoning about the fitting procedure rather than calculation.
Problem 1 · Why maximum likelihood?
A colleague proposes fitting logistic regression by minimising the mean
absolute difference Σ|yᵢ − pᵢ| between predicted probabilities
and binary labels. Discuss the merits and drawbacks of this criterion
compared with maximum likelihood. Would it produce the same coefficients?
Would it be easier or harder to optimise?
Problem 2 · Perfect separation
Consider a one-feature dataset with four observations:
(1, 0), (2, 0), (3, 1), (4, 1). Show that the data is
perfectly separable by a threshold at x = 2.5. Then show that
the log-likelihood increases as β₁ → ∞, so that no finite
maximum exists. What does this imply about the coefficients that a fitting
procedure would produce? How does regularisation change the situation?
Problem 3 · Gradient ascent vs. Newton–Raphson
In general, gradient ascent requires many iterations and a well-chosen learning rate, while Newton–Raphson converges in a handful of steps. Explain why. What is the computational cost per iteration of each method? Under what circumstances would gradient ascent be preferable despite the extra iterations?
Problem 4 · Feature scaling and convergence
Suppose one feature is measured in metres and another in millimetres, so that values of the second feature are a thousand times larger than the first. How does this affect the shape of the log-likelihood surface? What does it do to the convergence of gradient ascent? Why does Newton–Raphson suffer less from this problem?
Problem 5 · The intercept and the base rate
Show that for an intercept-only logistic regression (no features), the
maximum-likelihood estimate of the intercept is
β₀ = logit(ȳ), where ȳ is the proportion of
positives in the data. What does this tell you about what the intercept
represents in a model with features?
Problem 6 · Hessian at the boundary
The Hessian −XᵀWX depends on W, whose diagonal
entries are pᵢ(1 − pᵢ). As the model becomes more confident —
pᵢ close to 0 or 1 — these weights approach zero, and the
Hessian approaches the zero matrix. What does this imply about the shape of
the log-likelihood surface far from the optimum? Why does this matter for
Newton–Raphson?
10 Discussion and projects
Discussion questions
- Maximum likelihood is a general principle, not specific to logistic regression. What other models have you met that can be fitted by maximum likelihood? What is the same and what is different?
- The convexity of the log-likelihood means logistic regression has a unique best answer. Does this make it a "better" model than one with a non-convex loss surface, such as a neural network? Or does it make it a more limited one?
- The log loss penalises confident mistakes without bound. Is this always the right behaviour? Can you think of a context in which penalising confidence too harshly would be undesirable?
- In practice, almost nobody uses unregularised logistic regression. Given that the maximum-likelihood estimate is theoretically optimal (in the sense of asymptotic efficiency), why is the regularised version preferred?
Mini-project · Implement and compare optimisers
In this project you will implement three different ways of fitting logistic regression and compare them empirically. The goal is not to build a production tool but to understand what the library does on your behalf.
Write the log-likelihood and its gradient, then iterate with a fixed step size.
Use the exact Hessian and the update β ← β + (XᵀWX)⁻¹Xᵀ(y − p).
Minimise the negative log-likelihood with the BFGS method.
Use LogisticRegression(penalty=None) and compare the coefficients.
Plot the log-likelihood against iteration number for each method on the same axes.
Repeat the experiment with features on wildly different scales. Which methods are affected?
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.preprocessing import StandardScaler
# Generate and scale data
X, y = make_classification(n_samples=400, n_features=4, n_informative=3,
n_redundant=0, random_state=0)
X = StandardScaler().fit_transform(X)
X = np.hstack([np.ones((X.shape[0], 1)), X]) # add intercept column
def sigmoid(z):
return np.where(z >= 0,
1 / (1 + np.exp(-z)),
np.exp(z) / (1 + np.exp(z)))
def log_likelihood(beta, X, y):
p = np.clip(sigmoid(X @ beta), 1e-12, 1 - 1e-12)
return np.sum(y * np.log(p) + (1 - y) * np.log(1 - p))
def gradient(beta, X, y):
return X.T @ (y - sigmoid(X @ beta))
def hessian(beta, X, y):
p = sigmoid(X @ beta)
W = np.diag(p * (1 - p))
return -X.T @ W @ X
# Gradient ascent
def gradient_ascent(X, y, alpha=0.1, n_iter=500):
beta = np.zeros(X.shape[1])
history = [log_likelihood(beta, X, y)]
for _ in range(n_iter):
beta = beta + alpha * gradient(beta, X, y)
history.append(log_likelihood(beta, X, y))
return beta, history
# Newton-Raphson
def newton_raphson(X, y, n_iter=20):
beta = np.zeros(X.shape[1])
history = [log_likelihood(beta, X, y)]
for _ in range(n_iter):
g = gradient(beta, X, y)
H = hessian(beta, X, y)
beta = beta - np.linalg.solve(H, g)
history.append(log_likelihood(beta, X, y))
return beta, history
beta_ga, history_ga = gradient_ascent(X, y)
beta_nr, history_nr = newton_raphson(X, y)
fig, ax = plt.subplots(figsize=(8, 4.8))
ax.plot(history_ga, label="gradient ascent", linewidth=2)
ax.plot(history_nr, label="Newton-Raphson", linewidth=2)
ax.set_xlabel("iteration")
ax.set_ylabel("log-likelihood")
ax.set_title("Convergence comparison")
ax.legend()
ax.grid(alpha=0.25)
plt.tight_layout()
plt.show()
The plot will show the characteristic difference: gradient ascent climbs steadily but slowly, while Newton–Raphson jumps almost to the maximum in a handful of iterations. Both converge to the same coefficients — which is the convexity guarantee in action — but the paths they take are very different.
11 Summary
This tutorial answered the question of where the coefficients come from.
- Least squares is the wrong criterion. It under-penalises confident mistakes and does not correspond to the Bernoulli probability model assumed by logistic regression.
- Maximum likelihood is the right criterion. Choose the coefficients that make the observed labels most probable under the model.
-
The likelihood for a binary observation is
p^y (1 − p)^(1−y). Taking logs turns the product over observations into a sum, giving the log-likelihood. - The negative log-likelihood is the log loss. It penalises confident mistakes without bound, which is exactly the behaviour a loss function for probabilities should have.
-
The gradient is
Xᵀ(y − p). Each component is a weighted sum of residuals — the same structural form as in linear regression, with fitted probabilities replacing fitted values. -
There is no closed-form solution. The normal equations are
non-linear in
βbecause of the sigmoid, so the coefficients must be found iteratively. - Gradient ascent works but is slow. It requires a suitable learning rate, and its speed depends on the scaling of the features.
-
Newton–Raphson is much faster. Using the exact Hessian
−XᵀWX, it converges in a handful of iterations and needs no learning rate. - The log-likelihood is concave. The Hessian is negative semi-definite everywhere, so any local maximum is the global maximum, and the fitted coefficients are unique.
- scikit-learn handles all of this. It provides several solvers, applies L2 regularisation by default, and does not scale your features for you.
Before moving to T-05
You should be able to write down the log-likelihood and its gradient from memory, explain in one sentence why there is no closed form, and state why the concavity of the log-likelihood matters. You should also be able to fit a logistic regression in scikit-learn and explain what the default regularisation is doing.
12 Further reading
Core
- James, Witten, Hastie & Tibshirani — An Introduction to Statistical Learning, Section 4.3. Covers logistic regression and maximum likelihood estimation, with derivations of the log-likelihood and its properties.
- Hastie, Tibshirani & Friedman — The Elements of Statistical Learning, Section 4.4. A more rigorous treatment including the Newton–Raphson algorithm, IRLS, and the connection to generalised linear models.
- scikit-learn documentation — LogisticRegression. Read the "solvers" section for the practical trade-offs between L-BFGS, Newton methods, coordinate descent and stochastic gradient methods.
Supplementary
- Bishop — Pattern Recognition and Machine Learning, Section 4.3. Develops logistic regression within a probabilistic framework, with a careful derivation of the log-likelihood and the IRLS algorithm.
- Murphy — Probabilistic Machine Learning: An Introduction, Chapter 8. A modern treatment with clear discussion of both the mathematical foundations and the practical optimisation issues.
- McCullagh & Nelder — Generalized Linear Models. The classic reference. Logistic regression is a special case of a GLM with a binomial response and a logit link, and this book develops the general theory that unifies it with linear regression and other models.
On optimisation
- Boyd & Vandenberghe — Convex Optimization. The standard reference for the convexity arguments used in Section 3.9. Chapters 2–4 establish the properties of convex and concave functions and their implications for optimisation.
- Nocedal & Wright — Numerical Optimization. A comprehensive treatment of gradient methods, Newton methods, and quasi-Newton methods such as BFGS and L-BFGS.
- King & Zeng — "Logistic Regression in Rare Events Data" (2001). A well-known paper on the practical difficulties of fitting logistic regression when the positive class is rare — a preview of the material in T-06.