Contents
Deep Breakdown
What it tells me (Situation Awareness): projects a vector onto the 1D subspace (line through the origin) spanned by . The result is the closest point on that line to . Geometrically: drop a perpendicular from to the line; the foot of the perpendicular is . This is the scalar projection formula scaled back into a vector. The scalar projection of onto is (a number); multiplying by gives the vector projection . In DA/DS: projecting data onto a 1D direction is the core of PCA (project onto the first principal component), Linear Discriminant Analysis, and any dimensionality reduction to a single direction.
Flowchart
Real-world use
Where it is used
PCA: projecting data onto the first principal component direction . Regression with a single predictor: projecting the response vector onto the predictor direction. Gradient projection: projecting a gradient onto a constraint direction. Computing explained variance: = fraction of 's energy in the direction of .
Problem it solves
Given a direction and a point NOT on the line through , find the point on the line that is closest to . The closest point minimizes over all scalars . The solution is the orthogonal projection.
How it solves the problem
Minimize : take derivative with respect to and set to zero. . The projected vector is . Written as a matrix: where is the rank-1 projection matrix.
Example in a business
A DS computes the first PCA component of a customer feature matrix. To project each customer's feature vector onto this direction: (scalar, used for ranking) and (vector, for reconstruction). The scalar score is the first principal component score for customer .
The formula, piece by piece
- : the direction vector (basis of the 1D subspace); does NOT need to be unit length
- : row vector transpose of
- : the squared norm of (a scalar); the denominator normalizes the projection
- : outer product of with itself; an rank-1 matrix
- : the projection matrix onto ; rank-1, symmetric, idempotent ()
- : the projection of onto the line spanned by
- Scalar form: (scalar coefficient times the direction)
The formula in words
"Find how much of lies in the direction of (the scalar projection), then multiply by to get the vector that sits on the line at that 'shadow' point. Dividing by corrects for the length of ." Tiny example: , . . . . . Residual: . Check: .
Critical Concepts
- Idempotent: . Projecting twice gives the same result as projecting once.
- Symmetric: .
- Rank 1: the projection matrix has rank 1 (projects onto a line).
- Unit vector shortcut: if , then and .
- Residual orthogonality: always. The residual is perpendicular to .
- Energy decomposition: (Pythagorean theorem).
- Connection to PCA: PCA finds that maximizes over all data points, i.e., the direction of maximum projected variance.
Step-by-step calculation (tiny example)
Step 1: Define direction vector and input , .
Step 2: Compute scalar projection . . .
Step 3: Compute vector projection and verify orthogonality . Residual: . . The residual is orthogonal to .
Code examples
Beginner example (Python)
import numpy as np # -- 1D projection: pi_U(x) = (b b^T / b^T b) x ---
b = np.array([1.0, 2.0])
x = np.array([3.0, 1.0])
scalar_proj = np.dot(b, x) / np.dot(b, b)
proj_vector = scalar_proj * b
residual = x - proj_vector
print(f"b = {b}")
print(f"x = {x}")
print(f"lambda = {scalar_proj:.4f}")
print(f"pi_U(x) = {proj_vector}")
print(f"residual = {residual}")
print(f"b^T residual = {np.dot(b, residual):.10f} (should be 0)") # Projection matrix P_b = b b^T / b^T b
P_b = np.outer(b, b) / np.dot(b, b)
print(f"\nProjection matrix P_b:\n{P_b}")
print(f"P_b @ x = {P_b @ x} (matches pi_U(x): {np.allclose(P_b @ x, proj_vector)})")
print(f"P_b^2 = P_b (idempotent): {np.allclose(P_b @ P_b, P_b)}")Beginner example (R)
# -- 1D projection ---
b <- c(1, 2)
x <- c(3, 1)
scalar_proj <- sum(b * x) / sum(b * b)
proj_vector <- scalar_proj * b
residual <- x - proj_vector
cat(sprintf("lambda = %.4f\n", scalar_proj))
cat(sprintf("pi_U(x) = (%g, %g)\n", proj_vector[1], proj_vector[2]))
cat(sprintf("b^T residual = %.10f\n", sum(b * residual)))
# Projection matrix
P_b <- outer(b, b) / sum(b * b)
cat("Projection matrix P_b:\n")
print(round(P_b, 4))Professional example (Python)
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
np.random.seed(42)
# -- Business scenario: project customer data onto first PCA direction ---
# Each customer has 3 RFM features. Project each onto the first PCA direction.
N_CUSTOMERS = 200
rfm_raw = np.column_stack([
np.random.exponential(30, N_CUSTOMERS), # recency (days since last purchase)
np.random.poisson(10, N_CUSTOMERS), # frequency (purchases/month)
np.random.lognormal(4, 1, N_CUSTOMERS), # monetary (spend in euros)
])
scaler = StandardScaler()
rfm_scaled = scaler.fit_transform(rfm_raw)
# First PCA direction: eigenvector of largest eigenvalue of covariance matrix
cov_matrix = np.cov(rfm_scaled.T)
eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
b_first_pc = eigenvectors[:, -1] # largest eigenvalue direction
# Project each customer onto this 1D subspace
scalar_scores = rfm_scaled @ b_first_pc / np.dot(b_first_pc, b_first_pc)
proj_vectors = np.outer(scalar_scores, b_first_pc)
# Explained variance: ||pi_U(x)||^2 / ||x||^2
proj_norms_sq = np.sum(proj_vectors**2, axis=1)
orig_norms_sq = np.sum(rfm_scaled**2, axis=1)
explained_ratio = proj_norms_sq / orig_norms_sq
results = pd.DataFrame({
"customer": range(N_CUSTOMERS),
"pc1_score": scalar_scores.round(3),
"explained_ratio": explained_ratio.round(3),
})
print(f"First PCA direction b: {b_first_pc.round(4)}")
print(f"\nMean explained variance (1D projection): {explained_ratio.mean():.3f}")
print(f"\nTop 5 customers by PC1 score:")
print(results.nlargest(5, "pc1_score").to_string(index=False))Source: MML1