K-Nearest Neighbours
The simplest possible ML algorithm — predict based on what your neighbours look like. Distance metrics, the curse of dimensionality, and when KNN actually works.
KNN has no training phase. No weights. No boundary. Just one idea: similar inputs should produce similar outputs.
A new customer joins Amazon. They are 24 years old, live in Seattle, buy mostly electronics, and spend $3,000 per order on average. What products should you recommend to them?
The simplest possible answer: find the 5 existing customers who are most similar to this new customer. Look at what they bought and liked. Recommend those. You do not need a trained model, learned weights, or a decision boundary. You just need a way to measure similarity and enough historical data to look up neighbours from.
That is the entire KNN algorithm. For a new query point, find the k training points nearest to it (by some distance measure), and predict based on what those neighbours say. For classification: majority vote among the k neighbours. For regression: average of the k neighbours' values. No training. No parameters learned from data. Every prediction looks up the training set from scratch.
You move to a new city and want to know if a neighbourhood is safe. You do not build a statistical model of crime rates. You ask the 5 people who live closest to that neighbourhood what they think. If 4 out of 5 say it is safe, you conclude it is safe. That is KNN — ask your nearest neighbours and take a vote.
The key questions are: how do you measure "closeness"? How many neighbours k should you ask? And what happens when the neighbourhood is crowded in some dimensions but empty in others — the curse of dimensionality. This module answers all three.
How KNN makes a prediction — four steps, no hidden magic
KNN's prediction process is completely transparent. Every step can be inspected and understood. There are no learned parameters — the algorithm memorises the entire training set and consults it at prediction time.
Distance metrics — which one to use and why it matters
KNN's entire behaviour depends on how you measure distance. The same dataset can produce completely different predictions depending on which distance metric you choose. The default — Euclidean distance — works well in most cases. But understanding the alternatives lets you make better choices for specific problem types.
Choosing k — the bias-variance trade-off made visual
The value of k directly controls how much the model generalises versus memorises. Small k means the prediction is based on very few neighbours — highly sensitive to noise. Large k means the prediction is based on many neighbours — smoother but potentially missing local structure. This is the classic bias-variance trade-off, and KNN makes it unusually visible.
The curse of dimensionality — KNN's fundamental limitation
KNN works beautifully in 2 or 3 dimensions. It falls apart in 100 dimensions. The reason is counterintuitive but important — in high-dimensional space, distances lose their meaning. All points become approximately equidistant from each other. When every point is roughly the same distance from every other point, "nearest neighbours" is a meaningless concept.
Imagine searching for the nearest person to you on a street (1D). Easy — look left and right. Now on a field (2D). Harder, but doable. Now in a building (3D). Now in a 100-dimensional space where each dimension is one feature of a customer profile.
In 100 dimensions, the "nearest" customer might actually be almost as far away as the furthest customer. The ratio of nearest-to-furthest distance approaches 1 as dimensions grow. All distances become equally large and equally meaningless.
In d dimensions, to maintain the same neighbourhood density you need exponentially more data. To have 10 neighbours within a distance of 0.1 in 1D, you might need ~100 points. In 10D, you need ~10 billion points for the same density. In practice, your data becomes infinitely sparse.
KNN for classification — majority vote with probabilities
KNN classification works identically to regression — find k nearest neighbours and aggregate. For classification the aggregation is a majority vote: whichever class appears most among the k neighbours wins. Probabilities come naturally — the fraction of neighbours belonging to each class.
When KNN wins — and when it does not
KNN is not a general-purpose algorithm in modern ML. It is slow at prediction time, sensitive to irrelevant features, and breaks down in high dimensions. But it has genuine use cases where it outperforms more complex algorithms.
Speed up KNN for production: approximate nearest neighbours
Every common KNN error — explained and fixed
Where KNN survives in production — and where FAISS takes over
Nobody runs sklearn's KNeighborsClassifier against a training set of ten million rows in a live request path. But "nearest neighbour search" as an idea is everywhere in production ML — recommendation engines, fraud review queues, and visual search are all, underneath, asking the same question KNN asks: what is this new thing most similar to? The part that changes at scale is not the idea, it is the data structure used to answer it.
Reference set under roughly 50,000 points and a request latency budget of tens of milliseconds — plain KNN with a ball tree or KD-tree is simplest and exact. No reason to add FAISS as a dependency.
Reference set in the millions, or a request latency budget under about 10ms — move to an approximate nearest neighbour index. Exact brute-force search over millions of vectors cannot hit that latency no matter which language it is written in.
The result needs to be explainable or auditable (compliance review, fraud case comparison) — prefer exact KNN even if it means running slower or offline in batch, since ANN indexes trade a small amount of recall for speed and can occasionally miss the true nearest neighbour.
The embedding set changes constantly (new items added hourly) — prefer an ANN structure that supports incremental inserts (HNSW) over one that needs a full index rebuild for every batch of new vectors (IVF-based FAISS indexes).
Five things people get wrong about KNN
Calling KNN a lazy learner is true only about training — fitting a model means nothing more than storing the training set in memory, which is essentially free. But that cost has to go somewhere, and it goes entirely into prediction: every single query has to compute its distance to some or all of the training points before it can produce an answer. On a large training set with brute-force search that is an O(n) computation per prediction, which can dominate a latency budget in exactly the situations where fast predictions matter most — real-time serving at scale. Tree-based indexes like a ball tree or KD-tree, or approximate nearest-neighbor libraries like FAISS, exist specifically because no training cost does not mean no cost.
That is only true in the extreme case of k=1, where every prediction is literally the label of the single nearest training point, which does produce perfect training accuracy and a jagged, overfit decision surface. For any k greater than one, KNN is averaging or voting across a local neighborhood of points, which is a genuine form of generalization — it smooths out individual noisy examples in favor of what the local region as a whole suggests. The size of k directly controls how much smoothing happens, from essentially no generalization at k=1 to heavy generalization as k grows toward the size of the dataset, which is the same bias-variance trade-off every other model faces, just made unusually visible.
For KNN, scaling is not a generic best practice, it is a mathematical necessity created directly by how the algorithm computes distance. Euclidean distance sums squared differences across every feature, so a feature measured in the thousands contributes overwhelmingly more to that sum than a feature measured between zero and one, and the nearest neighbor the algorithm finds ends up determined almost entirely by whichever feature happens to have the largest raw scale. Contrast this with a decision tree, which splits on a per-feature threshold and never combines features into a single distance calculation — multiplying every value of one feature by a thousand changes nothing about which splits a tree chooses. KNN's need for scaling comes from its specific mechanism, not from a general rule that applies equally to every algorithm.
Larger k does reduce variance by averaging over more neighbors, but that is only half of the bias-variance trade-off — it also increases bias by pulling in points that are farther away and less representative of the query point's actual local neighborhood. Pushed far enough, a very large k washes out real local structure entirely and the model starts to resemble one that just predicts the global average or majority class regardless of the input, which is a form of underfitting just as damaging as k=1's overfitting. There is no universally safe direction to move k in — the right value depends on the noise level and structure of the specific dataset, which is why it should be chosen by cross-validation rather than by a rule of thumb.
Every additional feature adds another term to the distance calculation, and in high-dimensional space this backfires: as dimensions increase, the ratio between the closest and farthest neighbor's distance shrinks toward one, meaning every point starts to look approximately equidistant from every other point. Once that happens, "nearest neighbor" stops carrying real information, and predictions degrade toward random guessing regardless of how much genuinely predictive signal is buried in a subset of those features. Irrelevant or redundant features are actively harmful to KNN in a way they are not for models that can learn to downweight them, which is why reducing dimensionality with PCA, or doing feature selection first, often improves KNN more than adding data does.
K-Nearest Neighbours — 5 questions interviewers actually ask
A lazy learner defers essentially all computation from training time to prediction time. Fitting a KNN model means storing the training set in memory — no weights are learned, no boundary is computed, so training is effectively instantaneous. The cost shows up on the other side: every prediction has to search for the nearest neighbors among the stored training points, which is an O(n) operation per query with brute-force search. This is the opposite trade-off from something like a neural network, which spends heavy computation upfront during training so that prediction is a fast forward pass. In production, that means KNN can be a poor fit for high-throughput, low-latency serving unless you invest in an indexing structure like a ball tree, KD-tree, or an approximate nearest-neighbor library, precisely to move some of that deferred cost back out of the request path.
It comes down to how each model actually uses feature values. KNN computes distance by summing squared differences across all features simultaneously, so a feature on a scale of thousands will dominate that sum and effectively decide which points count as "near," regardless of how informative the smaller-scale features actually are. A decision tree instead picks a threshold on one feature at a time — it asks whether a value is above or below some cutoff — and that decision doesn't change if you multiply the entire feature by a constant, because the relative ordering of values within that feature is unaffected. So scaling isn't a blanket rule that all algorithms need; it's specifically required by any algorithm, like KNN, whose core computation combines raw feature magnitudes across dimensions.
k directly controls the bias-variance trade-off. At k=1, the model has zero bias and maximum variance — every prediction is just the single nearest training point's label, which produces perfect training accuracy but a decision surface that has memorized noise and generalizes poorly. At the other extreme, k equal to the size of the dataset has maximum bias and zero variance — every prediction collapses to the global average or majority class, ignoring the query point's actual location entirely. In practice I'd start from a rule of thumb like k equal to the square root of the training set size, then tune it properly with cross-validation across a range of odd values for binary classification to avoid tie votes, picking whichever k minimizes cross-validated error rather than training error.
As the number of features grows, the volume of the space grows exponentially, but the amount of data you have stays fixed, so the data becomes exponentially sparser relative to the space it lives in. The concrete symptom for KNN is that distances stop being discriminative — the ratio between the nearest neighbor's distance and the farthest point's distance approaches one as dimensions increase, meaning every point starts to look roughly equidistant from every other point. Since KNN's entire mechanism depends on "nearest" being a meaningful concept, this hits it harder than most algorithms — a tree-based model can simply ignore an uninformative feature by never splitting on it, but KNN's distance calculation folds every feature in by default. The practical fix is dimensionality reduction, like PCA, or feature selection, before fitting KNN on anything with more than roughly twenty features.
I would not use brute-force search in production if latency matters — I'd start with a tree-based index like a ball tree or KD-tree, which reduces average query cost from O(n) to roughly O(log n) for low-to-moderate dimensional data. If the dataset is very large or dimensionality is too high for tree indexes to help, I'd move to an approximate nearest-neighbor library like FAISS or Annoy, which trade a small amount of accuracy for order-of-magnitude speedups by not guaranteeing the exact nearest neighbors. I'd also push to reduce dimensionality first with PCA both for the curse-of-dimensionality reason and because lower-dimensional data makes tree-based indexes far more effective. And I'd reconsider whether KNN is the right algorithm at all — if the latency requirement is strict, a model that shifts computation to training time, like a gradient-boosted tree or a neural network, often fits the constraint better than any way of speeding up KNN itself.
KNN asks its neighbours. Naive Bayes asks Bayes' theorem.
KNN is a distance-based algorithm — it makes no assumptions about the distribution of data, it just measures proximity. Naive Bayes is the opposite — it is a probabilistic algorithm that makes explicit assumptions about how features are distributed, then uses Bayes' theorem to compute the probability of each class. Despite the "naive" independence assumption that is almost always wrong, it works surprisingly well for text classification and spam detection.
Bayes theorem applied to classification. Why the naive independence assumption works surprisingly well for spam and document classification.
🎯 Key Takeaways
- ✓KNN has no training phase — "training" means storing the data. All computation happens at prediction time: find k nearest training points, aggregate their labels. This makes training instant but prediction slow on large datasets.
- ✓KNN is one of the most scaling-sensitive algorithms in all of sklearn. Unscaled features completely break distance calculations. Always put StandardScaler in a Pipeline before any KNN model — this is the single most impactful thing you can do.
- ✓k controls the bias-variance trade-off directly. k=1 memorises every training point (zero bias, maximum variance, 100% training accuracy). k=n predicts the global average (maximum bias, zero variance). Start with k=sqrt(n_train) and tune with cross-validation.
- ✓Use weights="distance" instead of the default weights="uniform". Closer neighbours are more informative than distant ones — distance weighting consistently improves KNN performance at almost no cost.
- ✓The curse of dimensionality is KNN's fundamental limit. In high dimensions all points become approximately equidistant, making nearest neighbours meaningless. For datasets with more than ~20 features, apply PCA to reduce dimensions before KNN.
- ✓KNN genuinely wins at recommendation (collaborative filtering), anomaly detection (far from all neighbours = anomaly), and low-dimensional non-linear problems. For large datasets, tabular ML, or high-dimensional data, XGBoost or Random Forest will almost always outperform it.
Discussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.