diff --git a/README.md b/README.md index d4098e4..bc8229c 100644 --- a/README.md +++ b/README.md @@ -127,12 +127,6 @@ $d(p,q)=1-\frac{\sum\limits_{i=1}^{n}{min(p_i,q_i)}}{\sum\limits_{i=1}^{n}{p_i+q Note: distance between 2 identical vectors is 0.5 ! -- `ruzicka(p, q)` - -Returns the [Ruzicka similarity](http://www.naun.org/main/NAUN/ijmmas/mmmas-49.pdf) between vectors p and q. The matching distance is `soergel`. - -$s(p,q)=\frac{\sum\limits_{i=1}^{n}{min(p_i,q_i)}}{\sum\limits_{i=1}^{n}{max(p_i,q_i)}}$ - - `tanimoto(p, q, [bitVector])` Returns the [Tanimoto distance](http://www.naun.org/main/NAUN/ijmmas/mmmas-49.pdf) between vectors p and q, and accepts the bitVector use, see the test case for an example @@ -331,6 +325,12 @@ $s(p,q)=\frac{\sum\limits_{i=1}^{n}{p_i\cdot{q_i}}}{\sum\limits_{i=1}^{n}{p_i^2} Returns the [Pearson correlation](https://en.wikipedia.org/wiki/Pearson_correlation_coefficient) between vectors p and q, i.e. the cosine similarity of the mean-centred vectors +- `ruzicka(p, q)` + +Returns the [Ruzicka similarity](http://www.naun.org/main/NAUN/ijmmas/mmmas-49.pdf), also known as the [weighted Jaccard similarity](https://en.wikipedia.org/wiki/Jaccard_index#Weighted_Jaccard_similarity_and_distance), between vectors p and q. The matching distance is `soergel`. + +$s(p,q)=\frac{\sum\limits_{i=1}^{n}{min(p_i,q_i)}}{\sum\limits_{i=1}^{n}{max(p_i,q_i)}}$ + - `dice(p, q)` Returns the [Dice similarity](http://www.naun.org/main/NAUN/ijmmas/mmmas-49.pdf) between vectors p and q diff --git a/scripts/similarity.js b/scripts/similarity.js index e19cf4c..dae5b37 100644 --- a/scripts/similarity.js +++ b/scripts/similarity.js @@ -15,7 +15,7 @@ let v10 = [-0.4, 0.4]; let v11 = [-0.6, 0.7]; for (let algorithm in distance) { - if (algorithm.match(/fidelity|harmonicMean|innerProduct|ruzicka/)) continue; + if (algorithm.match(/fidelity|harmonicMean|innerProduct/)) continue; if (algorithm.match(/minkowski/) && algorithm.match(/motyka/)) continue; // does not give a 0 with identical vector let result = { algorithm }; let callback = distance[algorithm]; diff --git a/src/distances.ts b/src/distances.ts index bad8042..8bf78a1 100644 --- a/src/distances.ts +++ b/src/distances.ts @@ -62,8 +62,6 @@ export * from './distances/pearson.ts'; export * from './distances/probabilisticSymmetric.ts'; -export * from './distances/ruzicka.ts'; - export * from './distances/soergel.ts'; export * from './distances/sorensen.ts'; diff --git a/src/similarities.ts b/src/similarities.ts index 320c627..d4318de 100644 --- a/src/similarities.ts +++ b/src/similarities.ts @@ -12,6 +12,8 @@ export * from './similarities/motyka.ts'; export * from './similarities/pearson.ts'; +export * from './similarities/ruzicka.ts'; + export * from './similarities/squaredChord.ts'; export * from './similarities/tanimoto.ts'; diff --git a/src/distances/__tests__/ruzicka.test.ts b/src/similarities/__tests__/ruzicka.test.ts similarity index 58% rename from src/distances/__tests__/ruzicka.test.ts rename to src/similarities/__tests__/ruzicka.test.ts index 661d767..ab724a0 100644 --- a/src/distances/__tests__/ruzicka.test.ts +++ b/src/similarities/__tests__/ruzicka.test.ts @@ -1,22 +1,22 @@ import { expect, test } from 'vitest'; -import { distance } from '../../index.ts'; +import { distance, similarity } from '../../index.ts'; const v1 = [0.2, 0.4, 0.3, 0.1]; const v2 = [0.3, 0.2, 0.3, 0.2]; test('should be correct', () => { - expect(distance.ruzicka(v1, v2)).toBe(2 / 3); + expect(similarity.ruzicka(v1, v2)).toBe(2 / 3); }); test('should be 1 for identical vectors, not 0 as a distance would be', () => { - expect(distance.ruzicka(v1, v1)).toBe(1); + expect(similarity.ruzicka(v1, v1)).toBe(1); expect(distance.soergel(v1, v1)).toBe(0); }); test('should grow as the vectors get more similar', () => { - const far = distance.ruzicka([1, 0], [0, 1]); - const near = distance.ruzicka([1, 0], [0.9, 0.1]); + const far = similarity.ruzicka([1, 0], [0, 1]); + const near = similarity.ruzicka([1, 0], [0.9, 0.1]); expect(far).toBe(0); expect(near).toBeCloseTo(0.818181, 5); @@ -24,15 +24,19 @@ test('should grow as the vectors get more similar', () => { }); test('should be the complement of the soergel distance', () => { - expect(1 - distance.ruzicka(v1, v2)).toBeCloseTo( + expect(1 - similarity.ruzicka(v1, v2)).toBeCloseTo( distance.soergel(v1, v2), 10, ); }); test('should be the complement of the tanimoto distance', () => { - expect(1 - distance.ruzicka(v1, v2)).toBeCloseTo( + expect(1 - similarity.ruzicka(v1, v2)).toBeCloseTo( distance.tanimoto(v1, v2), 10, ); }); + +test('should not be exported as a distance', () => { + expect(distance).not.toHaveProperty('ruzicka'); +}); diff --git a/src/distances/ruzicka.ts b/src/similarities/ruzicka.ts similarity index 58% rename from src/distances/ruzicka.ts rename to src/similarities/ruzicka.ts index 3554691..eaab0c3 100644 --- a/src/distances/ruzicka.ts +++ b/src/similarities/ruzicka.ts @@ -1,7 +1,10 @@ import type { NumberArray } from 'cheminfo-types'; /** - *Returns the Ruzicka similarity between vectors a and b + *Returns the Ruzicka similarity between vectors a and b, also known as the + * weighted Jaccard similarity. It is 1 for identical vectors; the matching + * distance is `soergel`. * @link [Ruzicka algorithm](https://www.naun.org/main/NAUN/ijmmas/mmmas-49.pdf) + * @link [Weighted Jaccard similarity](https://en.wikipedia.org/wiki/Jaccard_index#Weighted_Jaccard_similarity_and_distance) * @param a - first vector * @param b - second vector */