44 lines
8.9 KiB
JavaScript
44 lines
8.9 KiB
JavaScript
function DBSCAN(t,e,i,s){this.dataset=[],this.epsilon=1,this.minPts=2,this.distance=this._euclideanDistance,this.clusters=[],this.noise=[],this._visited=[],this._assigned=[],this._datasetLength=0,this._init(t,e,i,s)}function KMEANS(t,e,i){this.k=3,this.dataset=[],this.assignments=[],this.centroids=[],this.init(t,e,i)}function PriorityQueue(t,e,i){this._queue=[],this._priorities=[],this._sorting="desc",this._init(t,e,i)}function OPTICS(t,e,i,s){this.epsilon=1,this.minPts=1,this.distance=this._euclideanDistance,this._reachability=[],this._processed=[],this._coreDistance=0,this._orderedList=[],this._init(t,e,i,s)}function Utils(){}if(DBSCAN.prototype.run=function(t,e,i,s){this._init(t,e,i,s);for(var r=0;r<this._datasetLength;r++)if(1!==this._visited[r]){this._visited[r]=1;var n=this._regionQuery(r);if(n.length<this.minPts)this.noise.push(r);else{var o=this.clusters.length;this.clusters.push([]),this._addToCluster(r,o),this._expandCluster(o,n)}}return this.clusters},DBSCAN.prototype._init=function(t,e,i,s){if(t){if(!(t instanceof Array))throw Error("Dataset must be of type array, "+typeof t+" given");this.dataset=t,this.clusters=[],this.noise=[],this._datasetLength=t.length,this._visited=new Array(this._datasetLength),this._assigned=new Array(this._datasetLength)}e&&(this.epsilon=e),i&&(this.minPts=i),s&&(this.distance=s)},DBSCAN.prototype._expandCluster=function(t,e){for(var i=0;i<e.length;i++){var s=e[i];if(1!==this._visited[s]){this._visited[s]=1;var r=this._regionQuery(s);r.length>=this.minPts&&(e=this._mergeArrays(e,r))}1!==this._assigned[s]&&this._addToCluster(s,t)}},DBSCAN.prototype._addToCluster=function(t,e){this.clusters[e].push(t),this._assigned[t]=1},DBSCAN.prototype._regionQuery=function(t){for(var e=[],i=0;i<this._datasetLength;i++){var s=this.distance(this.dataset[t],this.dataset[i]);s<this.epsilon&&e.push(i)}return e},DBSCAN.prototype._mergeArrays=function(t,e){for(var i=e.length,s=0;i>s;s++){var r=e[s];t.indexOf(r)<0&&t.push(r)}return t},DBSCAN.prototype._euclideanDistance=function(t,e){for(var i=0,s=Math.min(t.length,e.length);s--;)i+=(t[s]-e[s])*(t[s]-e[s]);return Math.sqrt(i)},"undefined"!=typeof module&&module.exports&&(module.exports=DBSCAN),KMEANS.prototype.init=function(t,e,i){this.assignments=[],this.centroids=[],"undefined"!=typeof t&&(this.dataset=t),"undefined"!=typeof e&&(this.k=e),"undefined"!=typeof i&&(this.distance=i)},KMEANS.prototype.run=function(t,e){this.init(t,e);for(var i=this.dataset.length,s=0;s<this.k;s++)this.centroids[s]=this.randomCentroid();for(var r=!0;r;){r=this.assign();for(var n=0;n<this.k;n++){for(var o=new Array(d),h=0,a=0;d>a;a++)o[a]=0;for(var u=0;i>u;u++){var d=this.dataset[u].length;if(n===this.assignments[u]){for(var a=0;d>a;a++)o[a]+=this.dataset[u][a];h++}}if(h>0){for(var a=0;d>a;a++)o[a]/=h;this.centroids[n]=o}else this.centroids[n]=this.randomCentroid(),r=!0}}return this.getClusters()},KMEANS.prototype.randomCentroid=function(){var t,e,i=this.dataset.length-1;do e=Math.round(Math.random()*i),t=this.dataset[e];while(this.centroids.indexOf(t)>=0);return t},KMEANS.prototype.assign=function(){for(var t,e=!1,i=this.dataset.length,s=0;i>s;s++)t=this.argmin(this.dataset[s],this.centroids,this.distance),t!=this.assignments[s]&&(this.assignments[s]=t,e=!0);return e},KMEANS.prototype.getClusters=function(){for(var t,e=new Array(this.k),i=0;i<this.assignments.length;i++)t=this.assignments[i],"undefined"==typeof e[t]&&(e[t]=[]),e[t].push(i);return e},KMEANS.prototype.argmin=function(t,e,i){for(var s,r=Number.MAX_VALUE,n=0,o=e.length,h=0;o>h;h++)s=i(t,e[h]),r>s&&(r=s,n=h);return n},KMEANS.prototype.distance=function(t,e){for(var i=0,s=Math.min(t.length,e.length);s--;){var r=t[s]-e[s];i+=r*r}return Math.sqrt(i)},"undefined"!=typeof module&&module.exports&&(module.exports=KMEANS),PriorityQueue.prototype.insert=function(t,e){for(var i=this._queue.length,s=i;s--;){var r=this._priorities[s];"desc"===this._sorting?e>r&&(i=s):r>e&&(i=s)}this._insertAt(t,e,i)},PriorityQueue.prototype.remove=function(t){for(var e=this._queue.length;e--;){var i=this._queue[e];if(t===i){this._queue.splice(e,1),this._priorities.splice(e,1);break}}},PriorityQueue.prototype.forEach=function(t){this._queue.forEach(t)},PriorityQueue.prototype.getElements=function(){return this._queue},PriorityQueue.prototype.getElementPriority=function(t){return this._priorities[t]},PriorityQueue.prototype.getPriorities=function(){return this._priorities},PriorityQueue.prototype.getElementsWithPriorities=function(){for(var t=[],e=0,i=this._queue.length;i>e;e++)t.push([this._queue[e],this._priorities[e]]);return t},PriorityQueue.prototype._init=function(t,e,i){if(t&&e){if(this._queue=[],this._priorities=[],t.length!==e.length)throw new Error("Arrays must have the same length");for(var s=0;s<t.length;s++)this.insert(t[s],e[s])}i&&(this._sorting=i)},PriorityQueue.prototype._insertAt=function(t,e,i){this._queue.length===i?(this._queue.push(t),this._priorities.push(e)):(this._queue.splice(i,0,t),this._priorities.splice(i,0,e))},"undefined"!=typeof module&&module.exports&&(module.exports=PriorityQueue),"undefined"!=typeof module&&module.exports)var PriorityQueue=require("./PriorityQueue.js");OPTICS.prototype.run=function(t,e,i,s){this._init(t,e,i,s);for(var r=0,n=this.dataset.length;n>r;r++)if(1!==this._processed[r]){this._processed[r]=1,this.clusters.push([r]);var o=this.clusters.length-1;this._orderedList.push(r);var h=new PriorityQueue(null,null,"asc"),a=this._regionQuery(r);void 0!==this._distanceToCore(r)&&(this._updateQueue(r,a,h),this._expandCluster(o,h))}return this.clusters},OPTICS.prototype.getReachabilityPlot=function(){for(var t=[],e=0,i=this._orderedList.length;i>e;e++){var s=this._orderedList[e],r=this._reachability[s];t.push([s,r])}return t},OPTICS.prototype._init=function(t,e,i,s){if(t){if(!(t instanceof Array))throw Error("Dataset must be of type array, "+typeof t+" given");this.dataset=t,this.clusters=[],this._reachability=new Array(this.dataset.length),this._processed=new Array(this.dataset.length),this._coreDistance=0,this._orderedList=[]}e&&(this.epsilon=e),i&&(this.minPts=i),s&&(this.distance=s)},OPTICS.prototype._updateQueue=function(t,e,i){var s=this;this._coreDistance=this._distanceToCore(t),e.forEach(function(e){if(void 0===s._processed[e]){var r=s.distance(s.dataset[t],s.dataset[e]),n=Math.max(s._coreDistance,r);void 0===s._reachability[e]?(s._reachability[e]=n,i.insert(e,n)):n<s._reachability[e]&&(s._reachability[e]=n,i.remove(e),i.insert(e,n))}})},OPTICS.prototype._expandCluster=function(t,e){for(var i=e.getElements(),s=0,r=i.length;r>s;s++){var n=i[s];if(void 0===this._processed[n]){var o=this._regionQuery(n);this._processed[n]=1,this.clusters[t].push(n),this._orderedList.push(n),void 0!==this._distanceToCore(n)&&(this._updateQueue(n,o,e),this._expandCluster(t,e))}}},OPTICS.prototype._distanceToCore=function(t){for(var e=this.epsilon,i=0;e>i;i++){var s=this._regionQuery(t,i);if(s.length>=this.minPts)return i}},OPTICS.prototype._regionQuery=function(t,e){e=e||this.epsilon;for(var i=[],s=0,r=this.dataset.length;r>s;s++)this.distance(this.dataset[t],this.dataset[s])<e&&i.push(s);return i},OPTICS.prototype._euclideanDistance=function(t,e){for(var i=0,s=Math.min(t.length,e.length);s--;)i+=(t[s]-e[s])*(t[s]-e[s]);return Math.sqrt(i)},"undefined"!=typeof module&&module.exports&&(module.exports=OPTICS),KMEANS.prototype.getRandomVector=function(t){for(var e=t.length,i=[],s=0,r=0,n=0;e>n;n++){var o=t[n],h=Math.max(o.center-o.min,o.center-o.max);h>r&&(r=h)}for(var n=0;e>n;n++){var a=2*Math.random()-1;i.push(a),s+=a*a}s=Math.sqrt(s);for(var n=0;e>n;n++)i[n]/=s,i[n]*=r,i[n]+=t[n].center;return i},"undefined"!=typeof module&&module.exports&&(module.exports={DBSCAN:require("./DBSCAN.js"),KMEANS:require("./KMEANS.js"),OPTICS:require("./OPTICS.js"),PriorityQueue:require("./PriorityQueue.js")});
|
|
|
|
|
|
/**
|
|
* 方格聚合算法
|
|
* 1、根据 range 将当前屏幕分割成由 n 个正方形组成的矩形
|
|
* 2、遍历传过来的 posArr
|
|
* 3、计算每个 pos 对应所在的格子
|
|
*/
|
|
function getGridGroup(arrPos,range){
|
|
let width = 1870;
|
|
let heigh = 917;
|
|
let row = parseInt(heigh/range)+1;
|
|
let col = parseInt(width/range)+1;
|
|
let res = [];
|
|
let resGroup = [];
|
|
arrPos.forEach((screenPos,index)=>{
|
|
// screenPos[0] -> x
|
|
// screenPos[1] -> y
|
|
let x = parseInt(screenPos[0]/range);
|
|
let y = parseInt(screenPos[1]/range);
|
|
let nowGridIndex = parseInt((x*col + y)/range);
|
|
if(!res[nowGridIndex]){
|
|
res[nowGridIndex] = []
|
|
}
|
|
res[nowGridIndex].push(index)
|
|
})
|
|
res.forEach(i=>{
|
|
if(i.length>1){
|
|
resGroup.push(i)
|
|
}
|
|
})
|
|
return resGroup
|
|
}
|
|
|
|
|
|
let dbscan = new DBSCAN();
|
|
let kmeans = new KMEANS();
|
|
this.addEventListener('message',(msg)=>{
|
|
let posArr = JSON.parse(msg.data.posArr);
|
|
// this.postMessage({res:dbscan.run(posArr,msg.data.range),key:msg.data.key});
|
|
// this.postMessage({res:kmeans.run(posArr),key:msg.data.key});
|
|
this.postMessage({res:getGridGroup(posArr,msg.data.range),key:msg.data.key});
|
|
}) |