@thi.ng/k-means 1.0.22 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/README.md +2 -2
- package/api.d.ts +13 -0
- package/kmeans.d.ts +7 -1
- package/kmeans.js +13 -11
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2025-
|
|
3
|
+
- **Last updated**: 2025-06-14T20:56:27Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -11,6 +11,14 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
11
11
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
12
12
|
and/or version bumps of transitive dependencies.
|
|
13
13
|
|
|
14
|
+
## [1.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/k-means@1.1.0) (2025-06-14)
|
|
15
|
+
|
|
16
|
+
#### 🚀 Features
|
|
17
|
+
|
|
18
|
+
- update initKmeanspp(), add configurable distance exponent ([2aed319](https://github.com/thi-ng/umbrella/commit/2aed319))
|
|
19
|
+
- add KMeansOpts.exponent
|
|
20
|
+
- update doc strings
|
|
21
|
+
|
|
14
22
|
### [0.7.10](https://github.com/thi-ng/umbrella/tree/@thi.ng/k-means@0.7.10) (2024-10-05)
|
|
15
23
|
|
|
16
24
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://mastodon.thi.ng/@toxi)
|
|
8
8
|
|
|
9
9
|
> [!NOTE]
|
|
10
|
-
> This is one of
|
|
10
|
+
> This is one of 209 standalone projects, maintained as part
|
|
11
11
|
> of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo
|
|
12
12
|
> and anti-framework.
|
|
13
13
|
>
|
|
@@ -59,7 +59,7 @@ For Node.js REPL:
|
|
|
59
59
|
const kmeans = await import("@thi.ng/k-means");
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
62
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 898 bytes
|
|
63
63
|
|
|
64
64
|
## Dependencies
|
|
65
65
|
|
package/api.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export interface KMeansOpts {
|
|
|
13
13
|
* Distance function/metric to use for finding nearest centroid.
|
|
14
14
|
*/
|
|
15
15
|
dist: IDistance<ReadonlyVec>;
|
|
16
|
+
/**
|
|
17
|
+
* Sample dimensions. If omitted uses length of first sample vector.
|
|
18
|
+
*/
|
|
19
|
+
dim: number;
|
|
16
20
|
/**
|
|
17
21
|
* Max. iteration count
|
|
18
22
|
*/
|
|
@@ -25,6 +29,15 @@ export interface KMeansOpts {
|
|
|
25
29
|
* Centroid refinement strategy (default: {@link means}).
|
|
26
30
|
*/
|
|
27
31
|
strategy: CentroidStrategy;
|
|
32
|
+
/**
|
|
33
|
+
* Only used if no {@link KMeansOpts.initial} is given and the
|
|
34
|
+
* {@link initKmeanspp} default is used. There the `exponent` is applied to
|
|
35
|
+
* scale the distances to nearest centroid, which will be used to control
|
|
36
|
+
* the weight distribution for choosing next centroid. A higher exponent
|
|
37
|
+
* means that points with larger distances will be more prioritized in the
|
|
38
|
+
* random selection.
|
|
39
|
+
*/
|
|
40
|
+
exponent: number;
|
|
28
41
|
}
|
|
29
42
|
/**
|
|
30
43
|
* k-means initialization function, e.g. {@link initKmeanspp}.
|
package/kmeans.d.ts
CHANGED
|
@@ -24,6 +24,11 @@ export declare const kmeans: <T extends ReadonlyVec>(k: number, samples: T[], op
|
|
|
24
24
|
* fulfilled (e.g. due to lower number of samples and/or distance metric).
|
|
25
25
|
* Throws an error if `samples` are empty.
|
|
26
26
|
*
|
|
27
|
+
* The optional `exponent` (default: 2) is applied to scale the distances to
|
|
28
|
+
* nearest centroid, which will be used to control the weight distribution for
|
|
29
|
+
* choosing next centroid. A higher exponent means that points with larger
|
|
30
|
+
* distances will be more prioritized in the random selection.
|
|
31
|
+
*
|
|
27
32
|
* References:
|
|
28
33
|
*
|
|
29
34
|
* - https://en.wikipedia.org/wiki/K-means%2B%2B
|
|
@@ -34,8 +39,9 @@ export declare const kmeans: <T extends ReadonlyVec>(k: number, samples: T[], op
|
|
|
34
39
|
* @param samples -
|
|
35
40
|
* @param dist -
|
|
36
41
|
* @param rnd -
|
|
42
|
+
* @param exponent -
|
|
37
43
|
*/
|
|
38
|
-
export declare const initKmeanspp: <T extends ReadonlyVec>(k: number, samples: T[], dist?: IDistance<ReadonlyVec>, rnd?: IRandom) => number[];
|
|
44
|
+
export declare const initKmeanspp: <T extends ReadonlyVec>(k: number, samples: T[], dist?: IDistance<ReadonlyVec>, rnd?: IRandom, exponent?: number) => number[];
|
|
39
45
|
/**
|
|
40
46
|
* Default centroid strategy forming new centroids by averaging the position of
|
|
41
47
|
* participating samples.
|
package/kmeans.js
CHANGED
|
@@ -7,16 +7,18 @@ import { add } from "@thi.ng/vectors/add";
|
|
|
7
7
|
import { median } from "@thi.ng/vectors/median";
|
|
8
8
|
import { mulN } from "@thi.ng/vectors/muln";
|
|
9
9
|
import { zeroes } from "@thi.ng/vectors/setn";
|
|
10
|
-
const kmeans = (k, samples, opts) => {
|
|
11
|
-
let {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
const kmeans = (k, samples, opts = {}) => {
|
|
11
|
+
let {
|
|
12
|
+
dim = samples[0].length,
|
|
13
|
+
dist = DIST_SQ,
|
|
14
|
+
maxIter = 32,
|
|
15
|
+
strategy = means,
|
|
16
|
+
exponent,
|
|
17
|
+
initial,
|
|
18
|
+
rnd
|
|
19
|
+
} = opts;
|
|
17
20
|
const num = samples.length;
|
|
18
|
-
const
|
|
19
|
-
const centroidIDs = Array.isArray(initial) ? initial : initial ? initial(k, samples, dist, rnd) : initKmeanspp(k, samples, dist, rnd);
|
|
21
|
+
const centroidIDs = Array.isArray(initial) ? initial : initial ? initial(k, samples, dist, rnd) : initKmeanspp(k, samples, dist, rnd, exponent);
|
|
20
22
|
assert(centroidIDs.length > 0, `missing initial centroids`);
|
|
21
23
|
k = centroidIDs.length;
|
|
22
24
|
const centroids = centroidIDs.map((i) => samples[i]);
|
|
@@ -36,7 +38,7 @@ const kmeans = (k, samples, opts) => {
|
|
|
36
38
|
}
|
|
37
39
|
return __buildClusters(centroids, clusters);
|
|
38
40
|
};
|
|
39
|
-
const initKmeanspp = (k, samples, dist = DIST_SQ, rnd = SYSTEM) => {
|
|
41
|
+
const initKmeanspp = (k, samples, dist = DIST_SQ, rnd = SYSTEM, exponent = 2) => {
|
|
40
42
|
const num = samples.length;
|
|
41
43
|
assert(num > 0, `missing samples`);
|
|
42
44
|
k = Math.min(k, num);
|
|
@@ -47,7 +49,7 @@ const initKmeanspp = (k, samples, dist = DIST_SQ, rnd = SYSTEM) => {
|
|
|
47
49
|
while (centroidIDs.length < k) {
|
|
48
50
|
let psum = 0;
|
|
49
51
|
const probs = samples.map((p) => {
|
|
50
|
-
const d = dist.from(metric(p, centroids[argmin(p, centroids, dist)])) **
|
|
52
|
+
const d = dist.from(metric(p, centroids[argmin(p, centroids, dist)])) ** exponent;
|
|
51
53
|
psum += d;
|
|
52
54
|
return d;
|
|
53
55
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/k-means",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Configurable k-means & k-medians (with k-means++ initialization) for n-D vectors",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@thi.ng/api": "^8.11.
|
|
43
|
-
"@thi.ng/distance": "^
|
|
44
|
-
"@thi.ng/errors": "^2.5.
|
|
45
|
-
"@thi.ng/random": "^4.1.
|
|
46
|
-
"@thi.ng/vectors": "^8.
|
|
42
|
+
"@thi.ng/api": "^8.11.29",
|
|
43
|
+
"@thi.ng/distance": "^3.0.0",
|
|
44
|
+
"@thi.ng/errors": "^2.5.35",
|
|
45
|
+
"@thi.ng/random": "^4.1.20",
|
|
46
|
+
"@thi.ng/vectors": "^8.3.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"esbuild": "^0.25.5",
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
"year": 2021,
|
|
88
88
|
"screenshot": "examples/kmeans-viz.jpg"
|
|
89
89
|
},
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "14e994e531d32053e948768998324d443436a542\n"
|
|
91
91
|
}
|