w-cluster 1.0.20 → 1.0.21
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/.github/workflows/ci-test.yml +3 -3
- package/README.md +4 -6
- package/babel.config.js +4 -3
- package/dist/w-cluster.umd.js +2 -2
- package/dist/w-cluster.umd.js.map +1 -1
- package/dist/w-cluster.wk.umd.js +1 -1
- package/docs/DenseMatrix.html +202 -0
- package/docs/DistancePair.html +202 -0
- package/docs/LowerTriangle.html +202 -0
- package/docs/Rec.html +202 -0
- package/docs/Reco.html +202 -0
- package/docs/WCluster.mjs.html +8 -4
- package/docs/examples/ex-PCA.html +1 -1
- package/docs/examples/ex-cluster-webworker.html +1 -1
- package/docs/examples/ex-cluster.html +1 -1
- package/docs/global.html +6799 -164
- package/docs/index.html +2 -2
- package/docs/k-medoids_alternating.mjs.html +144 -0
- package/docs/k-medoids_arrayadapter.mjs.html +107 -0
- package/docs/k-medoids_dynmsc.mjs.html +255 -0
- package/docs/k-medoids_fastermsc.mjs.html +411 -0
- package/docs/k-medoids_fasterpam.mjs.html +305 -0
- package/docs/k-medoids_fastmsc.mjs.html +166 -0
- package/docs/k-medoids_fastpam1.mjs.html +132 -0
- package/docs/k-medoids_initialization.mjs.html +107 -0
- package/docs/k-medoids_pam.mjs.html +275 -0
- package/docs/k-medoids_pammedsil.mjs.html +307 -0
- package/docs/k-medoids_pamsil.mjs.html +225 -0
- package/docs/k-medoids_par_fasterpam.mjs.html +134 -0
- package/docs/k-medoids_par_silhouette.mjs.html +126 -0
- package/docs/k-medoids_silhouette.mjs.html +193 -0
- package/docs/k-medoids_util.mjs.html +135 -0
- package/g-PCA-nodeworker.mjs +1 -1
- package/g-PCA.mjs +1 -1
- package/g-cluster-kMeans-large.mjs +83 -0
- package/g-cluster-kMeans-nodeworker.mjs +181 -0
- package/g-cluster-kMeans.mjs +178 -0
- package/g-cluster-kMedoids-large-suggest.mjs +95 -0
- package/g-cluster-kMedoids-large.mjs +104 -0
- package/{g-cluster-nodeworker.mjs → g-cluster-kMedoids-nodeworker.mjs} +1 -2
- package/{g-cluster.mjs → g-cluster-kMedoids-simple.mjs} +1 -1
- package/package.json +7 -7
- package/script.txt +5 -7
- package/src/WCluster.mjs +6 -2
- package/src/WClusterCore.mjs +30 -21
- package/src/WClusterMat.mjs +98 -24
- package/src/jaccardBitset.mjs +63 -0
- package/src/k-medoids/README.md +124 -0
- package/src/k-medoids/alternating.mjs +72 -0
- package/src/k-medoids/arrayadapter.mjs +35 -0
- package/src/k-medoids/dynmsc.mjs +183 -0
- package/src/k-medoids/fastermsc.mjs +339 -0
- package/src/k-medoids/fasterpam.mjs +233 -0
- package/src/k-medoids/fastmsc.mjs +94 -0
- package/src/k-medoids/fastpam1.mjs +60 -0
- package/src/k-medoids/index.mjs +37 -0
- package/src/k-medoids/initialization.mjs +35 -0
- package/src/k-medoids/package.json +8 -0
- package/src/k-medoids/pam.mjs +203 -0
- package/src/k-medoids/pammedsil.mjs +235 -0
- package/src/k-medoids/pamsil.mjs +153 -0
- package/src/k-medoids/par_fasterpam.mjs +62 -0
- package/src/k-medoids/par_silhouette.mjs +54 -0
- package/src/k-medoids/silhouette.mjs +121 -0
- package/src/k-medoids/test.mjs +357 -0
- package/src/k-medoids/util.mjs +63 -0
- package/test/jaccardBitset.test.mjs +141 -0
- package/test/kMeans.test.mjs +278 -0
- package/test/kMedoids-large-suggest.test.mjs +140 -0
- package/test/kMedoids-large.test.mjs +142 -0
- package/test/{cluster.test.mjs → kMedoids-simple.test.mjs} +5 -5
- package/toolg/gDocsExams.mjs +1 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>k-medoids/par_fasterpam.mjs - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
|
|
22
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
23
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
24
|
+
<div class="navicon"></div>
|
|
25
|
+
</label>
|
|
26
|
+
|
|
27
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
28
|
+
|
|
29
|
+
<nav >
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="DenseMatrix.html">DenseMatrix</a></li><li><a href="DistancePair.html">DistancePair</a></li><li><a href="LowerTriangle.html">LowerTriangle</a></li><li><a href="Rec.html">Rec</a></li><li><a href="Reco.html">Reco</a></li></ul><h3>Global</h3><ul><li><a href="global.html#PCA">PCA</a></li><li><a href="global.html#WCluster">WCluster</a></li><li><a href="global.html#alternating">alternating</a></li><li><a href="global.html#arrayAdapter">arrayAdapter</a></li><li><a href="global.html#assign_nearest">assign_nearest</a></li><li><a href="global.html#choose_medoid_within_partition">choose_medoid_within_partition</a></li><li><a href="global.html#cluster">cluster</a></li><li><a href="global.html#do_swap">do_swap</a></li><li><a href="global.html#do_swap_k2">do_swap_k2</a></li><li><a href="global.html#dynmsc">dynmsc</a></li><li><a href="global.html#fastermsc">fastermsc</a></li><li><a href="global.html#fastermsc_k2">fastermsc_k2</a></li><li><a href="global.html#fasterpam">fasterpam</a></li><li><a href="global.html#fastmsc">fastmsc</a></li><li><a href="global.html#fastmsc_k2">fastmsc_k2</a></li><li><a href="global.html#fastpam1">fastpam1</a></li><li><a href="global.html#find_best_swap">find_best_swap</a></li><li><a href="global.html#find_best_swap_k2">find_best_swap_k2</a></li><li><a href="global.html#find_best_swap_pam">find_best_swap_pam</a></li><li><a href="global.html#find_best_swap_pammedsil">find_best_swap_pammedsil</a></li><li><a href="global.html#find_best_swap_pammedsil_k2">find_best_swap_pammedsil_k2</a></li><li><a href="global.html#find_max">find_max</a></li><li><a href="global.html#find_min">find_min</a></li><li><a href="global.html#first_k">first_k</a></li><li><a href="global.html#initial_assignment">initial_assignment</a></li><li><a href="global.html#initial_assignment_k2">initial_assignment_k2</a></li><li><a href="global.html#medoid_silhouette">medoid_silhouette</a></li><li><a href="global.html#pam">pam</a></li><li><a href="global.html#pam_build">pam_build</a></li><li><a href="global.html#pam_build_initialize">pam_build_initialize</a></li><li><a href="global.html#pam_optimize">pam_optimize</a></li><li><a href="global.html#pam_swap">pam_swap</a></li><li><a href="global.html#pammedsil">pammedsil</a></li><li><a href="global.html#pammedsil_build_initialize">pammedsil_build_initialize</a></li><li><a href="global.html#pammedsil_optimize">pammedsil_optimize</a></li><li><a href="global.html#pammedsil_swap">pammedsil_swap</a></li><li><a href="global.html#pamsil">pamsil</a></li><li><a href="global.html#pamsil_build_initialize">pamsil_build_initialize</a></li><li><a href="global.html#pamsil_optimize">pamsil_optimize</a></li><li><a href="global.html#pamsil_swap">pamsil_swap</a></li><li><a href="global.html#par_fasterpam">par_fasterpam</a></li><li><a href="global.html#par_silhouette">par_silhouette</a></li><li><a href="global.html#rand_fasterpam">rand_fasterpam</a></li><li><a href="global.html#random_initialization">random_initialization</a></li><li><a href="global.html#remove_med">remove_med</a></li><li><a href="global.html#sample">sample</a></li><li><a href="global.html#shuffle">shuffle</a></li><li><a href="global.html#silhouette">silhouette</a></li><li><a href="global.html#update_removal_loss">update_removal_loss</a></li><li><a href="global.html#update_second_nearest">update_second_nearest</a></li><li><a href="global.html#update_third_nearest">update_third_nearest</a></li><li><a href="global.html#update_third_nearest_without_new">update_third_nearest_without_new</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">k-medoids/par_fasterpam.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>// Parallel FasterPAM algorithm, ported 1:1 from src/par_fasterpam.rs
|
|
49
|
+
// JS is single-threaded; parallelism is collapsed to a sequential equivalent
|
|
50
|
+
// by delegating to fasterpam.mjs helpers (result-identical to the Rust parallel internals).
|
|
51
|
+
import { arrayAdapter } from './arrayadapter.mjs';
|
|
52
|
+
import { choose_medoid_within_partition } from './util.mjs';
|
|
53
|
+
import { initial_assignment, find_best_swap, do_swap, update_removal_loss } from './fasterpam.mjs';
|
|
54
|
+
import { shuffle } from './initialization.mjs';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Run the FasterPAM algorithm (parallel version).
|
|
58
|
+
*
|
|
59
|
+
* For small data sets (n<1000) it is usually faster to use the non-parallel version.
|
|
60
|
+
*
|
|
61
|
+
* @param mat - a pairwise distance matrix
|
|
62
|
+
* @param med - the list of medoids (mutated in place)
|
|
63
|
+
* @param maxiter - the maximum number of iterations allowed
|
|
64
|
+
* @param rng - random number generator for shuffling the input data
|
|
65
|
+
* @returns { loss, assi, nIter, nSwaps }
|
|
66
|
+
*
|
|
67
|
+
* Panics (throws) when the dissimilarity matrix is not square, or k is 0 or larger than N.
|
|
68
|
+
*/
|
|
69
|
+
export function par_fasterpam(mat, med, maxiter, rng = Math.random) {
|
|
70
|
+
mat = arrayAdapter(mat);
|
|
71
|
+
const n = mat.len(), k = med.length;
|
|
72
|
+
if (k === 1) {
|
|
73
|
+
const assi = new Array(n).fill(0);
|
|
74
|
+
const [swapped, loss] = choose_medoid_within_partition(mat, assi, med, 0);
|
|
75
|
+
return { loss, assi, nIter: 1, nSwaps: swapped ? 1 : 0 };
|
|
76
|
+
}
|
|
77
|
+
let [loss, data] = initial_assignment(mat, med);
|
|
78
|
+
|
|
79
|
+
let removal_loss = new Array(k).fill(0);
|
|
80
|
+
update_removal_loss(data, removal_loss);
|
|
81
|
+
let lastswap = n, n_swaps = 0, iter = 0;
|
|
82
|
+
const seq = shuffle(rng, n); // random shuffling
|
|
83
|
+
while (iter < maxiter) {
|
|
84
|
+
iter += 1;
|
|
85
|
+
const swaps_before = n_swaps, lastloss = loss;
|
|
86
|
+
for (const j of seq) {
|
|
87
|
+
if (j === lastswap) {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
if (j === med[data[j].near.i]) {
|
|
91
|
+
continue; // This already is a medoid
|
|
92
|
+
}
|
|
93
|
+
const [change, b] = find_best_swap(mat, removal_loss, data, j);
|
|
94
|
+
if (change >= 0) {
|
|
95
|
+
continue; // No improvement
|
|
96
|
+
}
|
|
97
|
+
n_swaps += 1;
|
|
98
|
+
lastswap = j;
|
|
99
|
+
// perform the swap
|
|
100
|
+
loss = do_swap(mat, med, data, b, j);
|
|
101
|
+
update_removal_loss(data, removal_loss);
|
|
102
|
+
}
|
|
103
|
+
if (n_swaps === swaps_before || loss >= lastloss) {
|
|
104
|
+
break; // converged
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const assi = data.map((x) => x.near.i);
|
|
108
|
+
return { loss, assi, nIter: iter, nSwaps: n_swaps };
|
|
109
|
+
}
|
|
110
|
+
</code></pre>
|
|
111
|
+
</article>
|
|
112
|
+
</section>
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<br class="clear">
|
|
122
|
+
|
|
123
|
+
<footer>
|
|
124
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Jun 14 2026 10:59:21 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
125
|
+
</footer>
|
|
126
|
+
|
|
127
|
+
<script>prettyPrint();</script>
|
|
128
|
+
<script src="scripts/polyfill.js"></script>
|
|
129
|
+
<script src="scripts/linenumber.js"></script>
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
</body>
|
|
134
|
+
</html>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>k-medoids/par_silhouette.mjs - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
|
|
22
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
23
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
24
|
+
<div class="navicon"></div>
|
|
25
|
+
</label>
|
|
26
|
+
|
|
27
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
28
|
+
|
|
29
|
+
<nav >
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="DenseMatrix.html">DenseMatrix</a></li><li><a href="DistancePair.html">DistancePair</a></li><li><a href="LowerTriangle.html">LowerTriangle</a></li><li><a href="Rec.html">Rec</a></li><li><a href="Reco.html">Reco</a></li></ul><h3>Global</h3><ul><li><a href="global.html#PCA">PCA</a></li><li><a href="global.html#WCluster">WCluster</a></li><li><a href="global.html#alternating">alternating</a></li><li><a href="global.html#arrayAdapter">arrayAdapter</a></li><li><a href="global.html#assign_nearest">assign_nearest</a></li><li><a href="global.html#choose_medoid_within_partition">choose_medoid_within_partition</a></li><li><a href="global.html#cluster">cluster</a></li><li><a href="global.html#do_swap">do_swap</a></li><li><a href="global.html#do_swap_k2">do_swap_k2</a></li><li><a href="global.html#dynmsc">dynmsc</a></li><li><a href="global.html#fastermsc">fastermsc</a></li><li><a href="global.html#fastermsc_k2">fastermsc_k2</a></li><li><a href="global.html#fasterpam">fasterpam</a></li><li><a href="global.html#fastmsc">fastmsc</a></li><li><a href="global.html#fastmsc_k2">fastmsc_k2</a></li><li><a href="global.html#fastpam1">fastpam1</a></li><li><a href="global.html#find_best_swap">find_best_swap</a></li><li><a href="global.html#find_best_swap_k2">find_best_swap_k2</a></li><li><a href="global.html#find_best_swap_pam">find_best_swap_pam</a></li><li><a href="global.html#find_best_swap_pammedsil">find_best_swap_pammedsil</a></li><li><a href="global.html#find_best_swap_pammedsil_k2">find_best_swap_pammedsil_k2</a></li><li><a href="global.html#find_max">find_max</a></li><li><a href="global.html#find_min">find_min</a></li><li><a href="global.html#first_k">first_k</a></li><li><a href="global.html#initial_assignment">initial_assignment</a></li><li><a href="global.html#initial_assignment_k2">initial_assignment_k2</a></li><li><a href="global.html#medoid_silhouette">medoid_silhouette</a></li><li><a href="global.html#pam">pam</a></li><li><a href="global.html#pam_build">pam_build</a></li><li><a href="global.html#pam_build_initialize">pam_build_initialize</a></li><li><a href="global.html#pam_optimize">pam_optimize</a></li><li><a href="global.html#pam_swap">pam_swap</a></li><li><a href="global.html#pammedsil">pammedsil</a></li><li><a href="global.html#pammedsil_build_initialize">pammedsil_build_initialize</a></li><li><a href="global.html#pammedsil_optimize">pammedsil_optimize</a></li><li><a href="global.html#pammedsil_swap">pammedsil_swap</a></li><li><a href="global.html#pamsil">pamsil</a></li><li><a href="global.html#pamsil_build_initialize">pamsil_build_initialize</a></li><li><a href="global.html#pamsil_optimize">pamsil_optimize</a></li><li><a href="global.html#pamsil_swap">pamsil_swap</a></li><li><a href="global.html#par_fasterpam">par_fasterpam</a></li><li><a href="global.html#par_silhouette">par_silhouette</a></li><li><a href="global.html#rand_fasterpam">rand_fasterpam</a></li><li><a href="global.html#random_initialization">random_initialization</a></li><li><a href="global.html#remove_med">remove_med</a></li><li><a href="global.html#sample">sample</a></li><li><a href="global.html#shuffle">shuffle</a></li><li><a href="global.html#silhouette">silhouette</a></li><li><a href="global.html#update_removal_loss">update_removal_loss</a></li><li><a href="global.html#update_second_nearest">update_second_nearest</a></li><li><a href="global.html#update_third_nearest">update_third_nearest</a></li><li><a href="global.html#update_third_nearest_without_new">update_third_nearest_without_new</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">k-medoids/par_silhouette.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>// Parallelism (rayon) collapsed to sequential equivalent for JS.
|
|
49
|
+
import { arrayAdapter } from './arrayadapter.mjs';
|
|
50
|
+
import { checked_div } from './silhouette.mjs';
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Compute the Silhouette of a strict partitional clustering (sequential JS port of parallel Rust impl).
|
|
54
|
+
*
|
|
55
|
+
* @param {object|Array} mat - pairwise distance matrix (will be wrapped by arrayAdapter)
|
|
56
|
+
* @param {number[]} assi - cluster assignment for each point
|
|
57
|
+
* @returns {number} the average silhouette value
|
|
58
|
+
*/
|
|
59
|
+
export function par_silhouette(mat, assi) {
|
|
60
|
+
mat = arrayAdapter(mat);
|
|
61
|
+
if (!mat.isSquare()) throw new Error('Dissimilarity matrix is not square');
|
|
62
|
+
let lsum = 0;
|
|
63
|
+
for (let i = 0; i < assi.length; i++) {
|
|
64
|
+
const ai = assi[i];
|
|
65
|
+
// buf[c] = [count, sum] for cluster c
|
|
66
|
+
const buf = [];
|
|
67
|
+
for (let j = 0; j < assi.length; j++) {
|
|
68
|
+
const aj = assi[j];
|
|
69
|
+
while (aj >= buf.length) {
|
|
70
|
+
buf.push([0, 0]);
|
|
71
|
+
}
|
|
72
|
+
if (i !== j) {
|
|
73
|
+
buf[aj][0] += 1;
|
|
74
|
+
buf[aj][1] += mat.get(i, j);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (buf[ai][0] > 0) {
|
|
78
|
+
const a = checked_div(buf[ai][1], buf[ai][0]);
|
|
79
|
+
// find minimum average distance to any other cluster (b)
|
|
80
|
+
// mirrors Rust: tmp.next().unwrap_or_else(L::zero) seeds the fold
|
|
81
|
+
let tmp2 = 0;
|
|
82
|
+
let foundFirst = false;
|
|
83
|
+
let b = 0;
|
|
84
|
+
for (let c = 0; c < buf.length; c++) {
|
|
85
|
+
if (c === ai) continue;
|
|
86
|
+
const avg = checked_div(buf[c][1], buf[c][0]);
|
|
87
|
+
if (!foundFirst) {
|
|
88
|
+
tmp2 = avg;
|
|
89
|
+
foundFirst = true;
|
|
90
|
+
b = tmp2;
|
|
91
|
+
} else {
|
|
92
|
+
b = avg < b ? avg : b;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// if no other cluster exists, foundFirst is false → b = tmp2 = 0
|
|
96
|
+
lsum += checked_div(b - a, a > b ? a : b);
|
|
97
|
+
}
|
|
98
|
+
// else: singleton, contributes 0 (lsum unchanged)
|
|
99
|
+
}
|
|
100
|
+
return lsum / assi.length;
|
|
101
|
+
}
|
|
102
|
+
</code></pre>
|
|
103
|
+
</article>
|
|
104
|
+
</section>
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<br class="clear">
|
|
114
|
+
|
|
115
|
+
<footer>
|
|
116
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Jun 14 2026 10:59:21 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
117
|
+
</footer>
|
|
118
|
+
|
|
119
|
+
<script>prettyPrint();</script>
|
|
120
|
+
<script src="scripts/polyfill.js"></script>
|
|
121
|
+
<script src="scripts/linenumber.js"></script>
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
</body>
|
|
126
|
+
</html>
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>k-medoids/silhouette.mjs - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
|
|
22
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
23
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
24
|
+
<div class="navicon"></div>
|
|
25
|
+
</label>
|
|
26
|
+
|
|
27
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
28
|
+
|
|
29
|
+
<nav >
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="DenseMatrix.html">DenseMatrix</a></li><li><a href="DistancePair.html">DistancePair</a></li><li><a href="LowerTriangle.html">LowerTriangle</a></li><li><a href="Rec.html">Rec</a></li><li><a href="Reco.html">Reco</a></li></ul><h3>Global</h3><ul><li><a href="global.html#PCA">PCA</a></li><li><a href="global.html#WCluster">WCluster</a></li><li><a href="global.html#alternating">alternating</a></li><li><a href="global.html#arrayAdapter">arrayAdapter</a></li><li><a href="global.html#assign_nearest">assign_nearest</a></li><li><a href="global.html#choose_medoid_within_partition">choose_medoid_within_partition</a></li><li><a href="global.html#cluster">cluster</a></li><li><a href="global.html#do_swap">do_swap</a></li><li><a href="global.html#do_swap_k2">do_swap_k2</a></li><li><a href="global.html#dynmsc">dynmsc</a></li><li><a href="global.html#fastermsc">fastermsc</a></li><li><a href="global.html#fastermsc_k2">fastermsc_k2</a></li><li><a href="global.html#fasterpam">fasterpam</a></li><li><a href="global.html#fastmsc">fastmsc</a></li><li><a href="global.html#fastmsc_k2">fastmsc_k2</a></li><li><a href="global.html#fastpam1">fastpam1</a></li><li><a href="global.html#find_best_swap">find_best_swap</a></li><li><a href="global.html#find_best_swap_k2">find_best_swap_k2</a></li><li><a href="global.html#find_best_swap_pam">find_best_swap_pam</a></li><li><a href="global.html#find_best_swap_pammedsil">find_best_swap_pammedsil</a></li><li><a href="global.html#find_best_swap_pammedsil_k2">find_best_swap_pammedsil_k2</a></li><li><a href="global.html#find_max">find_max</a></li><li><a href="global.html#find_min">find_min</a></li><li><a href="global.html#first_k">first_k</a></li><li><a href="global.html#initial_assignment">initial_assignment</a></li><li><a href="global.html#initial_assignment_k2">initial_assignment_k2</a></li><li><a href="global.html#medoid_silhouette">medoid_silhouette</a></li><li><a href="global.html#pam">pam</a></li><li><a href="global.html#pam_build">pam_build</a></li><li><a href="global.html#pam_build_initialize">pam_build_initialize</a></li><li><a href="global.html#pam_optimize">pam_optimize</a></li><li><a href="global.html#pam_swap">pam_swap</a></li><li><a href="global.html#pammedsil">pammedsil</a></li><li><a href="global.html#pammedsil_build_initialize">pammedsil_build_initialize</a></li><li><a href="global.html#pammedsil_optimize">pammedsil_optimize</a></li><li><a href="global.html#pammedsil_swap">pammedsil_swap</a></li><li><a href="global.html#pamsil">pamsil</a></li><li><a href="global.html#pamsil_build_initialize">pamsil_build_initialize</a></li><li><a href="global.html#pamsil_optimize">pamsil_optimize</a></li><li><a href="global.html#pamsil_swap">pamsil_swap</a></li><li><a href="global.html#par_fasterpam">par_fasterpam</a></li><li><a href="global.html#par_silhouette">par_silhouette</a></li><li><a href="global.html#rand_fasterpam">rand_fasterpam</a></li><li><a href="global.html#random_initialization">random_initialization</a></li><li><a href="global.html#remove_med">remove_med</a></li><li><a href="global.html#sample">sample</a></li><li><a href="global.html#shuffle">shuffle</a></li><li><a href="global.html#silhouette">silhouette</a></li><li><a href="global.html#update_removal_loss">update_removal_loss</a></li><li><a href="global.html#update_second_nearest">update_second_nearest</a></li><li><a href="global.html#update_third_nearest">update_third_nearest</a></li><li><a href="global.html#update_third_nearest_without_new">update_third_nearest_without_new</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">k-medoids/silhouette.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>// Silhouette evaluation measures, ported from src/silhouette.rs
|
|
49
|
+
import { arrayAdapter } from './arrayadapter.mjs';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Compute the Silhouette of a strict partitional clustering.
|
|
53
|
+
*
|
|
54
|
+
* The Silhouette, proposed by Peter Rousseeuw in 1987, is a popular internal
|
|
55
|
+
* evaluation measure for clusterings.
|
|
56
|
+
*
|
|
57
|
+
* @param mat - a pairwise distance matrix
|
|
58
|
+
* @param assi - the cluster assignment
|
|
59
|
+
* @param samples - whether to keep the individual samples, or not
|
|
60
|
+
* @returns { sil, samples } where sil is the average silhouette and samples are
|
|
61
|
+
* the individual silhouette values (empty [] if samples = false)
|
|
62
|
+
*/
|
|
63
|
+
export function silhouette(mat, assi, samples = false) {
|
|
64
|
+
mat = arrayAdapter(mat);
|
|
65
|
+
if (!mat.isSquare()) throw new Error('Dissimilarity matrix is not square');
|
|
66
|
+
let sil = new Array(samples ? assi.length : 0).fill(0);
|
|
67
|
+
let lsum = 0;
|
|
68
|
+
let buf = []; // array of [count(u32), sum(L)] pairs
|
|
69
|
+
for (let i = 0; i < assi.length; i++) {
|
|
70
|
+
const ai = assi[i];
|
|
71
|
+
buf.length = 0;
|
|
72
|
+
for (let j = 0; j < assi.length; j++) {
|
|
73
|
+
const aj = assi[j];
|
|
74
|
+
while (aj >= buf.length) {
|
|
75
|
+
buf.push([0, 0]);
|
|
76
|
+
}
|
|
77
|
+
if (i !== j) {
|
|
78
|
+
buf[aj][0] += 1;
|
|
79
|
+
buf[aj][1] += mat.get(i, j);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (buf.length === 1) {
|
|
83
|
+
return { sil: 0, samples: sil };
|
|
84
|
+
}
|
|
85
|
+
let s;
|
|
86
|
+
if (buf[ai][0] > 0) {
|
|
87
|
+
const a = checked_div(buf[ai][1], buf[ai][0]);
|
|
88
|
+
// Ugly hack to get the min():
|
|
89
|
+
let started = false;
|
|
90
|
+
let b = 0;
|
|
91
|
+
for (let k = 0; k < buf.length; k++) {
|
|
92
|
+
if (k === ai) continue;
|
|
93
|
+
const p = buf[k];
|
|
94
|
+
const y = checked_div(p[1], p[0]);
|
|
95
|
+
if (!started) {
|
|
96
|
+
b = y; // tmp.next().unwrap_or_else(L::zero)
|
|
97
|
+
started = true;
|
|
98
|
+
} else {
|
|
99
|
+
b = y < b ? y : b; // tmp.fold(tmp2, |x, y| if y < x { y } else { x })
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// tmp2 = tmp.next().unwrap_or_else(L::zero): if no element, b stays 0
|
|
103
|
+
s = checked_div(b - a, a > b ? a : b);
|
|
104
|
+
} else {
|
|
105
|
+
s = 0; // singleton
|
|
106
|
+
}
|
|
107
|
+
if (samples) {
|
|
108
|
+
sil[i] = s;
|
|
109
|
+
}
|
|
110
|
+
lsum += s;
|
|
111
|
+
}
|
|
112
|
+
return { sil: lsum / assi.length, samples: sil };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Compute the Medoid Silhouette of a clustering.
|
|
117
|
+
*
|
|
118
|
+
* The Medoid Silhouette is an approximation to the original Silhouette where the
|
|
119
|
+
* distance to the cluster medoid is used instead of the average distance.
|
|
120
|
+
*
|
|
121
|
+
* @param mat - a pairwise distance matrix
|
|
122
|
+
* @param meds - the medoid list
|
|
123
|
+
* @param samples - whether to keep the individual samples, or not
|
|
124
|
+
* @returns { sil, samples } where sil is the average medoid silhouette and
|
|
125
|
+
* samples are the individual values (empty [] if samples = false)
|
|
126
|
+
*/
|
|
127
|
+
export function medoid_silhouette(mat, meds, samples = false) {
|
|
128
|
+
mat = arrayAdapter(mat);
|
|
129
|
+
const n = mat.len(), k = meds.length;
|
|
130
|
+
if (!mat.isSquare()) throw new Error('Dissimilarity matrix is not square');
|
|
131
|
+
if (!(n <= U32_MAX_GUARD)) throw new Error('N is too large');
|
|
132
|
+
let sil = new Array(samples ? n : 0).fill(1);
|
|
133
|
+
if (k === 1) { return { sil: 1, samples: sil }; } // not really well-defined
|
|
134
|
+
if (!(k >= 2 && k <= n)) throw new Error('invalid k, must be over 1 and at most N');
|
|
135
|
+
let loss = 0;
|
|
136
|
+
for (let i = 0; i < n; i++) {
|
|
137
|
+
const d1 = mat.get(i, meds[0]), d2 = mat.get(i, meds[1]);
|
|
138
|
+
let best = d1 < d2 ? [d1, d2] : [d2, d1];
|
|
139
|
+
for (let s2 = 2; s2 < meds.length; s2++) {
|
|
140
|
+
const m = meds[s2];
|
|
141
|
+
const d = mat.get(i, m);
|
|
142
|
+
if (d < best[0]) {
|
|
143
|
+
best = [d, best[0]];
|
|
144
|
+
} else if (d < best[1]) {
|
|
145
|
+
best = [best[0], d];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (best[0] !== 0) {
|
|
149
|
+
const s = best[0] / best[1];
|
|
150
|
+
if (samples) { sil[i] = 1 - s; }
|
|
151
|
+
loss += s;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
loss = 1 - loss / n;
|
|
155
|
+
return { sil: loss, samples: sil };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// u32::MAX, used only for the "N is too large" assertion.
|
|
159
|
+
const U32_MAX_GUARD = 4294967295;
|
|
160
|
+
|
|
161
|
+
// helper function, returns 0 on division by 0
|
|
162
|
+
export function checked_div(x, y) {
|
|
163
|
+
if (y > 0) {
|
|
164
|
+
return x / y;
|
|
165
|
+
} else {
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
</code></pre>
|
|
170
|
+
</article>
|
|
171
|
+
</section>
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<br class="clear">
|
|
181
|
+
|
|
182
|
+
<footer>
|
|
183
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Jun 14 2026 10:59:21 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
184
|
+
</footer>
|
|
185
|
+
|
|
186
|
+
<script>prettyPrint();</script>
|
|
187
|
+
<script src="scripts/polyfill.js"></script>
|
|
188
|
+
<script src="scripts/linenumber.js"></script>
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
</body>
|
|
193
|
+
</html>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>k-medoids/util.mjs - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
|
|
22
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
23
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
24
|
+
<div class="navicon"></div>
|
|
25
|
+
</label>
|
|
26
|
+
|
|
27
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
28
|
+
|
|
29
|
+
<nav >
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="DenseMatrix.html">DenseMatrix</a></li><li><a href="DistancePair.html">DistancePair</a></li><li><a href="LowerTriangle.html">LowerTriangle</a></li><li><a href="Rec.html">Rec</a></li><li><a href="Reco.html">Reco</a></li></ul><h3>Global</h3><ul><li><a href="global.html#PCA">PCA</a></li><li><a href="global.html#WCluster">WCluster</a></li><li><a href="global.html#alternating">alternating</a></li><li><a href="global.html#arrayAdapter">arrayAdapter</a></li><li><a href="global.html#assign_nearest">assign_nearest</a></li><li><a href="global.html#choose_medoid_within_partition">choose_medoid_within_partition</a></li><li><a href="global.html#cluster">cluster</a></li><li><a href="global.html#do_swap">do_swap</a></li><li><a href="global.html#do_swap_k2">do_swap_k2</a></li><li><a href="global.html#dynmsc">dynmsc</a></li><li><a href="global.html#fastermsc">fastermsc</a></li><li><a href="global.html#fastermsc_k2">fastermsc_k2</a></li><li><a href="global.html#fasterpam">fasterpam</a></li><li><a href="global.html#fastmsc">fastmsc</a></li><li><a href="global.html#fastmsc_k2">fastmsc_k2</a></li><li><a href="global.html#fastpam1">fastpam1</a></li><li><a href="global.html#find_best_swap">find_best_swap</a></li><li><a href="global.html#find_best_swap_k2">find_best_swap_k2</a></li><li><a href="global.html#find_best_swap_pam">find_best_swap_pam</a></li><li><a href="global.html#find_best_swap_pammedsil">find_best_swap_pammedsil</a></li><li><a href="global.html#find_best_swap_pammedsil_k2">find_best_swap_pammedsil_k2</a></li><li><a href="global.html#find_max">find_max</a></li><li><a href="global.html#find_min">find_min</a></li><li><a href="global.html#first_k">first_k</a></li><li><a href="global.html#initial_assignment">initial_assignment</a></li><li><a href="global.html#initial_assignment_k2">initial_assignment_k2</a></li><li><a href="global.html#medoid_silhouette">medoid_silhouette</a></li><li><a href="global.html#pam">pam</a></li><li><a href="global.html#pam_build">pam_build</a></li><li><a href="global.html#pam_build_initialize">pam_build_initialize</a></li><li><a href="global.html#pam_optimize">pam_optimize</a></li><li><a href="global.html#pam_swap">pam_swap</a></li><li><a href="global.html#pammedsil">pammedsil</a></li><li><a href="global.html#pammedsil_build_initialize">pammedsil_build_initialize</a></li><li><a href="global.html#pammedsil_optimize">pammedsil_optimize</a></li><li><a href="global.html#pammedsil_swap">pammedsil_swap</a></li><li><a href="global.html#pamsil">pamsil</a></li><li><a href="global.html#pamsil_build_initialize">pamsil_build_initialize</a></li><li><a href="global.html#pamsil_optimize">pamsil_optimize</a></li><li><a href="global.html#pamsil_swap">pamsil_swap</a></li><li><a href="global.html#par_fasterpam">par_fasterpam</a></li><li><a href="global.html#par_silhouette">par_silhouette</a></li><li><a href="global.html#rand_fasterpam">rand_fasterpam</a></li><li><a href="global.html#random_initialization">random_initialization</a></li><li><a href="global.html#remove_med">remove_med</a></li><li><a href="global.html#sample">sample</a></li><li><a href="global.html#shuffle">shuffle</a></li><li><a href="global.html#silhouette">silhouette</a></li><li><a href="global.html#update_removal_loss">update_removal_loss</a></li><li><a href="global.html#update_second_nearest">update_second_nearest</a></li><li><a href="global.html#update_third_nearest">update_third_nearest</a></li><li><a href="global.html#update_third_nearest_without_new">update_third_nearest_without_new</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">k-medoids/util.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>// Utility types and helpers, ported from src/util.rs
|
|
49
|
+
export const U32_MAX = 4294967295;
|
|
50
|
+
export const USIZE_MAX = Number.MAX_SAFE_INTEGER;
|
|
51
|
+
|
|
52
|
+
/** Object id (i) and distance (d) pair. */
|
|
53
|
+
export class DistancePair {
|
|
54
|
+
constructor(i, d) { this.i = i; this.d = d; }
|
|
55
|
+
clone() { return new DistancePair(this.i, this.d); }
|
|
56
|
+
static empty() { return new DistancePair(U32_MAX, 0); }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Per-point record: nearest + second nearest medoid. */
|
|
60
|
+
export class Rec {
|
|
61
|
+
constructor(i1, d1, i2, d2) { this.near = new DistancePair(i1, d1); this.seco = new DistancePair(i2, d2); }
|
|
62
|
+
clone() { return new Rec(this.near.i, this.near.d, this.seco.i, this.seco.d); }
|
|
63
|
+
static empty() { return new Rec(U32_MAX, 0, U32_MAX, 0); }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Per-point record: nearest + second + third nearest medoid. */
|
|
67
|
+
export class Reco {
|
|
68
|
+
constructor(i1, d1, i2, d2, i3, d3) {
|
|
69
|
+
this.near = new DistancePair(i1, d1);
|
|
70
|
+
this.seco = new DistancePair(i2, d2);
|
|
71
|
+
this.third = new DistancePair(i3, d3);
|
|
72
|
+
}
|
|
73
|
+
clone() { return new Reco(this.near.i, this.near.d, this.seco.i, this.seco.d, this.third.i, this.third.d); }
|
|
74
|
+
static empty() { return new Reco(U32_MAX, 0, U32_MAX, 0, U32_MAX, 0); }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Find the minimum (index and value) over an array of numbers. */
|
|
78
|
+
export function find_min(arr) {
|
|
79
|
+
let bi = 0, bv = arr[0];
|
|
80
|
+
for (let i = 1; i < arr.length; i++) { if (arr[i] < bv) { bi = i; bv = arr[i]; } }
|
|
81
|
+
return [bi, bv];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Find the maximum (index and value) over an array of numbers. */
|
|
85
|
+
export function find_max(arr) {
|
|
86
|
+
let bi = 0, bv = arr[0];
|
|
87
|
+
for (let i = 1; i < arr.length; i++) { if (arr[i] > bv) { bi = i; bv = arr[i]; } }
|
|
88
|
+
return [bi, bv];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Choose the best medoid within a partition. Mutates med[m]. Returns [changed, sumb]. */
|
|
92
|
+
export function choose_medoid_within_partition(mat, assi, med, m) {
|
|
93
|
+
const first = med[m];
|
|
94
|
+
let best = first;
|
|
95
|
+
let sumb = 0;
|
|
96
|
+
for (let i = 0; i < assi.length; i++) {
|
|
97
|
+
if (first !== i && assi[i] === m) sumb += mat.get(first, i);
|
|
98
|
+
}
|
|
99
|
+
for (let j = 0; j < assi.length; j++) {
|
|
100
|
+
if (j !== first && assi[j] === m) {
|
|
101
|
+
let sumj = 0;
|
|
102
|
+
for (let i = 0; i < assi.length; i++) {
|
|
103
|
+
if (i !== j && assi[i] === m) sumj += mat.get(j, i);
|
|
104
|
+
}
|
|
105
|
+
if (sumj < sumb) { best = j; sumb = sumj; }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
med[m] = best;
|
|
109
|
+
return [best !== first, sumb];
|
|
110
|
+
}
|
|
111
|
+
</code></pre>
|
|
112
|
+
</article>
|
|
113
|
+
</section>
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<br class="clear">
|
|
123
|
+
|
|
124
|
+
<footer>
|
|
125
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Sun Jun 14 2026 10:59:21 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
126
|
+
</footer>
|
|
127
|
+
|
|
128
|
+
<script>prettyPrint();</script>
|
|
129
|
+
<script src="scripts/polyfill.js"></script>
|
|
130
|
+
<script src="scripts/linenumber.js"></script>
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
</body>
|
|
135
|
+
</html>
|
package/g-PCA-nodeworker.mjs
CHANGED
package/g-PCA.mjs
CHANGED