UNPKG

nodeml

Version:

node.js machine learning package

232 lines (193 loc) 5.37 kB
'use strict'; module.exports = function () { let app = this; let assert = (condition, message) => { if (!condition) { message = message || "Assertion failed"; if (typeof Error !== "undefined") { throw new Error(message); } throw message; } }; let _trained = null; app.setModel = (trained) => { _trained = trained; }; app.getModel = () => _trained; let initialize = (method, k, dataset, labels)=> { let center = []; if(labels) { let map = {}, mapid = 0, r = []; for(let i = 0 ; i < labels.length ; i++) { if(typeof map[labels[i]] == 'undefined') { map[labels[i]] = mapid; mapid++; } r[i] = map[labels[i]]; } k = mapid; center = Array.apply(null, Array(k)); let centerSum = Array.apply(null, Array(k)).map(Number.prototype.valueOf, 0); for(let n = 0 ; n < dataset.length ; n++) { let _k = r[n] * 1; let x = dataset[n]; if(!center[_k]) { center[_k] = {}; } for(let key in x) { if(!center[_k][key]) center[_k][key] = 0; center[_k][key] += x[key] * 1; } centerSum[_k]++; } for(let _k = 0 ; _k < center.length ; _k++) for(let _key in center[_k]) center[_k][_key] = center[_k][_key] / centerSum[_k * 1]; } else if(method == 'forgy') { } else if(method == 'random') { let preRand = {}; while(true) { let rand = Math.floor(Math.random() * dataset.length); if(preRand[rand]) continue; if(dataset[rand]) { center.push(dataset[rand]); preRand[rand] = true; } if(center.length == k) break; } } return center; }; // euclidean distance let distance = (x, y)=> { let sum = 0; let keys = {}; for(let key in x) keys[key] = true; for(let key in y) keys[key] = true; for(let key in keys) { let xd = x[key] ? x[key] * 1 : 0; let yd = y[key] ? y[key] * 1 : 0; sum += (xd - yd) * (xd - yd); } return Math.sqrt(sum); }; let em = (center, dataset)=> { let r = []; for(let n = 0 ; n < dataset.length ; n++) { let x = dataset[n]; let minDist = -1, rn = 0; for(let k = 0 ; k < center.length ; k++) { let dist = distance(dataset[n], center[k]); if(minDist === -1 || minDist > dist) { minDist = dist; rn = k; } } r[n] = rn; } center = Array.apply(null, Array(center.length)); let centerSum = Array.apply(null, Array(center.length)).map(Number.prototype.valueOf, 0); for(let n = 0 ; n < dataset.length ; n++) { let k = r[n] * 1; let x = dataset[n]; if(!center[k]) center[k] = {}; for(let key in x) { if(!center[k][key]) center[k][key] = 0; center[k][key] += x[key] * 1; } centerSum[k]++; } for(let k = 0 ; k < center.length ; k++) { for(let _key in center[k]) { center[k][_key] = center[k][_key] / centerSum[k * 1]; } } let J = 0; for(let n = 0 ; n < dataset.length ; n++) { let x = dataset[n]; let minDist = -1; for(let k = 0 ; k < center.length ; k++) { let dist = distance(dataset[n], center[k]); if(minDist === -1 || minDist > dist) { minDist = dist; } } J += minDist; } return {center: center, J: J}; }; app.train = (dataset, opts) => { assert(dataset, `dataset undefined`); // options if(!opts) opts = {}; let { init, dm, proc, iter, labels, k } = opts; if(!init) init = 'random'; // initializing method if(!dm) dm = 0; // distortion measure threshold if(!iter) iter = -1; // maximum iteration if(!proc) proc = ()=> {}; // process handler // check dataset if (Array.isArray(dataset) === false) dataset = [dataset]; else if (typeof dataset[0] != 'object') dataset = [dataset]; let n = dataset.length; if(!k) k = Math.floor(Math.sqrt(n / 2)); if(k === 0) k = 1; let map = {}, mapid = 0; if(labels) { for(let i = 0 ; i < labels.length ; i++) { if(typeof map[labels[i]] == 'undefined') { map[labels[i]] = mapid; mapid++; } } let tmp = {}; for(let key in map) tmp[map[key]] = key; map = tmp; } // initialize centre vector let center = initialize(init, k, dataset, labels); if(center.length == 0) { init = 'random'; center = initialize(init, k, dataset); } // iteration until J will be the smallest let _iter = 0; let preJ = 0; while(true) { if(iter !== -1 && iter < _iter) break; let _em = em(center, dataset); center = _em.center; let J = _em.J; let diff = Math.abs(preJ - J); proc(_iter, J, diff); if(diff <= dm) break; preJ = J; _iter++; } _trained = { center: center, map: map }; return _trained; }; app.test = (dataset) => { assert(dataset, `dataset undefined`); if (Array.isArray(dataset) === false) dataset = [dataset]; else if (typeof dataset[0] != 'object') dataset = [dataset]; let center = _trained.center; let map = _trained.map; let result = []; for(let n = 0 ; n < dataset.length ; n++) { let x = dataset[n]; let minDist = -1, rn = 0; for(let k = 0 ; k < center.length ; k++) { let dist = distance(dataset[n], center[k]); if(minDist === -1 || minDist > dist) { minDist = dist; rn = k; } } result[n] = map[rn] ? map[rn] : rn; } return result; }; return app; };