kinit.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. const
  2. Distance = require("./distance.js"),
  3. eudist = Distance.eudist,
  4. dist = Distance.dist;
  5. module.exports = {
  6. kmrand(data,k) {
  7. var map = {}, ks = [], t = k<<2;
  8. var len = data.length;
  9. var multi = data[0].length>0;
  10. while(ks.length<k && (t--)>0) {
  11. let d = data[Math.floor(Math.random()*len)];
  12. let key = multi? d.join("_") : `${d}`;
  13. if(!map[key]) {
  14. map[key] = true;
  15. ks.push(d);
  16. }
  17. }
  18. if(ks.length<k) throw new Error("Error initializating clusters");
  19. else return ks;
  20. },
  21. /**
  22. * K-means++ initial centroid selection
  23. */
  24. kmpp(data,k) {
  25. var distance = data[0].length? eudist : dist;
  26. var ks = [], len = data.length;
  27. var multi = data[0].length>0;
  28. var map = {};
  29. // First random centroid
  30. var c = data[Math.floor(Math.random()*len)];
  31. var key = multi? c.join("_") : `${c}`;
  32. ks.push(c);
  33. map[key] = true;
  34. // Retrieve next centroids
  35. while(ks.length<k) {
  36. // Min Distances between current centroids and data points
  37. let dists = [], lk = ks.length;
  38. let dsum = 0, prs = [];
  39. for(let i=0;i<len;i++) {
  40. let min = Infinity;
  41. for(let j=0;j<lk;j++) {
  42. let dist = distance(data[i],ks[j]);
  43. if(dist<=min) min = dist;
  44. }
  45. dists[i] = min;
  46. }
  47. // Sum all min distances
  48. for(let i=0;i<len;i++) {
  49. dsum += dists[i]
  50. }
  51. // Probabilities and cummulative prob (cumsum)
  52. for(let i=0;i<len;i++) {
  53. prs[i] = {i:i, v:data[i], pr:dists[i]/dsum, cs:0}
  54. }
  55. // Sort Probabilities
  56. prs.sort((a,b)=>a.pr-b.pr);
  57. // Cummulative Probabilities
  58. prs[0].cs = prs[0].pr;
  59. for(let i=1;i<len;i++) {
  60. prs[i].cs = prs[i-1].cs + prs[i].pr;
  61. }
  62. // Randomize
  63. let rnd = Math.random();
  64. // Gets only the items whose cumsum >= rnd
  65. let idx = 0;
  66. while(idx<len-1 && prs[idx++].cs<rnd);
  67. ks.push(prs[idx-1].v);
  68. /*
  69. let done = false;
  70. while(!done) {
  71. // this is our new centroid
  72. c = prs[idx-1].v
  73. key = multi? c.join("_") : `${c}`;
  74. if(!map[key]) {
  75. map[key] = true;
  76. ks.push(c);
  77. done = true;
  78. }
  79. else {
  80. idx++;
  81. }
  82. }
  83. */
  84. }
  85. return ks;
  86. }
  87. }