Generalized Additive Models › Example

Michael BrenndoerferOctober 25, 20265 min read
Machine Learning from ScratchAll chapters
Part 5 of 15Linear and Generalized Linear Models
Chapter 39Generalized Additive Models › Example
Reading section 6 of 10 · Example · 5 minSection 6 of 10 · 5 min

Section 6 of 10 · 5 min read

Generalized Additive Models › ExampleSection view · Sections in this chapter6 / 10 ↓
Reading tools Definitions, links & notes

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Notes & comments

The formula above is compact, but the algebra inside the penalized solve deserves to be seen once by hand. We now work through a tiny example where every matrix can be written out in full, using a deliberately small basis so the arithmetic stays readable. The lesson generalizes directly to cubic B-splines with many more knots; only the numbers change.

Suppose we have three points x=(0.1,0.5,0.9)x = (0.1, 0.5, 0.9) and responses y=(1.2,2.0,1.5)y = (1.2, 2.0, 1.5). On the domain 0≤x≤10 \le x \le 1, place knots at 00, 0.50.5, and 1.01.0, giving three linear hat functions:

h1(x)=max⁡(0,1−2x),h2(x)=1−∣2x−1∣,h3(x)=max⁡(0,2x−1).h_1(x) = \max(0, 1 - 2x), \quad h_2(x) = 1 - |2x - 1|, \quad h_3(x) = \max(0, 2x - 1).

Evaluating these at our three xx values gives the 3×33 \times 3 basis matrix

B0=(0.80.2001.0000.20.8).\mathbf{B}_0 = \begin{pmatrix} 0.8 & 0.2 & 0 \\ 0 & 1.0 & 0 \\ 0 & 0.2 & 0.8 \end{pmatrix}.

We will add an intercept column 1\mathbf{1} as the first column, so the full design becomes

B=(10.80.20101.00100.20.8).\mathbf{B} = \begin{pmatrix} 1 & 0.8 & 0.2 & 0 \\ 1 & 0 & 1.0 & 0 \\ 1 & 0 & 0.2 & 0.8 \end{pmatrix}.

The coefficient vector is β=(β0,β1,β2,β3)⊤\boldsymbol\beta = (\beta_0, \beta_1, \beta_2, \beta_3)^\top with β0\beta_0 the intercept and (β1,β2,β3)(\beta_1, \beta_2, \beta_3) giving the smooth.

The unpenalized normal-equation quantities are

B⊤B=(30.81.40.80.80.640.1601.40.161.080.160.800.160.64),B⊤y=(4.70.962.541.20).\mathbf{B}^\top \mathbf{B} = \begin{pmatrix} 3 & 0.8 & 1.4 & 0.8 \\ 0.8 & 0.64 & 0.16 & 0 \\ 1.4 & 0.16 & 1.08 & 0.16 \\ 0.8 & 0 & 0.16 & 0.64 \end{pmatrix}, \qquad \mathbf{B}^\top \mathbf{y} = \begin{pmatrix} 4.7 \\ 0.96 \\ 2.54 \\ 1.20 \end{pmatrix}.

These come from the same rules as OLS: each entry of B⊤B\mathbf{B}^\top \mathbf{B} is a dot product of two columns of B\mathbf{B}, and each entry of B⊤y\mathbf{B}^\top \mathbf{y} is a dot product of a column of B\mathbf{B} with the response. If we stopped here we would just be doing OLS on the basis expansion, flexible in principle, but with no safeguard against a wiggly fit. The penalty is what adds that safeguard.

The penalty comes next. Our smooth has three coefficients, so the second-difference matrix D\mathbf{D} has 3−2=13 - 2 = 1 row, D=(1,−2,1)\mathbf{D} = (1, -2, 1). The full penalty matrix has a zero row and column for the intercept (the intercept is not penalized) and D⊤D\mathbf{D}^\top \mathbf{D} in the smooth block:

P=(000001−210−24−201−21).\mathbf{P} = \begin{pmatrix} 0 & 0 & 0 & 0 \\ 0 & 1 & -2 & 1 \\ 0 & -2 & 4 & -2 \\ 0 & 1 & -2 & 1 \end{pmatrix}.

Take λ=0.1\lambda = 0.1. The penalized system is

(B⊤B+λP)β=B⊤y,\left( \mathbf{B}^\top \mathbf{B} + \lambda \mathbf{P} \right) \boldsymbol\beta = \mathbf{B}^\top \mathbf{y},

with

B⊤B+λP=(30.81.40.80.80.74−0.040.11.4−0.041.48−0.040.80.1−0.040.74).\mathbf{B}^\top \mathbf{B} + \lambda \mathbf{P} = \begin{pmatrix} 3 & 0.8 & 1.4 & 0.8 \\ 0.8 & 0.74 & -0.04 & 0.1 \\ 1.4 & -0.04 & 1.48 & -0.04 \\ 0.8 & 0.1 & -0.04 & 0.74 \end{pmatrix}.

Now compare the matrix above with the unpenalized B⊤B\mathbf{B}^\top \mathbf{B}. The off-diagonal entries (the −0.04-0.04 and 0.10.1 entries) are the change produced by the penalty. Those couplings come from second coefficient differences; they are the mechanism by which curvature is made expensive.

The displayed four-parameter system is still singular: the three hat functions sum to one, so their constant direction duplicates the intercept. Complete the fit by requiring the smooth to sum to zero at the three observations. Its constraint row is c⊤=(0,0.8,1.4,0.8)\mathbf{c}^{\top}=(0,0.8,1.4,0.8). We solve the normal equations and that constraint together, using a Lagrange multiplier (an extra unknown that enforces the constraint).

PythonIn [11]
CollapseExpand
toy_B = np.array(
    [[1.0, 0.8, 0.2, 0.0], [1.0, 0.0, 1.0, 0.0], [1.0, 0.0, 0.2, 0.8]]
)
toy_y = np.array([1.2, 2.0, 1.5])
toy_d = np.array([[0.0, 1.0, -2.0, 1.0]])
toy_P = toy_d.T @ toy_d
toy_A = toy_B.T @ toy_B + 0.1 * toy_P
toy_c = np.array([0.0, 0.8, 1.4, 0.8])
toy_system = np.block(
    [[toy_A, toy_c[:, None]], [toy_c[None, :], np.zeros((1, 1))]]
)
toy_beta = np.linalg.solve(toy_system, np.r_[toy_B.T @ toy_y, 0.0])[:4]
toy_predictions = toy_B @ toy_beta
assert np.allclose(toy_c @ toy_beta, 0.0)
ConsoleOut [12]
CollapseExpand
Constrained coefficients: [ 1.5667 -0.3832  0.2237 -0.0082]
Fitted responses: [1.3048 1.7903 1.6048]
Squared error: 0.065947

The intercept is the sample response mean because the fitted smooth is centered. The fitted responses no longer interpolate all observations at this positive penalty.

If we now think about the extreme choices:

  • With λ=0\lambda = 0 we recover the unpenalized fit, which on these three points fits every observation exactly (because the 3×43 \times 4 design, once the smooth is constrained by identifiability, leaves enough freedom to interpolate all three points), including any noise.
  • With λ→∞\lambda \to \infty the penalty forces β1−2β2+β3=0\beta_1 - 2\beta_2 + \beta_3 = 0, meaning the fitted curve is exactly a straight line (a linear trend in the hat basis).
  • For intermediate λ\lambda (here 0.10.1) the fit is a compromise that follows the data closely without allowing spurious curvature.

Both fits use a quadratic penalty, but a difference penalty couples neighboring coefficients, whereas ordinary ridge penalizes coefficient magnitudes. Their common normal-equation structure explains the connection. The next chapter Ridge Regularization (L2 Regularization) develops the ridge view of the penalty in more depth.

The worked example shows the arithmetic. The more important question is whether we can recover the sinusoid and the quadratic from the earlier synthetic data. That is what we implement next.

Comments

Add to the conversation

A question, a correction, or an example from your own work.

No comments yet. Be the first to share your thoughts!

Newsletter

Stay up to date

Get new articles, book updates, and notes on AI and technology.

Unsubscribe at any time. Privacy policy