Jaber Notes · 9 of 16
Unsupervised Learning
Hierarchical/DBSCAN clustering, PCA, SVD, LDA, ICA, t-SNE, UMAP.
Finding structure without labels: clustering beyond k-means, the full PCA eigenvector derivation and its SVD connection, LDA and ICA, the t-SNE/UMAP embedding methods, and anomaly detection.
Visual reference
Eigenvector intuition
Learn structure from unlabeled data. These methods are building blocks for EDA, pretraining, recommenders, and anomaly detection.
Table of contents
- Taxonomy of unsupervised learning
- Clustering (additional methods)
- PCA (full derivation)
- SVD and its applications
- Linear Discriminant Analysis (LDA)
- Independent Component Analysis (ICA)
- t-SNE (visualization)
- UMAP
- Matrix factorization for recommenders
- Anomaly detection
1. Taxonomy of unsupervised learning
| Category | Goal | Examples |
|---|---|---|
| Clustering | Group similar points | k-means, GMM, DBSCAN, hierarchical |
| Dimensionality reduction | Compress to lower-dim | PCA, ICA, autoencoders |
| Manifold learning | Preserve local structure | t-SNE, UMAP, Isomap |
| Density estimation | Learn | GMM, KDE, normalizing flows |
| Matrix factorization | Decompose data matrix | PCA, NMF, SVD, word2vec |
| Anomaly detection | Find unusual points | Isolation Forest, LOF, one-class SVM |
2. Clustering (additional methods)
2.1 Hierarchical clustering
Builds a dendrogram (tree of merges/splits).
Agglomerative (bottom-up):
- Start: each point is its own cluster.
- At each step: merge the two closest clusters.
- Stop when desired number of clusters reached (cut dendrogram).
Linkage criteria (how to measure distance between clusters):
| Linkage | Distance | Effect |
|---|---|---|
| Single | "Chaining" — long stringy clusters | |
| Complete | Compact, spherical clusters | |
| Average | Compromise | |
| Ward | Minimizes within-cluster variance | Most common; similar to k-means |
Divisive (top-down): start with one cluster, recursively split. Less common.
Advantage: no need to specify in advance. Dendrogram shows all possible clusterings. Disadvantage: or depending on implementation. Not scalable.
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
Z = linkage(X, method='ward')
plt.figure(figsize=(10,4))
dendrogram(Z, truncate_mode='lastp', p=30)
plt.show()
model = AgglomerativeClustering(n_clusters=4, linkage='ward')
labels = model.fit_predict(X)2.2 DBSCAN (Density-Based Spatial Clustering)
Idea: clusters are dense regions separated by low-density regions.
Parameters: eps (neighborhood radius), min_samples (minimum neighbors to be a core point).
Definitions:
- Core point:
min_samplespoints within radiuseps. - Border point: within eps of a core point but not core itself.
- Noise point: not within eps of any core point.
Algorithm:
- For each unvisited point:
- If core point: start new cluster, expand to all density-reachable points.
- Otherwise: mark as noise (may later become border).
Advantages:
- Finds arbitrarily shaped clusters.
- Automatically identifies outliers (noise points).
- No need to specify .
Disadvantages:
- Two parameters (eps, min_samples) to tune.
- Struggles when clusters have varying densities.
- Poor in high dimensions (all distances become similar).
from sklearn.cluster import DBSCAN
db = DBSCAN(eps=0.5, min_samples=5)
labels = db.fit_predict(X)
# -1 = noise/outlier
n_clusters = len(set(labels)) - (1 if -1 in labels else 0)2.3 Cluster evaluation metrics (no ground truth)
Silhouette coefficient:
where = mean distance to same-cluster, = mean distance to nearest other cluster. Range: . Higher = better. Average over all points.
Davies-Bouldin Index: lower = better. Ratio of within-cluster to between-cluster distances.
Calinski-Harabasz Index: ratio of between-cluster to within-cluster variance. Higher = better.
from sklearn.metrics import silhouette_score, davies_bouldin_score, calinski_harabasz_score3. PCA (full derivation)
3.1 Goal
Find orthonormal directions in such that projected data has maximum variance.
Center data: .
3.2 First principal component
where is the sample covariance.
Lagrangian: .
Stationarity: .
So is an eigenvector of . The objective value is . Maximize → choose eigenvector for largest eigenvalue.
3.3 Subsequent components
-th PC: eigenvector of for -th largest eigenvalue, subject to orthogonality with .
Spectral decomposition: , , .
3.4 Projection and reconstruction
Encode (reduce to dims): . Decode (reconstruct): . Reconstruction error: . Minimized by choosing top eigenvectors (Eckart-Young for covariance matrix).
3.5 Explained variance ratio
Cumulative EVR: choose to retain 95% (or 99%) of variance.
3.6 PCA via SVD (computational approach)
Directly decompose data matrix (more numerically stable than computing covariance):
Then: eigenvectors of = right singular vectors , eigenvalues of = .
sklearn uses SVD by default (no need to form ).
3.7 When PCA helps (and doesn't)
Helps: correlated features, dimensionality reduction for downstream model, visualization, noise reduction.
Doesn't help: if relationship to target is nonlinear with respect to principal components; if features are already uncorrelated; if you need interpretable features (PCs are linear combinations of originals).
Supervised alternative: see Linear Discriminant Analysis (§5).
from sklearn.decomposition import PCA
pca = PCA(n_components=0.95) # retain 95% variance
X_reduced = pca.fit_transform(X_train)
print(pca.n_components_)
print(pca.explained_variance_ratio_.cumsum())
# Visualize 2D
pca2 = PCA(n_components=2)
X_2d = pca2.fit_transform(X)4. SVD and its applications
4.1 Full decomposition
(see Note 01 for full details).
Truncated SVD (rank- approximation):
Minimizes over all rank- matrices (Eckart-Young theorem).
4.2 Applications
| Application | How SVD is used |
|---|---|
| PCA | SVD of centered data matrix → principal components |
| Recommender systems | Low-rank approximation of user-item rating matrix |
| Latent Semantic Analysis (LSA) | SVD of TF-IDF matrix → document/term embeddings |
| Image compression | Truncated SVD of pixel matrix |
| Pseudoinverse | |
| Condition number | \kappa = \sigma_\max/\sigma_\min — measures ill-conditioning |
5. Linear Discriminant Analysis (LDA)
5.1 Goal
Supervised dimensionality reduction: find projection that maximizes class separation.
Two scatter matrices:
- Within-class scatter: .
- Between-class scatter: .
5.2 Fisher criterion
Find projection that maximizes:
Solution: generalized eigenvalue problem .
Projection onto top eigenvectors.
LDA as generative classifier: assumes each class is Gaussian with shared covariance . Under this model, Bayes-optimal boundary is linear.
QDA (Quadratic Discriminant Analysis): allows class-specific covariances → quadratic boundary.
6. Independent Component Analysis (ICA)
6.1 Problem (cocktail party)
Observe , where are independent non-Gaussian sources and is unknown mixing matrix. Recover .
Key difference from PCA: PCA finds uncorrelated components (second-order statistics); ICA finds statistically independent components (higher-order statistics).
Why non-Gaussian? Central limit theorem: sums of independent variables are more Gaussian. So a Gaussian component is maximally "mixed" — unmixing must find the most non-Gaussian projections.
6.2 FastICA
Maximize non-Gaussianity of , measured by:
- Kurtosis: . Zero for Gaussian; non-zero for super/sub-Gaussian.
- Negentropy: . Always , maximized for non-Gaussian.
Fixed-point iteration (FastICA) converges cubically (faster than gradient methods).
from sklearn.decomposition import FastICA
ica = FastICA(n_components=3, random_state=0)
S_estimated = ica.fit_transform(X)Limitations: cannot determine order or scale of components; sources must be non-Gaussian (except at most one can be Gaussian).
7. t-SNE (visualization)
7.1 Purpose
t-distributed Stochastic Neighbor Embedding (van der Maaten & Hinton, 2008): map high-dimensional data to 2D/3D for visualization, preserving local structure (nearby points in high-D → nearby in low-D).
7.2 Algorithm
High-dimensional affinities: for each pair, define conditional probability:
is set per-point based on perplexity (target number of effective neighbors).
Symmetrize: .
Low-dimensional affinities (heavy-tailed Student-t):
Why Student-t? Alleviates crowding problem: in high-D, moderate distances become equal; t-distribution has heavier tail to spread points in 2D.
Objective (minimize KL divergence):
Optimized via gradient descent on low-D positions .
7.3 Critical notes about t-SNE
- Not for general dimensionality reduction (distances not preserved globally; non-deterministic; not invertible).
- Perplexity (5–50): controls neighborhood size. Try multiple values.
- Cluster sizes and distances between clusters are not meaningful in t-SNE plots.
- Cannot be applied to new data (need to re-run on full dataset).
- Non-convex; results depend on random seed.
from sklearn.manifold import TSNE
tsne = TSNE(n_components=2, perplexity=30, learning_rate='auto', init='pca', random_state=42)
X_2d = tsne.fit_transform(X)8. UMAP
8.1 Key differences from t-SNE
| Property | t-SNE | UMAP |
|---|---|---|
| Global structure | Poorly preserved | Better preserved |
| Speed | Slow ( naive) | Much faster |
| New points | Cannot transform | Can transform (out-of-sample) |
| Mathematical basis | Probability (KL divergence) | Topology (fuzzy simplicial sets) |
| Metric | Euclidean only | Any metric |
8.2 Brief theory
UMAP (McInnes et al., 2018) is grounded in Riemannian geometry and algebraic topology.
- Construct a fuzzy topological representation of the high-dimensional data using k-nearest neighbors and Riemannian metric (local radius normalized).
- Find a low-dimensional embedding that preserves this fuzzy structure, optimizing cross-entropy:
where (learnable parameters ).
import umap
reducer = umap.UMAP(n_components=2, n_neighbors=15, min_dist=0.1, metric='euclidean', random_state=42)
X_2d = reducer.fit_transform(X)
# Transform new points:
X_new_2d = reducer.transform(X_new)9. Matrix factorization for recommenders
9.1 Problem setup
Explicit feedback: user-item rating matrix , mostly missing.
Goal: fill in missing entries to predict ratings/preferences.
9.2 Matrix factorization (SVD-based)
Approximate: , where:
- : user embeddings.
- : item embeddings.
- = latent factors (dimensionality).
Objective (observed entries only):
Alternating Least Squares (ALS): fix , solve for each (closed form); fix , solve for each . Parallelizable.
SGD: sample observed ratings, gradient update for .
9.3 Non-negative Matrix Factorization (NMF)
with (element-wise).
Why non-negative? Parts-based representation: in images, each component corresponds to a part (not the signed PCA components). In NLP, topics are non-negative weighted combinations of words.
Multiplicative updates (Lee & Seung):
from sklearn.decomposition import NMF
model = NMF(n_components=10, init='nndsvda', max_iter=300, random_state=0)
W = model.fit_transform(X) # user/document representation
H = model.components_ # topic/feature representation9.4 Implicit feedback
Most real systems have implicit feedback (clicks, views, purchases) rather than explicit ratings.
Weighting: treat all interactions as positive; unobserved as potentially negative with lower confidence.
ALS for implicit (Hu et al., 2008): define confidence , minimize:
where if interaction, 0 otherwise. implicit library implements this.
10. Anomaly detection
10.1 Problem types
- Novelty detection: training data is clean; find new data that differs from it.
- Outlier detection: training data may contain outliers; find them.
10.2 Isolation Forest
Idea: anomalies are rare and different → isolated quickly by random splits.
Build random trees that recursively split on random features at random thresholds. Anomaly score = average depth at which point is isolated (shorter path = more anomalous).
where = path length, = expected path length for samples.
from sklearn.ensemble import IsolationForest
iso = IsolationForest(contamination=0.05, random_state=0)
labels = iso.fit_predict(X) # -1 = outlier, 1 = inlier
scores = iso.score_samples(X) # lower = more anomalous10.3 Local Outlier Factor (LOF)
Compare local density of point to its neighbors. Anomalies are in regions of much lower density than neighbors.
where = local reachability density.
LOF > 1 = outlier (lower density than neighbors).
10.4 One-class SVM
Fit a hypersphere (or hyperplane in kernel space) around the training data. Points outside are anomalies.
10.5 Statistical methods
Z-score: flag if . Assumes Gaussian. IQR: flag if outside . Non-parametric. Mahalanobis distance: multivariate generalization of Z-score; accounts for correlations.
*File: notes/09_unsupervised_learning.md — next: notes/10_practical_ml.md*
From-scratch code
Runnable implementations, each checked against its scikit-learn equivalent.
"""
Principal Component Analysis: covariance eigendecomposition vs sklearn.
Projects data onto directions of maximum variance (centered data).
"""
from __future__ import annotations
import numpy as np
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA as SkPCA
def pca_from_covariance(X: np.ndarray, n_components: int) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
X: n x d, assumed already centered.
Returns (transformed_X_n_by_k, components_k_by_d, explained_variance_ratio).
"""
n = X.shape[0]
cov = (X.T @ X) / (n - 1)
eigvals, eigvecs = np.linalg.eigh(cov)
idx = np.argsort(eigvals)[::-1][:n_components]
W = eigvecs[:, idx].T # k x d
Z = X @ W.T
ev = eigvals[idx]
evr = ev / eigvals.sum()
return Z, W, evr
def main() -> None:
X, _ = load_iris(return_X_y=True)
X = X - X.mean(axis=0)
n_comp = 2
Z, W, evr = pca_from_covariance(X, n_comp)
pca = SkPCA(n_components=n_comp).fit(X)
Z_sk = pca.transform(X)
# sklearn may flip sign of any principal direction
diff = np.minimum(np.abs(Z - Z_sk), np.abs(Z + Z_sk))
print("Explained variance ratio (scratch):", evr)
print("Explained variance ratio (sklearn) :", pca.explained_variance_ratio_)
print("Mean abs projection diff (per point, sign-corrected):", diff.mean())
if __name__ == "__main__":
main()