Add k-nearest neighbors algorithm. · valwebd/javascript-algorithms@4623bb9 · GitHub
Skip to content

Commit 4623bb9

Browse files
committed
Add k-nearest neighbors algorithm.
1 parent b13291d commit 4623bb9

7 files changed

Lines changed: 190 additions & 126 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion

src/algorithms/ML/KNN/README.md

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/algorithms/ML/KNN/__test__/knn.test.js

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/algorithms/ML/KNN/knn.js

Lines changed: 0 additions & 60 deletions
This file was deleted.

src/algorithms/ml/knn/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# k-Nearest Neighbors Algorithm
2+
3+
The **k-nearest neighbors algorithm (k-NN)** is a supervised Machine Learning algorithm. It's a classification algorithm, determining the class of a sample vector using a sample data.
4+
5+
In k-NN classification, the output is a class membership. An object is classified by a plurality vote of its neighbors, with the object being assigned to the class most common among its `k` nearest neighbors (`k` is a positive integer, typically small). If `k = 1`, then the object is simply assigned to the class of that single nearest neighbor.
6+
7+
The idea is to calculate the similarity between two data points on the basis of a distance metric. [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance) is used mostly for this task.
8+
9+
![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
10+
11+
_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_
12+
13+
The algorithm is as follows:
14+
15+
1. Check for errors like invalid data/labels.
16+
2. Calculate the euclidean distance of all the data points in training data with the classification point
17+
3. Sort the distances of points along with their classes in ascending order
18+
4. Take the initial `K` classes and find the mode to get the most similar class
19+
5. Report the most similar class
20+
21+
Here is a visualization of k-NN classification for better understanding:
22+
23+
![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/e7/KnnClassification.svg)
24+
25+
_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_
26+
27+
The test sample (green dot) should be classified either to blue squares or to red triangles. If `k = 3` (solid line circle) it is assigned to the red triangles because there are `2` triangles and only `1` square inside the inner circle. If `k = 5` (dashed line circle) it is assigned to the blue squares (`3` squares vs. `2` triangles inside the outer circle).
28+
29+
Another k-NN classification example:
30+
31+
![KNN Visualization 2](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)
32+
33+
_Image source: [GeeksForGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)_
34+
35+
Here, as we can see, the classification of unknown points will be judged by their proximity to other points.
36+
37+
It is important to note that `K` is preferred to have odd values in order to break ties. Usually `K` is taken as `3` or `5`.
38+
39+
## References
40+
41+
- [k-nearest neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import kNN from '../kNN';
2+
3+
describe('kNN', () => {
4+
it('should throw an error on invalid data', () => {
5+
expect(() => {
6+
kNN();
7+
}).toThrowError('Either dataSet or labels or toClassify were not set');
8+
});
9+
10+
it('should throw an error on invalid labels', () => {
11+
const noLabels = () => {
12+
kNN([[1, 1]]);
13+
};
14+
expect(noLabels).toThrowError('Either dataSet or labels or toClassify were not set');
15+
});
16+
17+
it('should throw an error on not giving classification vector', () => {
18+
const noClassification = () => {
19+
kNN([[1, 1]], [1]);
20+
};
21+
expect(noClassification).toThrowError('Either dataSet or labels or toClassify were not set');
22+
});
23+
24+
it('should throw an error on not giving classification vector', () => {
25+
const inconsistent = () => {
26+
kNN([[1, 1]], [1], [1]);
27+
};
28+
expect(inconsistent).toThrowError('Inconsistent vector lengths');
29+
});
30+
31+
it('should find the nearest neighbour', () => {
32+
let dataSet;
33+
let labels;
34+
let toClassify;
35+
let expectedClass;
36+
37+
dataSet = [[1, 1], [2, 2]];
38+
labels = [1, 2];
39+
toClassify = [1, 1];
40+
expectedClass = 1;
41+
expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass);
42+
43+
dataSet = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]];
44+
labels = [1, 2, 1, 2, 1, 2, 1];
45+
toClassify = [1.25, 1.25];
46+
expectedClass = 1;
47+
expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass);
48+
49+
dataSet = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]];
50+
labels = [1, 2, 1, 2, 1, 2, 1];
51+
toClassify = [1.25, 1.25];
52+
expectedClass = 2;
53+
expect(kNN(dataSet, labels, toClassify, 5)).toBe(expectedClass);
54+
});
55+
56+
it('should find the nearest neighbour with equal distances', () => {
57+
const dataSet = [[0, 0], [1, 1], [0, 2]];
58+
const labels = [1, 3, 3];
59+
const toClassify = [0, 1];
60+
const expectedClass = 3;
61+
expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass);
62+
});
63+
64+
it('should find the nearest neighbour in 3D space', () => {
65+
const dataSet = [[0, 0, 0], [0, 1, 1], [0, 0, 2]];
66+
const labels = [1, 3, 3];
67+
const toClassify = [0, 0, 1];
68+
const expectedClass = 3;
69+
expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass);
70+
});
71+
});

src/algorithms/ml/knn/kNN.js

Lines changed: 77 additions & 0 deletions

0 commit comments

Comments
 (0)