library(tidyverse)library(patchwork) # side-by-side ggplotslibrary(Matrix) # the sparse browsing matrix of lecture 12library(glmnet) # the lasso, for the comparison in section 5
kmeans() and prcomp() are in base R; no package is needed for the methods themselves.
File
Role
data/protein.csv
Protein consumption of 25 European countries in nine food groups
Regularization found a low-dimensional regression function inside a high-dimensional X.
A clear objective: predict Y_{n+1} from X_{n+1}, judged out of sample.
Unsupervised learning, today
Data X_i only, usually high-dimensional.
Posit a simpler structure that generates X and learn that structure.
The goal is to simplify X for its own sake, or to feed the simplified X into a later prediction.
Two methods: K-means clustering groups the observations; principal component analysis finds the few directions along which they vary.
What is it used for
Seeing the data. Twenty-five countries in nine food groups cannot be plotted; two principal components can.
Grouping. Cluster shoppers by purchases, voters by their issues, Spotify users by taste. Clustering can be exploratory, like a histogram, or operational: a recommendation engine recommends what similar users watched.
Few labels, many observations. Thousands of tweets, a few hand-labelled for sentiment: cluster the tweets by topic, then let the labelled tweets in each topic predict the rest.
Preprocessing for prediction. Replace a thousand correlated regressors by a handful of factors, then run a regression. That is section 5.
The directions \varphi_k and each observation’s scores Z_{ik}
Method
K-means
Principal component analysis
Picture
K clouds of points
A K-dimensional plane through the cloud
In both, X is d-dimensional and the hidden variable has K \ll d pieces. A discrete hidden variable gives clusters; a continuous one gives a plane.
A word of caution
Warning
With supervised learning, a story about X that did not help predict Y out of sample was dropped. With unsupervised learning, there is no Y_{n+1} to check against, so it is easy to “discover” structure that is not there.
A multimodal histogram may be one distribution, not a mixture of several.
A cluster can be an artifact of the scale of the variables, the number K we chose, or the random start.
A principal component picks up the largest source of variation, whatever it is. In section 4 that turns out to be attendance.
The discipline has to come from us: replicate across starts, check the scale, interpret with care.
K-means clustering
The mixture model
Model the distribution f of the data X as a weighted sum of K distributions,
f_1, \dots, f_K are the mixture components; \pi_1, \dots, \pi_K the mixture weights.
The same model with a hidden variable. Let U_k \sim f_k for k = 1, \dots, K. To draw X:
draw a type C with \Pr(C = k) = \pi_k;
set X = U_C.
Only X is observed. The type C is latent, and recovering it is the clustering problem.
Example: types of shoppers
X_i is a vector of one shopper’s purchases on Amazon in a month, one component per item.
Suppose there are K latent types: a new parent who buys baby items, someone who buys mainly electronics, and so on.
The component f_k describes the purchases of type k across all items.
The weight \pi_k is the share of shoppers who are type k.
The analyst never sees the types. From a large dataset of purchases, K-means tries to recover them: which shoppers are of the same type, and what does each type buy?
What a mixture looks like in one dimension
Left: the density of X. Right: the four normal components, each scaled by its weight, that add up to it.
The weights here are 0.10, 0.45, 0.40 and 0.05. The two middle components overlap, so an X near 22 could have come from either.
From mixtures to K-means
The picture on the left could also be a single distribution with four modes. To estimate a mixture we must say more about the components.
The usual assumption is normality, U_k \sim N(\mu_k, \sigma_k^2): the Gaussian mixture model, estimated by maximum likelihood with the EM algorithm, because the likelihood is not concave.
K-means is the simpler method we cover. It keeps the latent-type structure and drops the likelihood:
each type is summarized by its centre\mu_k;
each observation belongs to the type whose centre is closest.
Formally, K-means is the Gaussian mixture in the limit \sigma_k^2 \to 0 for every k (Hastie, Tibshirani and Friedman, section 14.3.7; the appendix sketches why).
The K-means algorithm
Given data X_1, \dots, X_n with X_i = (X_{i1}, \dots, X_{id})' and a number of groups K:
Centres. For each group, the average of its members, \hat\mu_k = \frac{\sum_{i=1}^n X_i\, \mathbf{1}\{\hat C_i = k\}}{\sum_{i=1}^n \mathbf{1}\{\hat C_i = k\}}.
Reassign. Move each observation to the group whose centre is nearest, \hat C_i = \arg\min_k \sum_{j=1}^d (X_{ij} - \hat\mu_{kj})^2.
Repeat steps 2 and 3 until no membership changes.
The algorithm in eight lines
set.seed(2) # three clouds of 50 pointsX <-matrix(c(-2, 0, 2, 1.5, -2, 0.5), ncol =2)[rep(1:3, each =50), ] +matrix(rnorm(300, sd =0.8), ncol =2)K <-3set.seed(12); C <-sample(1:K, nrow(X), replace =TRUE) # step 1: random labelsrepeat { mu <-t(sapply(1:K, function(k) colMeans(X[C == k, , drop =FALSE]))) # step 2: centres d2 <-sapply(1:K, function(k) colSums((t(X) - mu[k, ])^2)) # squared distances C_new <-apply(d2, 1, which.min) # step 3: reassignif (all(C_new == C)) break# step 4: until stable C <- C_new}c(within_SS =sum(d2[cbind(1:nrow(X), C)]), kmeans =kmeans(X, centers =3, nstart =10)$tot.withinss)
## within_SS kmeans
## 206.3774 206.3774
The hand-written loop and kmeans() reach the same partition and the same within-cluster sum of squares.
Watching it converge
Random labels put all three centres in the middle of the data. One pass pulls them apart; a few more passes settle the boundary points.
Crosses mark the centres \hat\mu_k at the start of each iteration.
What K-means minimizes
Steps 2 and 3 are coordinate descent on the within-cluster sum of squares,
Cluster 1: the Balkans, Hungary and the USSR; cereals and nuts.
Cluster 2: Western, Northern and Central Europe; meat, eggs and milk.
Cluster 3: Greece, Italy, Portugal and Spain; fish, fruit and vegetables. The three centres account for 51 percent of the total sum of squares.
The clusters on a map of two food groups
Two of the nine dimensions, chosen for the plot; the clusters were found in all nine. The Western cluster spans the whole range of white meat, so this pair of axes does not separate it from the others on its own.
Different starts, different answers
Twenty runs from a single random start each, same data, same K = 3:
Only 8 of the 20 runs find the partition with W = 106.0; the others stop at local minima up to 15 percent worse.
Always set nstart, ten or more, and keep the run with the smallest W. kmeans() does this for you.
kmeans() also refines steps 2 and 3: Hartigan and Wong’s algorithm checks whether moving any single observation lowers W, which escapes some local minima that plain reassignment cannot.
A finer subdivision of the three blocks, and the subdivisions are familiar: Scandinavia, the British Isles with France, Belgium and Switzerland, the German-speaking centre, the Iberian peninsula, and so on.
Seven clusters, two views
Same clusters, two pairs of axes. Red meat against fish separates the Iberian pair and the Scandinavians, which the white meat axis hid.
No two-dimensional plot shows a nine-dimensional partition faithfully. Section 3 builds a better pair of axes.
Choosing K
W always falls with K and reaches zero at K = n, so it cannot choose K. Practitioners look for an “elbow”; there is none here.
With supervised learning, cross-validation chose the complexity. Here there is no out-of-sample prediction to check, so the choice of K is a matter of interpretation: what counts as a diet? Movie genres, or sub-genres?
Checkpoint: K-means
The algorithm is run twice with different random starts and returns different partitions. Which one should you report, and how would you know?
Why does kmeans() on unscaled protein data put almost all the weight on cereals and milk?
A friend runs K-means with K = 25 on the 25 countries and reports W = 0. What went wrong?
Principal component analysis
The linear factor model
K-means put a d-dimensional X_i into one of K boxes. A linear factor model instead writes it as a combination of K unobserved numbers:
Z_{ik} is a scalar factor (or score): how much of pattern k observation i has.
\varphi_k is a d-vector of factor loadings: what pattern k looks like across the d variables.
It looks like a regression of X_i on Z_i, but
the outcome X_i is d-dimensional, not a scalar Y_i;
the “regressors” Z_{i1}, \dots, Z_{iK} are unobserved. We estimate both the regressors and the coefficients.
The PCA objective
Both Z and \varphi are unknown, so the model needs normalizations, just as a mixture needed a shape for its components. Principal component analysis picks \hat Z and \hat\varphi to minimize
the factors Z_{\cdot 1}, \dots, Z_{\cdot K} being uncorrelated across i;
the loadings being orthonormal: \varphi_j'\varphi_k = 0 for j \ne k and \varphi_k'\varphi_k = 1.
Order the factors by decreasing sample variance. The ordered pairs (\hat Z_{\cdot k}, \hat\varphi_k) are the principal components.
Reading PCA as the estimate of a “true” factor model needs more (uncorrelated \varepsilon_{ij}); as a description of the data it needs nothing more.
The geometry in two dimensions
d = 2, K = 1: PCA finds the line through the centred cloud that minimizes the squared perpendicular distances. The grey segments are the residuals \varepsilon_i; the score \hat Z_{i1} is where the foot of each segment lands.
Equivalently, PC1 is the direction along which the projected points have the largest variance. PC2 is the perpendicular direction, and the rotated coordinates on the right are uncorrelated.
In three dimensions
With d = 3 and K = 2, PCA fits a plane through the cloud.
\hat\varphi_1 and \hat\varphi_2 span the plane; (\hat Z_{i1}, \hat Z_{i2}) are observation i’s coordinates on it.
The segments are the residuals \varepsilon_i, perpendicular to the plane.
In general PCA finds the K-dimensional subspace closest to the d-dimensional cloud, and approximates each observation by \bar X + \hat Z_{i1}\hat\varphi_1 + \dots + \hat Z_{iK}\hat\varphi_K.
Computing it: the singular value decomposition
Let X be the n \times d matrix of centred (and scaled) data. Linear algebra factors it as
with U'U = I_n, V'V = I_d, and D zero off the diagonal with weakly decreasing diagonal entries d_1 \ge d_2 \ge \dots.
The kth loading vector \hat\varphi_k is the kth column of V.
The kth factor \hat Z_{\cdot k} is the kth column of UD, which equals X\hat\varphi_k: the data projected onto the kth loading.
The sample variance of \hat Z_{\cdot k} is d_k^2/(n - 1), decreasing in k by construction.
The kth component does not depend on K. Fitting one factor or five gives the same \hat\varphi_1 and \hat Z_{\cdot 1}, so “the first principal component” is well defined.
prcomp() on the European diets
pcfood <-prcomp(food, center =TRUE, scale =TRUE, rank =5) # rank = K; centre and scale as beforeround(pcfood$rotation, 2) # loadings: column k is the kth principal component
round(sort(food_factors[, 1]), 1)[c(1:4, 22:25)] # the ends of PC1
## Ireland Denmark W Germany UK Romania Bulgaria Albania Yugoslavia
## -2.7 -2.4 -2.1 -1.7 2.8 3.1 3.5 3.6
round(sort(food_factors[, 2], decreasing =TRUE), 1)[1:3] # the top of PC2
## Portugal Spain Greece
## 4.3 2.6 1.0
PC1 is negative for Ireland, Denmark, West Germany and the UK, positive for the Balkans: the east-west, animal-plant division. PC2 is largest for Portugal and Spain, then Greece: the Mediterranean reading survives.
Countries in principal component space
Colours are the seven K-means clusters. On PC1 and PC2 the clusters sit apart: countries that K-means grouped are close in component space, although neither method saw the other.
PC3 against PC4 carries little of the structure. Two components were the right axes; two food groups were not.
How many components? The scree plot
The variance of \hat Z_{\cdot k} falls with k by construction. Under a “true” factor model with K_0 factors, it should drop to about zero after K_0.
Here there is a drop after the first component and another after the fourth. One factor, or four? The notes’ plot(pcfood) draws the same bars.
Proportion of variance explained
summary(pcfood)
## Importance of first k=5 (out of 9) components:
## PC1 PC2 PC3 PC4 PC5
## Standard deviation 2.0016 1.2787 1.0620 0.9771 0.68106
## Proportion of Variance 0.4452 0.1817 0.1253 0.1061 0.05154
## Cumulative Proportion 0.4452 0.6268 0.7521 0.8582 0.90976
The variances sum to d = 9 after scaling, so the share of component k is \hat{\operatorname{Var}}(\hat Z_{\cdot k})/9: 45 percent for PC1, 63 percent for the first two, 86 percent for four.
The share is the proportional fall in the PCA objective from adding the component, like the explained sum of squares in an in-sample R^2, with the same two warnings: it is in-sample, and a large share does not certify a “true” factor.
Choosing K for PCA
As with clustering, K is a matter of interpretation, not of a prediction loss.
Nesting helps: compute a large K once, then read the components in order and stop when they stop making sense. For the diets that is two, perhaps three.
The scree plot and the variance shares guide the eye. In economics, Bai and Ng (2002) turn the drop in the scree plot into an information criterion for the number of factors.
For principal components regression, section 5, K becomes a tuning parameter with an out-of-sample criterion again, and cross-validation returns.
Checkpoint: PCA
The loadings of PC1 are multiplied by -1 and so are its scores. Has anything changed?
Why does prcomp(food, rank = 2) give the same first two loadings as rank = 5, when kmeans() with K = 3 and K = 7 gives unrelated clusters?
The first two components explain 63 percent of the variance of the scaled protein data. What would the share be if scale = FALSE and why would it be misleading?
PCA in the wild
Congress in two dimensions, the business cycle in one
Every recorded vote of 2009 and 2010: 445 members, 1,647 votes. Is there a low-dimensional structure in a member’s 1,647 votes? One candidate factor is obvious: ideology.
One dominant factor
pcavote <-prcomp(votes, scale =TRUE) # K not chosen yet: all 445 componentsround(100*summary(pcavote)$importance[2, 1:6], 1) # percent of variance
One component carries 36 percent of the variance of 1,647 votes, a second 13 percent, and nothing else more than 4 percent. This is what a scree plot with a cliff looks like.
The first component is ideology
votepc <-predict(pcavote)round(sort(votepc[, 1])[1:4], 1) # most negative
## PC1_positive
## party FALSE TRUE
## D 9 253
## DR 1 0
## R 182 0
The most negative scores are conservative Republicans, the most positive are liberal Democrats; the sign of the score alone classifies 435 of 445 members. The nine Democrats on the negative side are the conservative wing.
This is the horizontal axis of the opening slide. Political scientists estimate it with purpose-built models (Poole and Rosenthal); PCA gets most of the way in one line.
The five lowest scores belong to the five members who missed almost every vote: two who left for the Senate and the cabinet in early 2009, the Speaker, who by custom votes rarely, and two elected in November 2010.
The second component is attendance: its correlation with the number of abstentions is -0.98.
The votes with the largest loadings on PC2 were near-unanimous symbolic resolutions: Vote 1146 is “Supporting the goals and ideals of a Cold War Veterans Day”, 429 yeas, 16 abstentions, no nays.
PCA centres each column. The mean of such a vote is about 0.96, so a yea is +0.04 after centring and an abstention is -0.96. On a thousand such votes, a member who was absent sits far from everyone else, and that distance is the second-largest source of variance in the data.
The lesson, and a clustering cross-check
A principal component is the direction of largest variance, whatever that direction means. Ideology was first because members disagree most along party lines; attendance was second because a few members missed everything. The method does not know which one you wanted.
K-means with two groups on the same scaled votes, no labels:
set.seed(0)table(cluster =kmeans(scale(votes), centers =2, nstart =10)$cluster, party = legis$party)
## party
## cluster D DR R
## 1 8 1 182
## 2 254 0 0
Clustering recovers the parties for 436 of 445 members, eight of the same nine conservative Democrats crossing over. Two unsupervised methods, one latent structure.
The macroeconomy in one factor: FRED-MD
FRED-MD (McCracken and Ng 2016) is a monthly panel of 126 US series: output, employment, prices, interest rates, money. Row 1 of the file holds each series’ transformation code (levels, differences, log differences) to make it stationary.
raw <-read.csv("data/2024-07-fredmd.csv", check.names =FALSE)tcode <-as.numeric(raw[1, -1]) # transformation code of each seriesfred <- raw[-1, ]; fred$sasdate <-as.Date(fred$sasdate, "%m/%d/%Y")fredx <-as.data.frame(mapply(fredmd_transform, fred[, -1], tcode)) # function in the appendixfredx$date <- fred$sasdatefredx <-filter(fredx, date >=as.Date("1960-01-01"), date <=as.Date("2019-12-01"))keep <-names(fredx)[colSums(is.na(fredx)) ==0&names(fredx) !="date"]c(months =nrow(fredx), series =length(keep))
The first component of 121 series, 15 percent of their variance, falls in every recession and troughs in the deepest ones. Nothing about dates or recessions went in.
Its loadings are positive on payroll employment and industrial production and negative on the unemployment rate and claims: a real activity factor.
A loading vector is a recipe: the first factor is a weighted sum of 121 standardized series, employment and output positive, unemployment negative.
The second factor is prices: the consumer price index and its components, the PCE price index. Inflation is the next largest common movement after the cycle.
A few components summarize a hundred series; section 5 puts them into a regression.
Principal components regression
From unsupervised to supervised
PCA finds the few directions that best explain the variation in X.
If some Y depends on X through the same latent factors, those directions should predict Y too.
Principal components regression (PCR): do PCA on the X_i, then regress Y_i on the scores \hat Z_{i1}, \dots, \hat Z_{iK}.
Why it can work when OLS on X does not:
K regressors instead of d, with K \ll d, so OLS is well-behaved even when d is close to n or above it;
the scores are uncorrelated and ordered, so adding the (K+1)th does not disturb the first K;
K is a complexity parameter with an out-of-sample loss, so cross-validation chooses it.
The algorithm
Do PCA on X_1, \dots, X_n to obtain \hat Z_{i1}, \dots, \hat Z_{iK_{\max}} for some large K_{\max}, for instance K_{\max} = d if d \le n.
Apply a supervised method to predict Y_i from the scores:
OLS on the first K scores, for each K \le K_{\max}, with cross-validation choosing K. Because the components are nested and uncorrelated, this is one sequence of fits.
Or a lasso on the scores, or on the scores together with the original X_i, letting the penalty choose between raw variables and factors.
Neither step is new. Step 1 is section 3; step 2 is lectures 10 and 12. What is new is treating the unsupervised output as an input.
Online spending, continued
Lecture 12 predicted a household’s log spending from the share of its browsing at each of 1,000 websites. The lasso reached an out-of-sample R^2 of 0.11; OLS on all 1,000 sites was below zero. Same data, same split.
No: the first component explains under 2 percent of the variance and a hundred components under a third. Browsing shares are spread across many weak patterns, nothing like the one-factor Congress.
The scores’ correlations with spending are small and not ordered: the first component is the most related to spending, the fourth is next, the second and third are useless. PCA did not look at Y.
The familiar U: too few components underfit, too many let OLS chase noise. The minimum is at 48 components, against a null mean squared error of 2.79.
The decline is slow because the predictive directions arrive in no particular order; the curve has to wait for them.
PCR against the lasso, out of sample
b_pcr <-lm.fit(cbind(1, Zweb[train, 1:K_best]), ly[train])$coefficientsset.seed(0); cv_lasso <-cv.glmnet(xweb[train, ], ly[train]) # lecture 12set.seed(0); cv_both <-cv.glmnet(cbind(xweb, Zweb[, 1:100])[train, ], ly[train]) # sites and scoresb_both <-coef(cv_both, s ="lambda.min")[-1]data.frame(model =c("PCR, K chosen by CV", "Lasso on 1,000 sites", "Lasso on sites and 100 scores"),inputs_used =c(K_best, sum(coef(cv_lasso, s ="lambda.min")[-1] !=0),paste(sum(b_both[1:1000] !=0), "sites +", sum(b_both[1001:1100] !=0), "scores")),out_of_sample_r2 =round(c(r2(ly[test], cbind(1, Zweb[test, 1:K_best]) %*% b_pcr, mean(ly[train])),r2(ly[test], predict(cv_lasso, xweb[test, ], s ="lambda.min"), mean(ly[train])),r2(ly[test], predict(cv_both, cbind(xweb, Zweb[, 1:100])[test, ], s ="lambda.min"), mean(ly[train]))), 3))
## model inputs_used out_of_sample_r2
## 1 PCR, K chosen by CV 48 0.100
## 2 Lasso on 1,000 sites 228 0.107
## 3 Lasso on sites and 100 scores 163 sites + 20 scores 0.111
PCR with 48 components matches the lasso with 228 sites on the held-out households: two different models, the same ten percent of variance explained.
Offered both, the lasso keeps 163 sites and 20 scores: factors and raw variables are complements. With unscaled site shares, no number of components gets the hold-out R^2 above 0.02.
What the spending example shows
PCA ignores Y. Components are ordered by their variance in X. The predictive ones were the 1st, the 4th, the 8th, and so on, so PCR needed 48 components to collect them.
Scale decides the components. Unscaled, PCA described a handful of giant sites and PCR failed; scaled, it described browsing patterns and PCR worked.
K is now a tuning parameter with an out-of-sample loss, and cross-validation chooses it exactly as it chose \lambda for the lasso and the tree size last week.
Unsupervised output is supervised input. The forest and the lasso of earlier lectures accept scores as regressors; the lasso can even choose between scores and raw variables.
Checkpoint: PCR
Lecture 12 found OLS on all 1,000 sites had an out-of-sample R^2 below zero. Why does OLS on 48 principal component scores not suffer the same fate?
Why can the cross-validation curve over K be computed with a single ordering of regressors, when the lasso needed a whole path of penalties?
A colleague proposes choosing K from the scree plot of X and then regressing Y on those K scores. What could go wrong?
Unsupervised learning in one page
No Y, no out-of-sample check. The goal is to describe X with fewer numbers; the discipline against invented structure has to come from replication, scaling and interpretation.
Two latent-variable models, two methods. A mixture model with a hidden type gives K-means: alternate centres and nearest-centre assignments until nothing moves. A linear factor model with hidden continuous factors gives PCA: the K-dimensional plane closest to the cloud, computed by one singular value decomposition.
K-means finds a local minimum of the within-cluster sum of squares. Use many starts, scale the columns, and treat K as a question of interpretation.
Principal components are nested, uncorrelated and ordered by variance. Loadings say what a component is; scores say where each observation sits; the scree plot and variance shares say how many matter. The largest direction is whatever varies most, be it ideology, attendance or the business cycle.
Factors make regressors. Principal components regression turns the scores into inputs for OLS or the lasso and gives K an out-of-sample criterion again. PCA does not look at Y, so the useful components may come late.
Reading and data sources
James, Witten, Hastie and Tibshirani, An Introduction to Statistical Learning, chapter 12: PCA and clustering; section 6.3.1 for principal components regression.
Hastie, Tibshirani and Friedman, The Elements of Statistical Learning, sections 14.3 (clustering, including the Gaussian mixture limit) and 14.5 (PCA).
Taddy, Business Data Science (2019), chapter 7: the protein and roll-call data.
Write the objective with both arguments, W(C, \mu) = \sum_{i=1}^n \lVert X_i - \mu_{C_i} \rVert^2.
For fixed memberships C, W is a sum over clusters of \sum_{i \in C_k} \lVert X_i - \mu_k \rVert^2, which is minimized by the cluster mean. Step 2 cannot increase W.
For fixed centres \mu, each term \lVert X_i - \mu_{C_i} \rVert^2 is minimized by sending i to its nearest centre. Step 3 cannot increase W.
W is bounded below and there are finitely many partitions, so the sequence stops after finitely many steps, at a partition no single step improves: a local minimum.
Centres can be eliminated: for a cluster of size n_k,
so K-means also minimizes the within-cluster pairwise squared distances, each cluster’s sum scaled by its size. Hastie, Tibshirani and Friedman (section 14.3) introduce clustering through this pairwise form.
K-means as a limit of the Gaussian mixture
In a Gaussian mixture with common variance \sigma^2, the EM algorithm alternates two steps:
E step. The posterior probability that observation i came from component k, r_{ik} = \frac{\pi_k \exp\{-\lVert X_i - \mu_k \rVert^2 / 2\sigma^2\}}{\sum_{l} \pi_l \exp\{-\lVert X_i - \mu_l \rVert^2 / 2\sigma^2\}}.
M step.\mu_k becomes the r_{ik}-weighted average of the X_i, and \pi_k the average of r_{ik}.
As \sigma^2 \to 0, the exponential with the smallest distance dominates every other, so r_{ik} \to 1 for the nearest centre and 0 otherwise. The E step becomes step 3 of K-means, the M step becomes step 2, and the weights \pi_k drop out. K-means is EM with hard assignments; EM with finite \sigma^2 is “soft K-means” (Hastie, Tibshirani and Friedman, section 14.3.7).
The first component maximizes variance
Let S be the d \times d sample covariance matrix of the centred data. The variance of the projection X_i'\varphi is \varphi' S \varphi. The first loading solves
The Lagrangian \varphi' S \varphi - \lambda(\varphi'\varphi - 1) has first-order condition S\varphi = \lambda\varphi: \varphi is an eigenvector of S and the variance it achieves is \varphi' S \varphi = \lambda. So \hat\varphi_1 is the eigenvector with the largest eigenvalue \lambda_1, and \hat{\operatorname{Var}}(\hat Z_{\cdot 1}) = \lambda_1.
Adding the constraint \varphi'\hat\varphi_1 = 0 gives the second eigenvector, and so on. The eigenvalues sum to \operatorname{tr}(S), the total variance, which is d after scaling: that is the “proportion of variance explained”.
Minimum reconstruction error gives the same answer: for a unit vector \varphi, \lVert X_i \rVert^2 = (X_i'\varphi)^2 + \lVert X_i - (X_i'\varphi)\varphi \rVert^2, so minimizing the summed residuals is maximizing the summed projections.
With X = UDV', S = V (D'D/(n-1)) V', so the eigenvectors are the columns of V and \lambda_k = d_k^2/(n-1): the singular value decomposition of section 3 and the eigenvalues here are the same computation.
Reading prcomp() through the SVD
Every claim on the SVD slide, checked on the protein data:
sv <-svd(xfood) # xfood is centred and scaledall.equal(sv$d /sqrt(nrow(xfood) -1), pcfood$sdev) # sdev = d_k / sqrt(n - 1)
## [1] TRUE
all.equal(abs(unname(sv$v[, 1:5])), abs(unname(pcfood$rotation))) # loadings = columns of V, up to sign
## [1] TRUE
all.equal(abs(unname(xfood %*% sv$v[, 1:5])), abs(unname(food_factors))) # scores = X V = U D
## [1] TRUE
round(cor(food_factors), 2)[1:3, 1:3] # scores are uncorrelated
round(sum(pcfood$sdev^2), 6) # variances sum to d = 9
## [1] 9
abs() handles the arbitrary sign of each component. pcfood$x is the same matrix as predict(pcfood).
Why centring matters
PCA minimizes the sum of squared distances from the centred data to a K-dimensional subspace through the origin. Without centring, the subspace must pass through the origin of the raw data rather than through the point cloud, and the first component mostly points from the origin towards the mean \bar X.
For the roll-call votes, the raw mean of a near-unanimous resolution is 0.96. Uncentred, the first component would be “how much a member votes yea on everything”, which is attendance mixed with the number of resolutions, not ideology.
Centred, a yea on such a vote is +0.04 and an abstention -0.96: the column contributes almost nothing unless a member was absent, and absence becomes a component of its own only because the five absentees were absent on hundreds of such columns at once.
prcomp() centres by default (center = TRUE); scale = TRUE is the choice you must make.
The FRED-MD transformation codes
Each series in FRED-MD carries a code for the transformation that makes it stationary (McCracken and Ng 2016, Appendix). The function used on the FRED-MD slide:
fredmd_transform <-function(x, code) {switch(as.character(code),"1"= x, # level"2"=c(NA, diff(x)), # first difference"3"=c(NA, NA, diff(x, differences =2)), # second difference"4"=log(x), # log"5"=c(NA, diff(log(x))), # log difference: a growth rate"6"=c(NA, NA, diff(log(x), differences =2)), # change in the growth rate"7"=c(NA, NA, diff(x[-1] / x[-length(x)] -1))) # change in the percentage change}
mapply(fredmd_transform, fred[, -1], tcode) applies each series’ own code. Codes 5 and 6 dominate: 52 series are growth rates and 33 are changes in growth rates (prices).
protein.csv, the 25 countries and nine food groups;
rollcall-votes.csv and rollcall-members.csv, the 111th House;
2024-07-fredmd.csv, the FRED-MD panel through June 2024, used through December 2019;
browser-totalspend.csv, browser-domains.csv and browser-sites.txt, the online spending panel of lecture 12.
kmeans(), prcomp() and svd() are in base R.
Return to the question
A computer found the parties: the first principal component of 1,647 votes is an ideology score that classifies 435 of 445 members by its sign, and two-cluster K-means recovers the parties for 436. The members trailing off the bottom were the second component, attendance, because PCA reports the largest variation it finds, whatever it means.