楼主: ReneeBK
1426 3

Hierarchical Clustering in JavaScript [推广有奖]

  • 1关注
  • 62粉丝

VIP

已卖:4897份资源

学术权威

14%

还不是VIP/贵宾

-

TA的文库  其他...

R资源总汇

Panel Data Analysis

Experimental Design

威望
1
论坛币
49635 个
通用积分
55.7537
学术水平
370 点
热心指数
273 点
信用等级
335 点
经验
57805 点
帖子
4005
精华
21
在线时间
582 小时
注册时间
2005-5-8
最后登录
2023-11-26

楼主
ReneeBK 发表于 2016-6-27 00:17:01 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
hclust

Hierarchical clustering algorithms in JavaScript

Installation

npm install ml-hclust

Methods

Generate a clustering hierarchy.

new agnes(data,[options])

AGNES (AGglomerative NESting): Continuously merge nodes that have the least dissimilarity.

Arguments

  • data: Array of points to be clustered, are an array of arrays, as [[x1,y1],[x2,y2], ... ]
  • options: Is an object with the parameters sim and kind, where sim is a distance function between vectors (the default function is the euclidean), and kind is the string name for the function to calculate distance between clusters, and it could be single(default), complete, average, centroid or ward
getDendogram([input])

Returns a phylogram (a dendogram with weights) and change the leaves values for the values in input, if it's given.

Example

var hclust = require('ml-hclust')var data = [[2,6], [3,4], [3,8]];var HC = new hclust.agnes(data);var dend1 = HC.getDendogram();var dend2 = HC.getDendogram([{a:1},{b:2},{c:3}]);
nClusters(N)

Returns at least N clusters based in the clustering tree if it's possible

new diana(data,[options])

DIANA (Divisive ANAlysis): The process starts at the root with all the points as one cluster and recursively splits the higher level clusters to build the dendrogram.

Arguments

  • data: Array of points to be clustered, are an array of arrays, as [[x1,y1],[x2,y2], ... ]
  • options: Is an object with the parameters sim and kind, where sim is a distance function between vectors (the default function is the euclidean), and kind is the string name for the function to calculate distance between clusters, and it could be single(default), complete, average, centroid or ward
getDendogram([input])

Returns a phylogram (a dendogram with weights) and change the leaves values for the values in input, if it's given.

Example

var hclust = require('ml-hclust')var data = [[2,6], [3,4], [3,8]];var HC = new hclust.diana(data);var dend1 = HC.getDendogram();var dend2 = HC.getDendogram([{a:1},{b:2},{c:3}]);
nClusters(N)

Returns at least N clusters based in the clustering tree if it's possible

new birch(data,[options])

BIRCH (Balanced Iterative Reducing and Clustering using Hierarchies): Incrementally construct a CF (Clustering Feature) tree, a hierarchical data structure for multiphase clustering

new cure(data,[options])

CURE (Clustering Using REpresentatives):

new chameleon(data,[options])

CHAMELEON

Test$ npm install$ npm test
AuthorsLicense

MIT


本帖隐藏的内容

hclust-master.zip (9.5 KB)


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Hierarchical Clustering Javascript Cluster script function default distance between points

本帖被以下文库推荐

沙发
ReneeBK 发表于 2016-6-27 00:17:34

