Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit adda5c5

Browse files
Add Euclidean Distance formula (trekhleb#602)
* Add Matrices section with basic Matrix operations (multiplication, transposition, etc.) * Add Euclidean Distance algorithm.
1 parent 8d52ae5 commit adda5c5

File tree

7 files changed

+97
-26
lines changed

7 files changed

+97
-26
lines changed

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ a set of rules that precisely define a sequence of operations.
7878
* `B` [Fast Powering](src/algorithms/math/fast-powering)
7979
* `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation
8080
* `B` [Matrices](src/algorithms/math/matrix) - matrices and basic matrix operations (multiplication, transposition, etc.)
81+
* `B` [Euclidean Distance](src/algorithms/math/euclidean-distance) - distance between two points/vectors/matrices
8182
* `A` [Integer Partition](src/algorithms/math/integer-partition)
8283
* `A` [Square Root](src/algorithms/math/square-root) - Newton's method
8384
* `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Euclidean Distance
2+
3+
In mathematics, the **Euclidean distance** between two points in Euclidean space is the length of a line segment between the two points. It can be calculated from the Cartesian coordinates of the points using the Pythagorean theorem, therefore occasionally being called the Pythagorean distance.
4+
5+
![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg)
6+
7+
## Distance formulas
8+
9+
### One dimension
10+
11+
The distance between any two points on the real line is the absolute value of the numerical difference of their coordinates
12+
13+
![One dimension formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/7d75418dbec9482dbcb70f9063ad66e9cf7b5db9)
14+
15+
### Two dimensions
16+
17+
![Two dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/9c0157084fd89f5f3d462efeedc47d3d7aa0b773)
18+
19+
### Higher dimensions
20+
21+
In three dimensions, for points given by their Cartesian coordinates, the distance is
22+
23+
![Three dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/d1d13a40a7b203b455ae6d4be8b3cce898bda625)
24+
25+
Example: the distance between the two points `(8,2,6)` and `(3,5,7)`:
26+
27+
![3-dimension example](https://www.mathsisfun.com/algebra/images/dist-2-points-3d.svg)
28+
29+
In general, for points given by Cartesian coordinates in `n`-dimensional Euclidean space, the distance is
30+
31+
![n-dimensional formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/a0ef4fe055b2a51b4cca43a05e5d1cd93f758dcc)
32+
33+
## References
34+
35+
- [Euclidean Distance on MathIsFun](https://www.mathsisfun.com/algebra/distance-2-points.html)
36+
- [Euclidean Distance on Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import euclideanDistance from '../euclideanDistance';
2+
3+
describe('euclideanDistance', () => {
4+
it('should calculate euclidean distance between vectors', () => {
5+
expect(euclideanDistance([[1]], [[2]])).toEqual(1);
6+
expect(euclideanDistance([[2]], [[1]])).toEqual(1);
7+
expect(euclideanDistance([[5, 8]], [[7, 3]])).toEqual(5.39);
8+
expect(euclideanDistance([[5], [8]], [[7], [3]])).toEqual(5.39);
9+
expect(euclideanDistance([[8, 2, 6]], [[3, 5, 7]])).toEqual(5.92);
10+
expect(euclideanDistance([[8], [2], [6]], [[3], [5], [7]])).toEqual(5.92);
11+
expect(euclideanDistance([[[8]], [[2]], [[6]]], [[[3]], [[5]], [[7]]])).toEqual(5.92);
12+
});
13+
14+
it('should throw an error in case if two matrices are of different shapes', () => {
15+
expect(() => euclideanDistance([[1]], [[[2]]])).toThrowError(
16+
'Matrices have different dimensions',
17+
);
18+
19+
expect(() => euclideanDistance([[1]], [[2, 3]])).toThrowError(
20+
'Matrices have different shapes',
21+
);
22+
});
23+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @typedef {import('../matrix/Matrix.js').Matrix} Matrix
3+
*/
4+
5+
import * as mtrx from '../matrix/Matrix';
6+
7+
/**
8+
* Calculates the euclidean distance between 2 matrices.
9+
*
10+
* @param {Matrix} a
11+
* @param {Matrix} b
12+
* @returns {number}
13+
* @trows {Error}
14+
*/
15+
const euclideanDistance = (a, b) => {
16+
mtrx.validateSameShape(a, b);
17+
18+
let squaresTotal = 0;
19+
20+
mtrx.walk(a, (indices, aCellValue) => {
21+
const bCellValue = mtrx.getCellAtIndex(b, indices);
22+
squaresTotal += (aCellValue - bCellValue) ** 2;
23+
});
24+
25+
return Number(Math.sqrt(squaresTotal).toFixed(2));
26+
};
27+
28+
export default euclideanDistance;

‎src/algorithms/math/matrix/Matrix.js‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const validate2D = (m) => {
5858
* @param {Matrix} b
5959
* @trows {Error}
6060
*/
61-
const validateSameShape = (a, b) => {
61+
exportconst validateSameShape = (a, b) => {
6262
validateType(a);
6363
validateType(b);
6464

@@ -177,7 +177,7 @@ export const t = (m) => {
177177
* @param {Matrix} m
178178
* @param {function(indices: CellIndices, c: Cell)} visit
179179
*/
180-
const walk = (m, visit) => {
180+
exportconst walk = (m, visit) => {
181181
/**
182182
* Traverses the matrix recursively.
183183
*
@@ -208,7 +208,7 @@ const walk = (m, visit) => {
208208
* @param {CellIndices} cellIndices - Array of cell indices
209209
* @return {Cell}
210210
*/
211-
const getCellAtIndex = (m, cellIndices) => {
211+
exportconst getCellAtIndex = (m, cellIndices) => {
212212
// We start from the row at specific index.
213213
let cell = m[cellIndices[0]];
214214
// Going deeper into the next dimensions but not to the last one to preserve
@@ -227,7 +227,7 @@ const getCellAtIndex = (m, cellIndices) => {
227227
* @param {CellIndices} cellIndices - Array of cell indices
228228
* @param {Cell} cellValue - New cell value
229229
*/
230-
const updateCellAtIndex = (m, cellIndices, cellValue) => {
230+
exportconst updateCellAtIndex = (m, cellIndices, cellValue) => {
231231
// We start from the row at specific index.
232232
let cell = m[cellIndices[0]];
233233
// Going deeper into the next dimensions but not to the last one to preserve

‎src/algorithms/ml/knn/__test__/knn.test.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe('kNN', () => {
2525
const inconsistent = () => {
2626
kNN([[1, 1]], [1], [1]);
2727
};
28-
expect(inconsistent).toThrowError('Inconsistent vector lengths');
28+
expect(inconsistent).toThrowError('Matrices have different shapes');
2929
});
3030

3131
it('should find the nearest neighbour', () => {

‎src/algorithms/ml/knn/kNN.js‎

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,3 @@
1-
/**
2-
* Calculates calculate the euclidean distance between 2 vectors.
3-
*
4-
* @param {number[]} x1
5-
* @param {number[]} x2
6-
* @returns {number}
7-
*/
8-
function euclideanDistance(x1, x2) {
9-
// Checking for errors.
10-
if (x1.length !== x2.length) {
11-
throw new Error('Inconsistent vector lengths');
12-
}
13-
// Calculate the euclidean distance between 2 vectors and return.
14-
let squaresTotal = 0;
15-
for (let i = 0; i < x1.length; i += 1) {
16-
squaresTotal += (x1[i] - x2[i]) ** 2;
17-
}
18-
return Number(Math.sqrt(squaresTotal).toFixed(2));
19-
}
20-
211
/**
222
* Classifies the point in space based on k-nearest neighbors algorithm.
233
*
@@ -27,6 +7,9 @@ function euclideanDistance(x1, x2) {
277
* @param {number} k - number of nearest neighbors which will be taken into account (preferably odd)
288
* @return {number} - the class of the point
299
*/
10+
11+
import euclideanDistance from '../../math/euclidean-distance/euclideanDistance';
12+
3013
export default function kNN(
3114
dataSet,
3215
labels,
@@ -42,7 +25,7 @@ export default function kNN(
4225
const distances = [];
4326
for (let i = 0; i < dataSet.length; i += 1) {
4427
distances.push({
45-
dist: euclideanDistance(dataSet[i],toClassify),
28+
dist: euclideanDistance([dataSet[i]],[toClassify]),
4629
label: labels[i],
4730
});
4831
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /