k-Nearest Neighbors
Suppose a hospital wants to predict whether a new patient's tumor is malignant. It has thousands of past patients with measured features and known outcomes. However, it has no formula relating them. One natural idea: find the past patients most similar to the new one. Then predict whatever the majority of them turned out to have. This is the entire idea behind k-Nearest Neighbors (k-NN). It is one of the oldest and conceptually simplest algorithms in machine learning. It dates to work in the early 1950s on nonparametric discrimination. k-NN matters because it makes almost no assumptions about the shape of the relationship between inputs and outputs. Instead of fitting a global equation, it stores the training data. It defers all computation to prediction time, a strategy called instance-based or lazy learning. This makes it a natural first algorithm for understanding the Bias–Variance Tradeoff concretely. The single knob visibly slides the model between overfitting and underfitting. It also introduces the idea that a learning algorithm's behavior is governed by a notion of distance or similarity. This theme reappears in clustering, recommender systems, and later in kernel methods. The big picture is this: k-NN replaces "learn a function" with "remember examples and vote among neighbors." Prediction requires no training phase in the usual sense. But it requires searching through data at query time. This creates real engineering tradeoffs in large-scale systems. Despite its simplicity, k-NN remains a strong baseline in image retrieval, recommendation, and anomaly detection. It also serves as a diagnostic tool for understanding a dataset's local structure before reaching for heavier models. This article builds k-NN from first principles. It covers the precise algorithm for classification and regression. It examines the effect of the neighborhood size and the choice of distance metric. It explains the complexity of brute-force versus tree-based search. It includes a full worked numerical example. Finally, it addresses the classical pitfalls that trip up nearly every newcomer, most notably the curse of dimensionality.
- k-NN predicts a query point's label by looking at the closest training points and taking a majority vote (classification) or average (regression).
- There is no training phase beyond storing data; all work happens at prediction time — "lazy learning."
- Small gives low bias, high variance (jagged, overfit boundaries); large gives high bias, low variance (smooth, underfit boundaries).
- The distance metric (Euclidean, Manhattan, Minkowski, cosine) defines what "similar" means, and feature scaling is essential before computing it.
- Brute-force prediction costs per query; k-d trees and ball trees can reduce this in low dimensions but degrade toward brute force in high dimensions.
- k-NN is the conceptual bridge to Kernels and the Kernel Trick, since a vote among neighbors is a special case of a weighted average with a hard cutoff kernel.
k-NN predicts by finding the most similar stored examples and letting them vote or average, turning the choice of and distance metric into a direct, tunable knob on the bias–variance tradeoff.
The idea
Formally, k-NN is a non-parametric, instance-based learning method. Given a training set
where are feature vectors and are labels (discrete for classification, real-valued for regression), k-NN stores verbatim. There is no parameter vector estimated from data — the "model" is the dataset itself, together with a chosen distance function and an integer . To predict the label of a new query point , the algorithm finds the set of the training points closest to under the chosen distance. For classification, the prediction is the plurality (most frequent) class among the neighbors' labels:
For regression, the prediction is the mean (or a distance-weighted mean) of the neighbors' target values:
Because prediction depends entirely on which points happen to be nearby, k-NN implicitly assumes that similar inputs have similar outputs — a smoothness assumption on the underlying function, not a specific parametric form. This is what makes it non-parametric: the effective complexity of the decision boundary grows with the amount of data, unlike a linear model whose functional form is fixed in advance regardless of .
How it works
The algorithm has two conceptual phases, though the first is nearly vacuous: 1. "Training": store the dataset , optionally organized in a spatial index (a k-d tree or ball tree) to speed up future queries. No parameters are fit. 2. Prediction: for each query point, compute distances to (a relevant subset of) training points, select the nearest, and aggregate their labels by vote or average. Preprocessing is not optional in practice: features must be put on comparable scales (standardization or min-max scaling), because distance metrics like Euclidean distance treat all coordinates as commensurable, and a feature measured in the thousands will dominate one measured in fractions unless rescaled. ``` ALGORITHM: k-Nearest-Neighbors (classification variant) INPUT: D = {(x_1, y_1), ..., (x_n, y_n)} # training set x_q # query point k # number of neighbors, 1 <= k <= n dist(a, b) # distance function TRAIN(D): store D # optionally build a spatial index (k-d tree, ball tree) return D PREDICT(D, x_q, k, dist): distances <- empty list for each (x_i, y_i) in D: d_i <- dist(x_q, x_i) append (d_i, y_i) to distances sort distances by d_i ascending neighbors <- first k entries of sorted distances
# classification: majority vote (break ties by nearest neighbor or smallest class index) counts <- empty map from label to integer for (d_i, y_i) in neighbors: counts[y_i] <- counts[y_i] + 1 y_hat <- label with maximum count in counts (tie-break: prefer label of the single nearest neighbor) return y_hat PREDICT_REGRESSION(D, x_q, k, dist):
# same neighbor search as above, then: neighbors <- k nearest (d_i, y_i) pairs y_hat <- (1 / k) * sum(y_i for (d_i, y_i) in neighbors) return y_hat PREDICT_WEIGHTED(D, x_q, k, dist):
# distance-weighted variant, reduces sensitivity to k neighbors <- k nearest (d_i, y_i) pairs weights <- [1 / (d_i + epsilon) for each neighbor] # epsilon avoids divide-by-zero y_hat <- sum(w_i * y_i) / sum(w_i) # regression
# for classification, sum w_i within each class and argmax return y_hat ```
Choosing : is a hyperparameter selected by holding out validation data or by cross-validation, never by the training data's own error (which is minimized, misleadingly, at ). Odd values of are conventional in binary classification to avoid tied votes. Choosing the distance metric: common choices are Euclidean (), Manhattan (), the general Minkowski family, and cosine distance for high-dimensional sparse data such as text; the right choice depends on the geometry and scale of the features.
Complexity & correctness
Time complexity. Let be the number of training points and the dimensionality of the features.
- Training: with brute force (just store the array), or if building a k-d tree or ball tree.
- Brute-force prediction: computing distance to every point costs each, over points, giving per query; selecting the smallest via a partial selection (e.g., a max-heap of size ) costs an additional , so the total is per query.
- Tree-based prediction (k-d tree, ball tree): average-case per query when is small relative to , because the tree prunes large branches of the space that cannot contain a closer point than what's already found. This degrades toward in the worst case, and in practice toward brute force once exceeds roughly 15–20 dimensions — the geometric pruning stops helping because in high dimensions nearly every point ends up "on the boundary" of any partition.
- Space: to store the raw data, plus overhead for a tree index.
There is a genuine and important asymmetry with parametric models: k-NN pushes essentially all computation from training time to prediction time. A linear or logistic regression model spends effort fitting a small parameter vector once, then predicts in ; k-NN "trains" instantly but pays or on every single query, and must keep the entire dataset in memory indefinitely.
Correctness / why it works — the bias–variance view. Consider regression with squared-error loss. Suppose the true relationship is with mean-zero noise of variance , and the neighbors of have approximately independent noise. The k-NN regression estimate is
Taking expectation over the noise, the bias comes from averaging over a neighborhood instead of evaluating it exactly at :
which grows as grows, because the neighborhood radius must expand to include points, and typically varies more over a larger region (assuming is smooth, this scales with the neighborhood's spatial extent). The variance, assuming roughly independent noise across neighbors, is
which shrinks as grows, exactly as averaging more independent noisy quantities reduces variance. This is the bias–variance tradeoff made explicit: has zero averaging bias but variance (as noisy as a single observation); (predict the global mean for every query) has minimal variance but maximal bias, since it ignores entirely. The optimal minimizes the sum
and is found in practice by cross-validation rather than by this formula directly, since is unknown.
Consistency. A classical and reassuring theoretical result (Cover & Hart, 1967, for ; extended for general ) states that as with and , the k-NN classifier's error rate converges to the Bayes-optimal error rate — the best possible error achievable by any classifier given the true data distribution. Intuitively: letting grow ensures the noise-averaging variance vanishes, while requiring ensures the neighborhood radius shrinks to zero (so the bias from averaging over a spatial region also vanishes) as more data arrives. This is a genuine asymptotic guarantee, but it says nothing about finite-sample behavior, where the curse of dimensionality (below) can make "shrinking neighborhoods" require impractically large .
Worked example
Consider a tiny 2-feature dataset predicting whether a loan applicant defaults (`Yes`/`No`), with features income (in $1000s) and debt ratio (percentage of income owed in debt):
| Point | Income | Debt Ratio | Label |
|---|---|---|---|
| 25 | 40 | No | |
| 30 | 45 | No | |
| 70 | 10 | No | |
| 68 | 55 | Yes | |
| 40 | 60 | Yes | |
| 35 | 30 | No |
Query point: .
Step 1 — scale features. Income ranges roughly 25–70 (span 45), debt ratio 10–60 (span 50); they're comparable here, but in general we standardize: . For this worked example we proceed with raw values for transparency, computing Euclidean distance .
Step 2 — compute distances to :
| Point | Computation | Distance |
|---|---|---|
Step 3 — sort ascending: .
Step 4 — predict for different :
| Neighbors used | Labels | Vote | Prediction | |
|---|---|---|---|---|
| 1 | No | No: 1 | No | |
| 3 | No, No, Yes | No: 2, Yes: 1 | No | |
| 5 | No, No, Yes, No, Yes | No: 3, Yes: 2 | No |
All three choices of agree here — the applicant with income 32 and debt ratio 50 is predicted not to default, since the closest analogues (, a similarly low-income, low-debt-ratio applicant) did not default. Note how nearly flips: two of the five neighbors are the "Yes" applicants and , illustrating how increasing pulls in more distant, less relevant points and can shift or destabilize the prediction — exactly the bias increase the theory predicts. For a regression flavor of the same data (say we instead predict a continuous default risk score with values ), a prediction would be
again dominated by the two truly close points but nudged upward by the more distant but risky .
Common pitfalls & traps
| Pitfall | Why it happens | Fix |
|---|---|---|
| Forgetting to scale features | Distance is dominated by whichever feature has the largest numeric range | Standardize (zero mean, unit variance) or min-max scale before computing distances |
| Choosing by training accuracy | always achieves zero training error (each point is its own nearest neighbor) but overfits badly | Choose via cross-validation on held-out data |
| Using -NN naively in high dimensions | The curse of dimensionality: in high- spaces, distances between all points concentrate, so "nearest" and "farthest" become nearly indistinguishable | Reduce dimensionality first (PCA, feature selection) or use a learned/domain-appropriate distance |
| Ignoring class imbalance | Majority vote is biased toward the more frequent class when is large, since a plurality of neighbors from the sheer background frequency, not true similarity, can dominate | Use distance-weighted voting, or resample/reweight classes |
| Even in binary classification | Ties in the vote must be broken arbitrarily, adding instability | Prefer odd , or break ties using the single nearest neighbor |
| Treating brute-force search as "free" | per query seems fine for small data but becomes a bottleneck at scale (millions of queries against millions of points) | Use approximate nearest-neighbor structures (k-d tree, ball tree, or approximate methods like LSH/HNSW) in production |
| Leaking test data into distance computation | Standardizing using statistics computed over the full dataset (train+test) leaks test information | Fit scaling parameters on training data only, then apply to test/query points |
Pioneers & history
Origins · 1 minEvelyn Fix and how this was discovered
Evelyn Fix, working with Joseph Hodges at UC Berkeley for the US Air Force School of Aviation Medicine, wrote the 1951 unpublished technical report that first formalized nonparametric discrimination by nearest neighbors — the origin of what became k-NN. Their work went largely unrecognized for years before being properly credited as foundational to nonparametric statistics.
Where this matters
k-NN's direct descendants are everywhere in industrial machine learning even when the name "k-NN" doesn't appear on the label. Recommender systems use nearest-neighbor lookups over user or item embeddings to suggest products, songs, or videos. Image and face-recognition retrieval systems embed images into vector spaces and then run (approximate) nearest-neighbor search to find matches — the same core operation as k-NN classification, but at a scale where brute force is replaced by structures like HNSW or product quantization. Anomaly detection systems flag points whose nearest neighbors are unusually far away. In bioinformatics, k-NN imputes missing gene-expression values from similar samples. Beyond direct use, k-NN is the pedagogical bridge to more advanced methods: understanding how it weights neighbors by distance leads naturally into Kernels and the Kernel Trick, where a smooth weighting function (a kernel) replaces the hard "in the k nearest or not" cutoff, and into kernel density estimation, local regression (LOESS), and Gaussian processes, all of which generalize the same "local similarity implies local averaging" principle that k-NN teaches in its simplest form. Understanding k-NN also builds direct intuition for the Bias–Variance Tradeoff and for probability concepts underlying Bayes-optimal classification, both essential for evaluating any supervised learning method.
Ask the tutor: How does replacing the hard k-nearest cutoff with a smooth distance-based weighting function turn k-NN into a kernel method?
Is k-NN a "trained" model in the same sense as logistic regression or a neural network?
Not really. k-NN has no parameters that are fit by minimizing a loss function during a training phase; it simply stores the training data (and perhaps builds a spatial index for faster search). All the "work" traditionally associated with training — combining information across examples to make a compact decision rule — is deferred to prediction time, when neighbors are searched and aggregated. This is why k-NN is called a lazy or instance-based learner, in contrast to eager learners like linear models or trees that compress the training set into a fixed set of parameters before ever seeing a query point.
How should I choose k in practice?
Use cross-validation: split the training data into folds, try a range of candidate values (commonly odd numbers from 1 up to some fraction of ), and pick the that minimizes average validation error across folds. Never choose using training-set accuracy alone, since trivially achieves zero training error by definition (each training point is its own nearest neighbor) while typically overfitting. A common heuristic starting point is , but this should be treated as a starting guess to validate, not a rule.
Which distance metric should I use?
Euclidean distance () is the default for continuous, roughly isotropic features after standardization. Manhattan distance () is more robust to outliers in individual coordinates and is often preferred in high-dimensional or grid-like feature spaces. Cosine distance (or cosine similarity) is standard for high-dimensional sparse vectors such as text represented as term-frequency vectors, since it measures orientation rather than magnitude. For categorical or mixed data, specialized metrics like Hamming distance (categorical) or Gower's distance (mixed types) are used instead of raw Euclidean distance.
Does k-NN work well in high dimensions?
Generally, no, without modification. As dimensionality increases, the relative contrast between the nearest and farthest neighbor distances shrinks toward zero for many common data distributions, a phenomenon known as the curse of dimensionality. This means the "neighbors" k-NN finds become less meaningfully close than they appear. Practitioners typically apply dimensionality reduction (PCA, autoencoders, or supervised feature selection) or work in a learned embedding space before applying k-NN, rather than running it directly on hundreds of raw features.
How is k-NN different from k-means clustering?
They share a name pattern but solve different problems. k-NN is a supervised algorithm: it uses labeled training data to predict labels for new points via neighbor voting or averaging. k-means is unsupervised: it partitions unlabeled data into clusters by iteratively assigning points to the nearest of cluster centroids and updating those centroids, with no labels involved at all. The "k" means something different in each: in k-NN it is the number of neighbors consulted per query; in k-means it is the number of clusters to discover.
Can k-NN be used for regression, not just classification?
Yes. Instead of a majority vote over the k nearest neighbors' class labels, k-NN regression averages (or takes a distance-weighted average of) their continuous target values. The same bias–variance logic applies: small gives a low-bias, high-variance, noisy-looking regression function that tracks individual training points closely, while large gives a smoother, higher-bias, lower-variance function that approaches the global mean as approaches .
Why is k-NN prediction expensive compared to a linear model, and what fixes this?
A linear model compresses all training information into a fixed-size weight vector during training, so prediction only costs regardless of how large the training set was. k-NN keeps the entire dataset around and must search it — at least implicitly — for every single prediction, costing per query in the brute-force case. Spatial index structures like k-d trees or ball trees reduce this to roughly per query in low dimensions by pruning large regions of space, and approximate methods like locality-sensitive hashing or HNSW graphs trade a small amount of accuracy for major speedups at web scale.