DIANA (Divisive ANAlysis) using JavaScript

  1. 'use strict';

  2. var euclidean = require('ml-euclidean-distance');
  3. var ClusterLeaf = require('./ClusterLeaf');
  4. var Cluster = require('./Cluster');

  5. /**
  6. * @param {Array <Array <number>>} cluster1
  7. * @param {Array <Array <number>>} cluster2
  8. * @param {function} disFun
  9. * @returns {number}
  10. */
  11. function simpleLink(cluster1, cluster2, disFun) {
  12.     var m = 10e100;
  13.     for (var i = 0; i < cluster1.length; i++)
  14.         for (var j = i; j < cluster2.length; j++) {
  15.             var d = disFun(cluster1[i], cluster2[j]);
  16.             m = Math.min(d,m);
  17.         }
  18.     return m;
  19. }

  20. /**
  21. * @param {Array <Array <number>>} cluster1
  22. * @param {Array <Array <number>>} cluster2
  23. * @param {function} disFun
  24. * @returns {number}
  25. */
  26. function completeLink(cluster1, cluster2, disFun) {
  27.     var m = -1;
  28.     for (var i = 0; i < cluster1.length; i++)
  29.         for (var j = i; j < cluster2.length; j++) {
  30.             var d = disFun(cluster1[i], cluster2[j]);
  31.             m = Math.max(d,m);
  32.         }
  33.     return m;
  34. }

  35. /**
  36. * @param {Array <Array <number>>} cluster1
  37. * @param {Array <Array <number>>} cluster2
  38. * @param {function} disFun
  39. * @returns {number}
  40. */
  41. function averageLink(cluster1, cluster2, disFun) {
  42.     var m = 0;
  43.     for (var i = 0; i < cluster1.length; i++)
  44.         for (var j = 0; j < cluster2.length; j++)
  45.             m += disFun(cluster1[i], cluster2[j]);
  46.     return m / (cluster1.length * cluster2.length);
  47. }

  48. /**
  49. * @param {Array <Array <number>>} cluster1
  50. * @param {Array <Array <number>>} cluster2
  51. * @param {function} disFun
  52. * @returns {number}
  53. */
  54. function centroidLink(cluster1, cluster2, disFun) {
  55.     var x1 = 0,
  56.         y1 = 0,
  57.         x2 = 0,
  58.         y2 = 0;
  59.     for (var i = 0; i < cluster1.length; i++) {
  60.         x1 += cluster1[i][0];
  61.         y1 += cluster1[i][1];
  62.     }
  63.     for (var j = 0; j < cluster2.length; j++) {
  64.         x2 += cluster2[j][0];
  65.         y2 += cluster2[j][1];
  66.     }
  67.     x1 /= cluster1.length;
  68.     y1 /= cluster1.length;
  69.     x2 /= cluster2.length;
  70.     y2 /= cluster2.length;
  71.     return disFun([x1,y1], [x2,y2]);
  72. }

  73. /**
  74. * @param {Array <Array <number>>} cluster1
  75. * @param {Array <Array <number>>} cluster2
  76. * @param {function} disFun
  77. * @returns {number}
  78. */
  79. function wardLink(cluster1, cluster2, disFun) {
  80.     var x1 = 0,
  81.         y1 = 0,
  82.         x2 = 0,
  83.         y2 = 0;
  84.     for (var i = 0; i < cluster1.length; i++) {
  85.         x1 += cluster1[i][0];
  86.         y1 += cluster1[i][1];
  87.     }
  88.     for (var j = 0; j < cluster2.length; j++) {
  89.         x2 += cluster2[j][0];
  90.         y2 += cluster2[j][1];
  91.     }
  92.     x1 /= cluster1.length;
  93.     y1 /= cluster1.length;
  94.     x2 /= cluster2.length;
  95.     y2 /= cluster2.length;
  96.     return disFun([x1,y1], [x2,y2])*cluster1.length*cluster2.length / (cluster1.length+cluster2.length);
  97. }

  98. /**
  99. * Returns the most distant point and his distance
  100. * @param {Array <Array <number>>} splitting - Clusters to split
  101. * @param {Array <Array <number>>} data - Original data
  102. * @param {function} disFun - Distance function
  103. * @returns {{d: number, p: number}} - d: maximum difference between points, p: the point more distant
  104. */
  105. function diff(splitting, data, disFun) {
  106.     var ans = {
  107.         d:0,
  108.         p:0
  109.     };

  110.     var Ci = new Array(splitting[0].length);
  111.     for (var e = 0; e < splitting[0].length; e++)
  112.         Ci[e] = data[splitting[0][e]];
  113.     var Cj = new Array(splitting[1].length);
  114.     for (var f = 0; f < splitting[1].length; f++)
  115.         Cj[f] = data[splitting[1][f]];

  116.     var dist, ndist;
  117.     for (var i = 0; i < Ci.length; i++) {
  118.         dist = 0;
  119.         for (var j = 0; j < Ci.length; j++)
  120.             if (i !== j)
  121.                 dist += disFun(Ci[i], Ci[j]);
  122.         dist /= (Ci.length - 1);
  123.         ndist = 0;
  124.         for (var k = 0; k < Cj.length; k++)
  125.             ndist += disFun(Ci[i], Cj[k]);
  126.         ndist /= Cj.length;
  127.         if ((dist - ndist) > ans.d) {
  128.             ans.d = (dist - ndist);
  129.             ans.p = i;
  130.         }
  131.     }
  132.     return ans;
  133. }

  134. var defaultOptions = {
  135.     dist: euclidean,
  136.     kind: 'single'
  137. };

  138. /**
  139. * Intra-cluster distance
  140. * @param {Array} index
  141. * @param {Array} data
  142. * @param {function} disFun
  143. * @returns {number}
  144. */
  145. function intrDist(index, data, disFun) {
  146.     var dist = 0,
  147.         count = 0;
  148.     for (var i = 0; i < index.length; i++)
  149.         for (var j = i; j < index.length; j++) {
  150.             dist += disFun(data[index[i].index], data[index[j].index]);
  151.             count++
  152.         }
  153.     return dist / count;
  154. }

  155. /**
  156. * Splits the higher level clusters
  157. * @param {Array <Array <number>>} data - Array of points to be clustered
  158. * @param {json} options
  159. * @constructor
  160. */
  161. function diana(data, options) {
  162.     options = options || {};
  163.     for (var o in defaultOptions)
  164.         if (!(options.hasOwnProperty(o)))
  165.             options[o] = defaultOptions[o];
  166.     if (typeof options.kind === "string") {
  167.         switch (options.kind) {
  168.             case 'single':
  169.                 options.kind = simpleLink;
  170.                 break;
  171.             case 'complete':
  172.                 options.kind = completeLink;
  173.                 break;
  174.             case 'average':
  175.                 options.kind = averageLink;
  176.                 break;
  177.             case 'centroid':
  178.                 options.kind = centroidLink;
  179.                 break;
  180.             case 'ward':
  181.                 options.kind = wardLink;
  182.                 break;
  183.             default:
  184.                 throw new RangeError('Unknown kind of similarity');
  185.         }
  186.     }
  187.     else if (typeof options.kind !== "function")
  188.         throw new TypeError('Undefined kind of similarity');
  189.     var tree = new Cluster();
  190.     tree.children = new Array(data.length);
  191.     tree.index = new Array(data.length);
  192.     for (var ind = 0; ind < data.length; ind++) {
  193.         tree.children[ind] = new ClusterLeaf(ind);
  194.         tree.index[ind] = new ClusterLeaf(ind);
  195.     }

  196.     tree.distance = intrDist(tree.index, data, options.dist);
  197.     var m, M, clId,
  198.         dist, rebel;
  199.     var list = [tree];
  200.     while (list.length > 0) {
  201.         M = 0;
  202.         clId = 0;
  203.         for (var i = 0; i < list.length; i++) {
  204.             m = 0;
  205.             for (var j = 0; j < list[i].length; j++) {
  206.                 for (var l = (j + 1); l < list[i].length; l++) {
  207.                     m = Math.max(options.dist(data[list[i].index[j].index], data[list[i].index[l].index]), m);
  208.                 }
  209.             }
  210.             if (m > M) {
  211.                 M = m;
  212.                 clId = i;
  213.             }
  214.         }
  215.         M = 0;
  216.         if (list[clId].index.length === 2) {
  217.             list[clId].children = [list[clId].index[0], list[clId].index[1]];
  218.             list[clId].distance = options.dist(data[list[clId].index[0].index], data[list[clId].index[1].index]);
  219.         }
  220.         else if (list[clId].index.length === 3) {
  221.             list[clId].children = [list[clId].index[0], list[clId].index[1], list[clId].index[2]];
  222.             var d = [
  223.                 options.dist(data[list[clId].index[0].index], data[list[clId].index[1].index]),
  224.                 options.dist(data[list[clId].index[1].index], data[list[clId].index[2].index])
  225.             ];
  226.             list[clId].distance = (d[0] + d[1]) / 2;
  227.         }
  228.         else {
  229.             var C = new Cluster();
  230.             var sG = new Cluster();
  231.             var splitting = [new Array(list[clId].index.length), []];
  232.             for (var spl = 0; spl < splitting[0].length; spl++)
  233.                 splitting[0][spl] = spl;
  234.             for (var ii = 0; ii < splitting[0].length; ii++) {
  235.                 dist = 0;
  236.                 for (var jj = 0; jj < splitting[0].length; jj++)
  237.                     if (ii !== jj)
  238.                         dist += options.dist(data[list[clId].index[splitting[0][jj]].index], data[list[clId].index[splitting[0][ii]].index]);
  239.                 dist /= (splitting[0].length - 1);
  240.                 if (dist > M) {
  241.                     M = dist;
  242.                     rebel = ii;
  243.                 }
  244.             }
  245.             splitting[1] = [rebel];
  246.             splitting[0].splice(rebel, 1);
  247.             dist = diff(splitting, data, options.dist);
  248.             while (dist.d > 0) {
  249.                 splitting[1].push(splitting[0][dist.p]);
  250.                 splitting[0].splice(dist.p, 1);
  251.                 dist = diff(splitting, data, options.dist);
  252.             }
  253.             var fData = new Array(splitting[0].length);
  254.             C.index = new Array(splitting[0].length);
  255.             for (var e = 0; e < fData.length; e++) {
  256.                 fData[e] = data[list[clId].index[splitting[0][e]].index];
  257.                 C.index[e] = list[clId].index[splitting[0][e]];
  258.                 C.children[e] = list[clId].index[splitting[0][e]];
  259.             }
  260.             var sData = new Array(splitting[1].length);
  261.             sG.index = new Array(splitting[1].length);
  262.             for (var f = 0; f < sData.length; f++) {
  263.                 sData[f] = data[list[clId].index[splitting[1][f]].index];
  264.                 sG.index[f] = list[clId].index[splitting[1][f]];
  265.                 sG.children[f] = list[clId].index[splitting[1][f]];
  266.             }
  267.             C.distance = intrDist(C.index, data, options.dist);
  268.             sG.distance = intrDist(sG.index, data, options.dist);
  269.             list.push(C);
  270.             list.push(sG);
  271.             list[clId].children = [C, sG];
  272.         }
  273.         list.splice(clId, 1);
  274.     }
  275.     return tree;
  276. }

  277. module.exports = diana;
复制代码


藤椅
ReneeBK 发表于 2016-6-27 00:18:01

AGNES (AGglomerative NESting)

  1. 'use strict';

  2. var euclidean = require('ml-euclidean-distance');
  3. var ClusterLeaf = require('./ClusterLeaf');
  4. var Cluster = require('./Cluster');

  5. /**
  6. * @param cluster1
  7. * @param cluster2
  8. * @param disFun
  9. * @returns {number}
  10. */
  11. function simpleLink(cluster1, cluster2, disFun) {
  12.     var m = 10e100;
  13.     for (var i = 0; i < cluster1.length; i++)
  14.         for (var j = i; j < cluster2.length; j++) {
  15.             var d = disFun(cluster1[i], cluster2[j]);
  16.             m = Math.min(d,m);
  17.         }
  18.     return m;
  19. }

  20. /**
  21. * @param cluster1
  22. * @param cluster2
  23. * @param disFun
  24. * @returns {number}
  25. */
  26. function completeLink(cluster1, cluster2, disFun) {
  27.     var m = -1;
  28.     for (var i = 0; i < cluster1.length; i++)
  29.         for (var j = i; j < cluster2.length; j++) {
  30.             var d = disFun(cluster1[i], cluster2[j]);
  31.             m = Math.max(d,m);
  32.         }
  33.     return m;
  34. }

  35. /**
  36. * @param cluster1
  37. * @param cluster2
  38. * @param disFun
  39. * @returns {number}
  40. */
  41. function averageLink(cluster1, cluster2, disFun) {
  42.     var m = 0;
  43.     for (var i = 0; i < cluster1.length; i++)
  44.         for (var j = 0; j < cluster2.length; j++)
  45.             m += disFun(cluster1[i], cluster2[j]);
  46.     return m / (cluster1.length * cluster2.length);
  47. }

  48. /**
  49. * @param cluster1
  50. * @param cluster2
  51. * @param disFun
  52. * @returns {*}
  53. */
  54. function centroidLink(cluster1, cluster2, disFun) {
  55.     var x1 = 0,
  56.         y1 = 0,
  57.         x2 = 0,
  58.         y2 = 0;
  59.     for (var i = 0; i < cluster1.length; i++) {
  60.         x1 += cluster1[i][0];
  61.         y1 += cluster1[i][1];
  62.     }
  63.     for (var j = 0; j < cluster2.length; j++) {
  64.         x2 += cluster2[j][0];
  65.         y2 += cluster2[j][1];
  66.     }
  67.     x1 /= cluster1.length;
  68.     y1 /= cluster1.length;
  69.     x2 /= cluster2.length;
  70.     y2 /= cluster2.length;
  71.     return disFun([x1,y1], [x2,y2]);
  72. }

  73. /**
  74. * @param cluster1
  75. * @param cluster2
  76. * @param disFun
  77. * @returns {number}
  78. */
  79. function wardLink(cluster1, cluster2, disFun) {
  80.     var x1 = 0,
  81.         y1 = 0,
  82.         x2 = 0,
  83.         y2 = 0;
  84.     for (var i = 0; i < cluster1.length; i++) {
  85.         x1 += cluster1[i][0];
  86.         y1 += cluster1[i][1];
  87.     }
  88.     for (var j = 0; j < cluster2.length; j++) {
  89.         x2 += cluster2[j][0];
  90.         y2 += cluster2[j][1];
  91.     }
  92.     x1 /= cluster1.length;
  93.     y1 /= cluster1.length;
  94.     x2 /= cluster2.length;
  95.     y2 /= cluster2.length;
  96.     return disFun([x1,y1], [x2,y2])*cluster1.length*cluster2.length / (cluster1.length+cluster2.length);
  97. }

  98. var defaultOptions = {
  99.     disFunc: euclidean,
  100.     kind: 'single'
  101. };

  102. /**
  103. * Continuously merge nodes that have the least dissimilarity
  104. * @param {Array <Array <number>>} data - Array of points to be clustered
  105. * @param {json} options
  106. * @constructor
  107. */
  108. function agnes(data, options) {
  109.     options = options || {};
  110.     for (var o in defaultOptions)
  111.         if (!(options.hasOwnProperty(o)))
  112.             options[o] = defaultOptions[o];
  113.     var len = data.length;

  114.     // allows to use a string or a given function
  115.     if (typeof options.kind === "string") {
  116.         switch (options.kind) {
  117.             case 'single':
  118.                 options.kind = simpleLink;
  119.                 break;
  120.             case 'complete':
  121.                 options.kind = completeLink;
  122.                 break;
  123.             case 'average':
  124.                 options.kind = averageLink;
  125.                 break;
  126.             case 'centroid':
  127.                 options.kind = centroidLink;
  128.                 break;
  129.             case 'ward':
  130.                 options.kind = wardLink;
  131.                 break;
  132.             default:
  133.                 throw new RangeError('Unknown kind of similarity');
  134.         }
  135.     }
  136.     else if (typeof options.kind !== "function")
  137.         throw new TypeError('Undefined kind of similarity');

  138.     var list = new Array(len);
  139.     for (var i = 0; i < data.length; i++)
  140.         list[i] = new ClusterLeaf(i);
  141.     var min  = 10e5,
  142.         d = {},
  143.         dis = 0;

  144.     while (list.length > 1) {

  145.         // calculates the minimum distance
  146.         d = {};
  147.         min = 10e5;
  148.         for (var j = 0; j < list.length; j++)
  149.             for (var k = j + 1; k < list.length; k++) {
  150.                 var fData, sData;
  151.                 if (list[j] instanceof ClusterLeaf)
  152.                     fData = [data[list[j].index]];
  153.                 else {
  154.                     fData = new Array(list[j].index.length);
  155.                     for (var e = 0; e < fData.length; e++)
  156.                         fData[e] = data[list[j].index[e].index];
  157.                 }
  158.                 if (list[k] instanceof ClusterLeaf)
  159.                     sData = [data[list[k].index]];
  160.                 else {
  161.                     sData = new Array(list[k].index.length);
  162.                     for (var f = 0; f < sData.length; f++)
  163.                         sData[f] = data[list[k].index[f].index];
  164.                 }
  165.                 dis = options.kind(fData, sData, options.disFunc).toFixed(4);
  166.                 if (dis in d) {
  167.                     d[dis].push([list[j], list[k]]);
  168.                 }
  169.                 else {
  170.                     d[dis] = [[list[j], list[k]]];
  171.                 }
  172.                 min = Math.min(dis, min);
  173.             }

  174.         // cluster dots
  175.         var dmin = d[min.toFixed(4)];
  176.         var clustered = new Array(dmin.length);
  177.         var aux,
  178.             count = 0;
  179.         while (dmin.length > 0) {
  180.             aux = dmin.shift();
  181.             for (var q = 0; q < dmin.length; q++) {
  182.                 var int = dmin[q].filter(function(n) {
  183.                     //noinspection JSReferencingMutableVariableFromClosure
  184.                     return aux.indexOf(n) !== -1
  185.                 });
  186.                 if (int.length > 0) {
  187.                     var diff = dmin[q].filter(function(n) {
  188.                         //noinspection JSReferencingMutableVariableFromClosure
  189.                         return aux.indexOf(n) === -1
  190.                     });
  191.                     aux = aux.concat(diff);
  192.                     dmin.splice(q-- ,1);
  193.                 }
  194.             }
  195.             clustered[count++] = aux;
  196.         }
  197.         clustered.length = count;

  198.         for (var ii = 0; ii < clustered.length; ii++) {
  199.             var obj = new Cluster();
  200.             obj.children = clustered[ii].concat();
  201.             obj.distance = min;
  202.             obj.index = new Array(len);
  203.             var indCount = 0;
  204.             for (var jj = 0; jj < clustered[ii].length; jj++) {
  205.                 if (clustered[ii][jj] instanceof ClusterLeaf)
  206.                     obj.index[indCount++] = clustered[ii][jj];
  207.                 else {
  208.                     indCount += clustered[ii][jj].index.length;
  209.                     obj.index = clustered[ii][jj].index.concat(obj.index);
  210.                 }
  211.                 list.splice((list.indexOf(clustered[ii][jj])), 1);
  212.             }
  213.             obj.index.length = indCount;
  214.             list.push(obj);
  215.         }
  216.     }
  217.     return list[0];
  218. }

  219. module.exports = agnes;
复制代码


板凳
ReneeBK 发表于 2016-6-27 00:20:40
  1. 'use strict';

  2. function Cluster () {
  3.     this.children = [];
  4.     this.distance = -1;
  5.     this.index = [];
  6. }

  7. /**
  8. * Creates an array of values where maximum distance smaller than the threshold
  9. * @param {number} threshold
  10. * @return {Array <Cluster>}
  11. */
  12. Cluster.prototype.cut = function (threshold) {
  13.     if (threshold < 0) throw new RangeError('Threshold too small');
  14.     var root = new Cluster();
  15.     root.children = this.children;
  16.     root.distance = this.distance;
  17.     root.index = this.index;
  18.     var list = [root];
  19.     var ans = [];
  20.     while (list.length > 0) {
  21.         var aux = list.shift();
  22.         if (threshold >= aux.distance)
  23.             ans.push(aux);
  24.         else
  25.             list = list.concat(aux.children);
  26.     }
  27.     return ans;
  28. };

  29. /**
  30. * Merge the leaves in the minimum way to have 'minGroups' number of clusters
  31. * @param {number} minGroups
  32. * @return {Cluster}
  33. */
  34. Cluster.prototype.group = function (minGroups) {
  35.     if (minGroups < 1) throw new RangeError('Number of groups too small');
  36.     var root = new Cluster();
  37.     root.children = this.children;
  38.     root.distance = this.distance;
  39.     root.index = this.index;
  40.     if (minGroups === 1)
  41.         return root;
  42.     var list = [root];
  43.     var aux;
  44.     while (list.length < minGroups && list.length !== 0) {
  45.         aux = list.shift();
  46.         list = list.concat(aux.children);
  47.     }
  48.     if (list.length === 0) throw new RangeError('Number of groups too big');
  49.     for (var i = 0; i < list.length; i++)
  50.         if (list[i].distance === aux.distance) {
  51.             list.concat(list[i].children.slice(1));
  52.             list[i] = list[i].children[0];
  53.         }
  54.     for (var j = 0; j < list.length; j++)
  55.         if (list[j].distance !== 0) {
  56.             var obj = list[j];
  57.             obj.children = obj.index;
  58.         }
  59.     return root;
  60. };

  61. module.exports = Cluster;
复制代码

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2026-1-2 01:43