Training pairs (Xi,yi), i=1..n, Xi∈Rm, yi∈{1,…,c}, c≥2. Test point X0. Distance ρ (default Euclidean).
Python helpers — run once, the checks below reuse them
import numpy as npdef knn(X, y, x0, k): """Plain kNN vote. Returns (label, sorted distances of the k neighbours).""" d = np.linalg.norm(np.asarray(X, float) - x0, axis=1) idx = np.argsort(d, kind="stable")[:k] labs, cnt = np.unique(np.asarray(y)[idx], return_counts=True) return labs[cnt.argmax()], d[idx]def dudani(d): """Dudani weights for distances d sorted ascending.""" d = np.asarray(d, float) return np.ones_like(d) if d[-1] == d[0] else (d[-1] - d) / (d[-1] - d[0])def tknn(seq, beta): """Tweaked kNN on a list of neighbour labels (nearest first). Returns (label, L) or (None, None).""" for L in range(beta, len(seq) + 1): c = sorted(np.unique(seq[:L], return_counts=True)[1], reverse=True) + [0] if c[0] - c[1] == beta: return max(set(seq[:L]), key=seq[:L].count), L return None, None
C23. The kNN Decision Rule
Intuition
“Tell me who your neighbours are and I will tell you who you are.” Find the k training points closest to the new point and let them vote. Like asking the 3 nearest shops whether a new product sells — you trust people who live closest.
x2
6 | B ← B cluster
5 | B B
|
2 | ●? ← query (k=3): neighbours A(1.0) A(1.4) B(4.2) → A
1 | A A
+------------→ x1
Algorithm (lecture)
Compute ρ(X0,Xi) for all i.
Sort the distances in non-decreasing order.
Take the first k (the k nearest neighbours).
Let Lj be the number of those k points in class j. Assign X0 to class p if Lp≥Lj∀j=p. Ties are broken arbitrarily.
Geometrically, the neighbourhood is the closed disk of radius rk=ρ(X0,its kth nearest neighbour).
Mathematical facts
Choice of k: no universal rule; estimate by cross-validation (C13). Small k ⇒ low bias, high variance (jagged boundary); large k ⇒ smoother, may swamp small classes.
1-NN asymptotics (Cover & Hart 1967): as n→∞, the 1-NN error is at most twice the Bayes errorR∗. More precisely, for two classes R1NN≤2R∗(1−R∗)≤2R∗.
Cost: no training, O(nm) per query.
Derivation of the 1-NN limit (two classes)
Let η(x)=P(w1∣x). As n→∞ the nearest neighbour x′ of x converges to x, so its label is an independent draw with P(w1)=η(x). 1-NN errs when the test label and the neighbour’s label differ:
e1NN(x)=η(1−η)+(1−η)η=2η(1−η),eBayes(x)=min(η,1−η).
Let r=min(η,1−η); then 2η(1−η)=2r(1−r)≤2r. Taking expectations (with R∗=E[r]): R1NN=2E[r]−2E[r2]≤2R∗−2(R∗)2=2R∗(1−R∗), because Jensen gives E[r2]≥(E[r])2. ∎
Key insights
Distance function and feature scaling dominate the behaviour.
Majority voting is unreliable when the top two classes are nearly tied (the lecture’s motivation for the variants C24–C25).
Worked examples
Example 1 — Very Easy · Healthy or diseased plant?
Problem: Two leaf-sensor readings per plant. Training: (1,1) A, (2,1) A, (5,5) B, (6,5) B, (5,6) B (A = healthy, B = diseased). Classify (2,2) with k=3 (Euclidean).
Asked: Class.
Concept: kNN.
Approach: Distances, sort, vote.
Solution:d(1,1)=1.414; d(2,1)=1; d(5,5)=4.243; d(6,5)=5; d(5,6)=5. Sorted: (2,1)A(1),(1,1)A(1.414),(5,5)B(4.243). Votes: A = 2, B = 1.
Final answer: A.
Python check
X = [(1,1), (2,1), (5,5), (6,5), (5,6)]; y = list("AABBB")print(knn(X, y, np.array([2, 2]), 3)) # ('A', [1. 1.414 4.243])
Key lesson
Only the k closest matter; the two B points at distance 5 never vote.
Example 2 — Easy · The vote flips with k
Problem: The sorted neighbour labels of X0 (nearest first) are y1,y2,y1,y2,y2,y1,y1,y2,y1. Classify for k=5,6,7,9.
Asked: Four decisions.
Concept: Dependence on k.
Approach: Count in prefixes.
Solution:
k
y1
y2
decision
5
2
3
y2
6
3
3
tie
7
4
3
y1
9
5
4
y1
Final answer:y2, tie, y1, y1.
Key lesson
The prediction flips with k when the vote is nearly even.
Example 3 — Moderate · How good can 1-NN be?
Problem: Two classes with Bayes error R∗=0.05. Bound the asymptotic 1-NN error. Repeat for R∗=0.3.
The bound is tight when R∗ is small, loose when large (it cannot exceed 0.5).
Example 4 — Hard · Why you must scale features
Problem: Features (age in years, income in ₹). Training: A=(25,50500), B=(30,52000). Test (30,50000). Feature standard deviations: age 5, income 10000. Classify by 1-NN raw and after standardising (divide differences by the std).
Asked: Two decisions.
Concept: Feature scaling.
Approach: Compute both distances twice.
Solution:Raw:dA=52+5002=500.02; dB=0+20002=2000 ⇒ A. Scaled:ΔA=(1,−0.05), dA=1.0012; ΔB=(0,−0.2), dB=0.2 ⇒ B.
Final answer: Raw → A; scaled → B.
Python check
a = np.array([(25 - 30) / 5, (50500 - 50000) / 10000]); b = np.array([0, 2000 / 10000])print(np.linalg.norm(a), np.linalg.norm(b)) # 1.0012 0.2 -> B
Key lesson
Without normalisation the large-unit feature (income) is the only feature that matters.
Example 5 — Very Hard · Cover–Hart on a two-region world
Problem: Half of the input space has η=P(w1∣x)=0.9, the other half η=0.5. Compute (a) the Bayes error, (b) the asymptotic 1-NN error, (c) 2R∗(1−R∗), and confirm (b) ≤ (c) ≤2R∗.
Asked: Three numbers and verification.
Concept: Cover–Hart derivation.
Approach: Local errors, then average.
Solution: (a) Local Bayes: min(0.9,0.1)=0.1 and 0.5. R∗=21(0.1)+21(0.5)=0.3. (b) Local 1-NN: 2(0.9)(0.1)=0.18 and 2(0.5)(0.5)=0.5. R1NN=21(0.18)+21(0.5)=0.34. (c) 2(0.3)(0.7)=0.42; 2R∗=0.6. Chain: 0.34≤0.42≤0.6 ✓.
Final answer:R∗=0.30, R1NN=0.34, bound 0.42.
region
η
Bayes min(η,1−η)
1-NN 2η(1−η)
half 1
0.9
0.10
0.18
half 2
0.5
0.50
0.50
average
0.30
0.34
Key lesson
1-NN pays extra only where the posterior is neither pure nor 50/50.
Common mistakes
Not scaling features.
Using even k in 2-class problems (ties).
Believing 1-NN error is always twice Bayes (it is an upper bound).
Exam traps
Ties are broken arbitrarily.
“Optimal k” is found by cross-validation; there is no formula.
A neighbour 1 cm away should speak louder than one 10 km away. Give each of the k neighbours a weight that decreases with distance.
Formal definition (Dudani 1976, as in the lecture)
Let X1,…,Xk be the k nearest neighbours sorted by distance dj=ρ(Xj,X0), so d1≤⋯≤dk.
wj=⎩⎨⎧dk−d1dk−dj,1,dk=d1,dk=d1.
Assign X0 to the class whose neighbours’ weights sum to the greatest value.
weight
1.0 |●
| ●
| ● weights fall linearly from 1 (nearest)
0.0 +-----------●→ d to 0 (k-th neighbour)
d1 d2 dk
Properties
w1=1 (nearest) and wk=0 (farthest), linear in between.
It reduces sensitivity to the arbitrary cut-off, but k must still be chosen.
Worked examples
Example 1 — Very Easy · Compute the weights
Problem: Distances d=(1,2,4) for k=3. Weights?
Asked:w1,w2,w3.
Concept: Linear weighting.
Approach:d1=1,dk=4.
Solution:w1=34−1=1; w2=34−2=0.6667; w3=0.
Final answer:(1,0.667,0).
Key lesson
The farthest neighbour always gets weight 0.
Example 2 — Easy · Plain vs weighted vote
Problem: Neighbour labels (nearest first) A,B,B with the distances above. Plain vote vs weighted vote.
Asked: Two classes.
Concept: Weighted voting.
Approach: Sum the weights per class.
Solution: Plain: A = 1, B = 2 ⇒ B. Weighted: A =1; B =0.6667+0=0.6667 ⇒ A.
Final answer: Plain → B; weighted → A.
Python check
w = dudani([1, 2, 4]); labels = np.array(list("ABB"))print(w, {c: w[labels == c].sum() for c in "AB"}) # [1. .667 0.] {'A': 1.0, 'B': 0.667}
Key lesson
One very close point can outweigh two distant ones.
Example 3 — Moderate · All distances equal
Problem:d=(2,2,2,2,2) with labels A,A,B,B,B. Weights and decision.
Asked: Weights, class.
Concept: Degenerate case dk=d1.
Approach: Use the "1" branch.
Solution: All wj=1 ⇒ A =2, B =3 ⇒ B (ordinary kNN).
Final answer: B.
Key lesson
The formula degrades gracefully to majority vote.
Example 4 — Hard · Five neighbours
Problem:k=5 with distances (0.5,0.6,1.0,2.0,2.5) and labels A,B,B,A,A. Compute weights and compare plain majority vs weighted.
Asked: Weights, both decisions.
Concept: Weighted kNN.
Approach:d1=0.5, d5=2.5, denominator 2.0.
Solution:w=(1,0.95,0.75,0.25,0). Class A: 1+0.25+0=1.25. Class B: 0.95+0.75=1.70. Plain majority: A =3, B =2 ⇒ A. Weighted ⇒ B.
Final answer: Plain → A; weighted → B.
Python check
w = dudani([.5, .6, 1.0, 2.0, 2.5]); lab = np.array(list("ABBAA"))print(w, {c: round(w[lab == c].sum(), 2) for c in "AB"}) # [1 .95 .75 .25 0] {'A': 1.25, 'B': 1.7}
Key lesson
Close neighbours (B, B) outweigh far ones (A, A).
Example 5 — Very Hard · Weighted kNN can collapse to 1-NN
Problem: Show (i) the weighted rule with k neighbours ignores the kth, so it uses only the k−1 nearer neighbours; (ii) construct k=3 distances where weighted kNN is identical to 1-NN regardless of the other labels.
Asked: Proof and construction.
Concept: Weight structure.
Approach: Algebra.
Solution: (i) wk=0 always, so Xk never contributes. The remaining weights are dk−d1dk−dj, j<k; they depend on dk — so k still controls the scale of the weighting. (ii) Let d=(1,5,5.001) with labels A,B,B. Weights: w1=1; w2=4.0010.001=0.00025; w3=0. Class A =1; B =0.00025 ⇒ A, the 1-NN label, even though a majority of 3 says B.
Final answer: Weighted kNN can behave like 1-NN when the nearest neighbour is much closer than the rest.
Python check
print(dudani([1, 5, 5.001])) # [1. 0.00025 0.]
Key lesson
The weighting depends on relative distances; an outlier in distance can make the rule effectively 1-NN.
Common mistakes
Forgetting wk=0.
Using 1/d weights and calling them the lecture formula.
Exam traps
Weights use dk−dj in the numerator, dk−d1 in the denominator.
You still need a valid k.
Connections: C23, C25.
Mastery checklist
Compute linear distance weights.
Explain when weighted and plain kNN disagree.
C25. Tweaked kNN (TkNN): Bounded Majority Voting
Intuition
Instead of fixing k, keep widening the neighbourhood until the winner leads the runner-up by a marginβ. If no margin is ever reached, refuse to classify. A single, more interpretable parameter β replaces k.
flowchart TD
S[Sort neighbours] --> I["L ← β"]
I --> C{"margin = L_max1 − L_max2 = β ?"}
C -->|yes| O[Output majority class]
C -->|no| G["L ← L+1"]
G --> E{"L > n ?"}
E -->|no| C
E -->|yes| U[Unclassified]
Algorithm (lecture)
Compute and sort distances ρ(X0,Xi).
L←β (a positive integer).
Take the first L neighbours; let Lj be the class counts. Lmax1=maxjLj; Lmax2 = second largest.
If Lmax1−Lmax2=β ⇒ output the majority class. Else L←L+1 and repeat. If L>n ⇒ X0 is unclassified.
Properties
β=1 ⇒ the rule equals 1-NN (at L=1 the margin is already 1).
Larger β ⇒ more cautious, more abstentions.
Choose β by cross-validation. It does not consider the quality of the voting neighbours (open problem noted in the lecture).
Worked examples
Example 1 — Very Easy · β = 1 is 1-NN
Problem: Show TkNN with β=1 equals 1-NN.
Asked: Proof.
Concept: Margin definition.
Approach: Start at L=1.
Solution: At L=β=1: the top class has count 1, every other has 0 ⇒ margin =1=β ⇒ stop, output the class of the nearest neighbour.
Final answer: Yes.
Key lesson
β=1 is the most permissive setting.
Example 2 — Easy · The alternating sequence
Problem: The sequence (nearest first) y1,y2,y1,y2,y2,y1,y1,y2,y1 (the lecture’s 9.1). Run TkNN with β=1 and β=2.
The margin is against the second best class, not the average of the others.
Example 5 — Very Hard · Why the margin is exactly β
Problem: Show that TkNN can only ever stop when L≥β and that the margin at stopping is exactlyβ (not larger). Then argue why overshooting is impossible.
Asked: Two proofs.
Concept: Margin dynamics.
Approach: One-step margin changes.
Solution: The margin ML=Lmax1−Lmax2 is at most L (all neighbours in one class), so stopping requires L≥β — matching the initial L=β. When L increases by 1, exactly one class count increases by 1: if it is the leader, M rises by 1; if it is the runner-up, M falls by 1; otherwise M is unchanged. So ∣ΔM∣≤1 and M cannot jump over β: the first time M≥β it equals β. (At the start L=β we have M≤β.)
Final answer: The stopping margin is exactly β.
Key lesson
The test "=β" is equivalent to "≥β", because M moves in unit steps.
Common mistakes
Starting with L=1 instead of L=β (harmless, but not the lecture’s algorithm).