all these changes

This commit is contained in:
Jake Kasper
2026-04-09 13:19:47 -05:00
parent e83a51a051
commit 65315f36d1
39102 changed files with 7932979 additions and 567 deletions

64
frontend/node_modules/density-clustering/.jscsrc generated vendored Normal file
View File

@@ -0,0 +1,64 @@
{
"requireCurlyBraces": [
"if",
"else",
"for",
"while",
"do",
"try",
"catch"
],
"requireOperatorBeforeLineBreak": true,
"requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties",
"maximumLineLength": {
"value": 80,
"allowComments": true,
"allowRegex": true
},
"validateIndentation": 2,
"validateQuoteMarks": "'",
"disallowMultipleLineStrings": true,
"disallowMixedSpacesAndTabs": true,
"disallowTrailingWhitespace": true,
"disallowSpaceAfterPrefixUnaryOperators": true,
"disallowKeywordsOnNewLine": ["else"],
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"return",
"try",
"catch"
],
"requireSpaceBeforeBinaryOperators": [
"=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=",
"&=", "|=", "^=", "+=",
"+", "-", "*", "/", "%", "<<", ">>", ">>>", "&",
"|", "^", "&&", "||", "===", "==", ">=",
"<=", "<", ">", "!=", "!=="
],
"requireSpaceAfterBinaryOperators": true,
"requireSpacesInConditionalExpression": true,
"requireSpaceBeforeBlockStatements": true,
"requireSpacesInForStatement": true,
"requireLineFeedAtFileEnd": true,
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"disallowSpacesInAnonymousFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInsideObjectBrackets": "nested",
"disallowSpacesInsideArrayBrackets": "all",
"disallowSpacesInsideParentheses": true,
"disallowMultipleLineBreaks": true,
"disallowNewlineBeforeBlockStatements": true,
"disallowMultipleVarDecl": true
}

5
frontend/node_modules/density-clustering/.jshintrc generated vendored Normal file
View File

@@ -0,0 +1,5 @@
{
// suppresses warnings about the use of expression
// where normally you would expect to see assignments or function calls
"expr": true
}

View File

@@ -0,0 +1,13 @@
{
"uploadOnSave": true,
"hostname": "192.168.111.202",
"port": "22",
"target": "/var/www/clustering",
"ignore": [
".git/**"
],
"username": "abeja",
"keyfile": "C:\\Users\\lukasz\\lukasz_key",
"passphrase": "aabbeejjaa",
"transport": "scp"
}

11
frontend/node_modules/density-clustering/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,11 @@
v.1.3.0
- bower compatibility (huge thanks to ([@tim42](https://github.com/tim42)))
v.1.2.1
- unit test fix
v.1.2.0
- DBSCAN, OPTICS - include core point in region query
v.1.1.0
- Add K-Means algorithm

22
frontend/node_modules/density-clustering/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License
Copyright © 2013 Abeja Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in the
Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The software is provided “as is”, without warranty of any kind, express or
implied, including but not limited to the warranties of merchantability, fitness
for a particular purpose and noninfringement. In no event shall the authors or
copyright holders be liable for any claim, damages or other liability, whether
in an action of contract, tort or otherwise, arising from, out of or in
connection with the software or the use or other dealings in the software.

171
frontend/node_modules/density-clustering/README.md generated vendored Normal file
View File

@@ -0,0 +1,171 @@
# Density Based Clustering for JavaScript
Package contains popular methods for cluster analysis in data mining:
- DBSCAN
- OPTICS
- K-MEANS
# Overview
### DBSCAN
Density-based spatial clustering of applications with noise (DBSCAN) is one of the most popular algorithm for clustering data.
http://en.wikipedia.org/wiki/DBSCAN
### OPTICS
Ordering points to identify the clustering structure (OPTICS) is an algorithm for clustering data similar to DBSCAN.
The main difference between OPTICS and DBSCAN is that it can handle data of varying densities.
http://en.wikipedia.org/wiki/OPTICS_algorithm
**Important**
Clustering returned by OPTICS is nearly indistinguishable from a clustering created by DBSCAN.
To extract different density-based clustering as well as hierarchical structure you need to analyse **reachability plot** generated by OPTICS.
For more information visit http://en.wikipedia.org/wiki/OPTICS_algorithm#Extracting_the_clusters
### K-MEANS
K-means clustering is one of the most popular method of vector quantization, originally from signal processing.
Although this method is **not density-based**, it's included in the library for completeness.
http://en.wikipedia.org/wiki/K-means_clustering
## Installation
Node:
```bash
npm install density-clustering
```
Browser:
```bash
bower install density-clustering
# build
npm install
gulp
```
## Examples
### DBSCAN
```js
var dataset = [
[1,1],[0,1],[1,0],
[10,10],[10,13],[13,13],
[54,54],[55,55],[89,89],[57,55]
];
var clustering = require('density-clustering');
var dbscan = new clustering.DBSCAN();
// parameters: 5 - neighborhood radius, 2 - number of points in neighborhood to form a cluster
var clusters = dbscan.run(dataset, 5, 2);
console.log(clusters, dbscan.noise);
/*
RESULT:
[
[0,1,2],
[3,4,5],
[6,7,9],
[8]
]
NOISE: [ 8 ]
*/
```
### OPTICS
```js
// REGULAR DENSITY
var dataset = [
[1,1],[0,1],[1,0],
[10,10],[10,11],[11,10],
[50,50],[51,50],[50,51],
[100,100]
];
var clustering = require('density-clustering');
var optics = new clustering.OPTICS();
// parameters: 2 - neighborhood radius, 2 - number of points in neighborhood to form a cluster
var clusters = optics.run(dataset, 2, 2);
var plot = optics.getReachabilityPlot();
console.log(clusters, plot);
/*
RESULT:
[
[0,1,2],
[3,4,5],
[6,7,8],
[9]
]
*/
```
```js
// VARYING DENSITY
var dataset = [
[0,0],[6,0],[-1,0],[0,1],[0,-1],
[45,45],[45.1,45.2],[45.1,45.3],[45.8,45.5],[45.2,45.3],
[50,50],[56,50],[50,52],[50,55],[50,51]
];
var clustering = require('density-clustering');
var optics = new clustering.OPTICS();
// parameters: 6 - neighborhood radius, 2 - number of points in neighborhood to form a cluster
var clusters = optics.run(dataset, 6, 2);
var plot = optics.getReachabilityPlot();
console.log(clusters, plot);
/*
RESULT:
[
[0, 2, 3, 4],
[1],
[5, 6, 7, 9, 8],
[10, 14, 12, 13],
[11]
]
*/
```
### K-MEANS
```js
var dataset = [
[1,1],[0,1],[1,0],
[10,10],[10,13],[13,13],
[54,54],[55,55],[89,89],[57,55]
];
var clustering = require('density-clustering');
var kmeans = new clustering.KMEANS();
// parameters: 3 - number of clusters
var clusters = kmeans.run(dataset, 3);
console.log(clusters);
/*
RESULT:
[
[0,1,2,3,4,5],
[6,7,9],
[8]
]
*/
```
## Testing
Open folder and run:
```bash
mocha -R spec
```
## License
Software is licensed under MIT license.
For more information check LICENSE file.

40
frontend/node_modules/density-clustering/bower.json generated vendored Normal file
View File

@@ -0,0 +1,40 @@
{
"name": "density-clustering",
"version": "1.3.0",
"description": "Density Based Clustering in JavaScript",
"main": "./dist/clustering.min.js",
"directories": {
"example": "example",
"test": "test"
},
"dependencies": {},
"devDependencies": {},
"repository": {
"type": "git",
"url": "https://github.com/LukaszKrawczyk/density-clustering.git"
},
"keywords": [
"DBSCAN",
"OPTICS",
"K-Means",
"clustering",
"cluster",
"analysis",
"machine",
"learning",
"statistics"
],
"authors": {
"name": "Lukasz Krawczyk"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/LukaszKrawczyk/density-clustering/issues"
},
"homepage": "https://github.com/LukaszKrawczyk/density-clustering",
"ignore": [
"**/.*",
"node_modules",
"bower_components"
]
}

View File

@@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<title>Clustering</title>
<meta charset="utf-8"/>
</head>
<body>
<script src="../dist/clustering.js"></script>
<script>
var dbscan = new DBSCAN();
var dataset = [
[1, 1], [0, 1], [1, 0],
[10, 10], [10, 13], [13, 13],
[30, 30], [30, 33], [49, 49], [33, 33], [36, 36]
];
console.log(dbscan.run(dataset, 5, 2));
</script>
</body>
</html>

View File

@@ -0,0 +1,11 @@
var DBSCAN = require('../lib/index.js').DBSCAN;
var dataset = [
[1,1],[0,1],[1,0],
[10,10],[13,13],[10,13],
[54,54],[55,55],[89,89],[57,55]
];
var dbscan = new DBSCAN();
var clusters = dbscan.run(dataset, 5, 2);
console.log(clusters);

View File

@@ -0,0 +1,11 @@
var KMEANS = require('../lib/index.js').KMEANS;
var dataset = [
[1,1],[0,1],[1,0],
[10,10],[10,13],[13,13],
[54,54],[55,55],[89,89],[57,55]
];
var kmeans = new KMEANS();
var clusters = kmeans.run(dataset, 3);
console.log(clusters);

View File

@@ -0,0 +1,12 @@
var OPTICS = require('../lib/index.js').OPTICS;
var dataset = [
[1,1],[0,1],[1,0],
[10,10],[13,13],[10,13],
[54,54],[55,55],[89,89],[57,55],
[20.01, 20.05],[20.09, 20.07],[20.20, 20.15],[20.09, 20.12]
];
var optics = new OPTICS();
var clusters = optics.run(dataset, 5, 2);
console.log(clusters);

View File

@@ -0,0 +1,12 @@
var PriorityQueue = require('../lib/index.js').PriorityQueue;
var p = new PriorityQueue();
p.insert(1, 4);
p.insert(2, 1);
p.insert(3, 2);
p.insert(4, 3);
p.insert(4, 5);
console.log(p.getElements());
var p = new PriorityQueue([1,2,3,4,4], [4,1,2,3,5]);
console.log(p.getElements());

30
frontend/node_modules/density-clustering/gulpfile.js generated vendored Normal file
View File

@@ -0,0 +1,30 @@
(function () {
'use strict';
// dependencies
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var resolveDependencies = require('gulp-resolve-dependencies');
// source
var sources = './lib/*.js';
gulp.task('build', function () {
return gulp.src(sources)
.pipe(resolveDependencies())
.pipe(concat('clustering.js'))
.pipe(gulp.dest('./dist'))
;
});
gulp.task('build-min', ['build'], function () {
return gulp.src('./dist/clustering.js')
.pipe(uglify())
.pipe(concat('clustering.min.js'))
.pipe(gulp.dest('./dist'))
;
});
gulp.task('default', ['build-min']);
})();

236
frontend/node_modules/density-clustering/lib/DBSCAN.js generated vendored Normal file
View File

@@ -0,0 +1,236 @@
/**
* DBSCAN - Density based clustering
*
* @author Lukasz Krawczyk <contact@lukaszkrawczyk.eu>
* @copyright MIT
*/
/**
* DBSCAN class construcotr
* @constructor
*
* @param {Array} dataset
* @param {number} epsilon
* @param {number} minPts
* @param {function} distanceFunction
* @returns {DBSCAN}
*/
function DBSCAN(dataset, epsilon, minPts, distanceFunction) {
/** @type {Array} */
this.dataset = [];
/** @type {number} */
this.epsilon = 1;
/** @type {number} */
this.minPts = 2;
/** @type {function} */
this.distance = this._euclideanDistance;
/** @type {Array} */
this.clusters = [];
/** @type {Array} */
this.noise = [];
// temporary variables used during computation
/** @type {Array} */
this._visited = [];
/** @type {Array} */
this._assigned = [];
/** @type {number} */
this._datasetLength = 0;
this._init(dataset, epsilon, minPts, distanceFunction);
};
/******************************************************************************/
// public functions
/**
* Start clustering
*
* @param {Array} dataset
* @param {number} epsilon
* @param {number} minPts
* @param {function} distanceFunction
* @returns {undefined}
* @access public
*/
DBSCAN.prototype.run = function(dataset, epsilon, minPts, distanceFunction) {
this._init(dataset, epsilon, minPts, distanceFunction);
for (var pointId = 0; pointId < this._datasetLength; pointId++) {
// if point is not visited, check if it forms a cluster
if (this._visited[pointId] !== 1) {
this._visited[pointId] = 1;
// if closest neighborhood is too small to form a cluster, mark as noise
var neighbors = this._regionQuery(pointId);
if (neighbors.length < this.minPts) {
this.noise.push(pointId);
} else {
// create new cluster and add point
var clusterId = this.clusters.length;
this.clusters.push([]);
this._addToCluster(pointId, clusterId);
this._expandCluster(clusterId, neighbors);
}
}
}
return this.clusters;
};
/******************************************************************************/
// protected functions
/**
* Set object properties
*
* @param {Array} dataset
* @param {number} epsilon
* @param {number} minPts
* @param {function} distance
* @returns {undefined}
* @access protected
*/
DBSCAN.prototype._init = function(dataset, epsilon, minPts, distance) {
if (dataset) {
if (!(dataset instanceof Array)) {
throw Error('Dataset must be of type array, ' +
typeof dataset + ' given');
}
this.dataset = dataset;
this.clusters = [];
this.noise = [];
this._datasetLength = dataset.length;
this._visited = new Array(this._datasetLength);
this._assigned = new Array(this._datasetLength);
}
if (epsilon) {
this.epsilon = epsilon;
}
if (minPts) {
this.minPts = minPts;
}
if (distance) {
this.distance = distance;
}
};
/**
* Expand cluster to closest points of given neighborhood
*
* @param {number} clusterId
* @param {Array} neighbors
* @returns {undefined}
* @access protected
*/
DBSCAN.prototype._expandCluster = function(clusterId, neighbors) {
/**
* It's very important to calculate length of neighbors array each time,
* as the number of elements changes over time
*/
for (var i = 0; i < neighbors.length; i++) {
var pointId2 = neighbors[i];
if (this._visited[pointId2] !== 1) {
this._visited[pointId2] = 1;
var neighbors2 = this._regionQuery(pointId2);
if (neighbors2.length >= this.minPts) {
neighbors = this._mergeArrays(neighbors, neighbors2);
}
}
// add to cluster
if (this._assigned[pointId2] !== 1) {
this._addToCluster(pointId2, clusterId);
}
}
};
/**
* Add new point to cluster
*
* @param {number} pointId
* @param {number} clusterId
*/
DBSCAN.prototype._addToCluster = function(pointId, clusterId) {
this.clusters[clusterId].push(pointId);
this._assigned[pointId] = 1;
};
/**
* Find all neighbors around given point
*
* @param {number} pointId,
* @param {number} epsilon
* @returns {Array}
* @access protected
*/
DBSCAN.prototype._regionQuery = function(pointId) {
var neighbors = [];
for (var id = 0; id < this._datasetLength; id++) {
var dist = this.distance(this.dataset[pointId], this.dataset[id]);
if (dist < this.epsilon) {
neighbors.push(id);
}
}
return neighbors;
};
/******************************************************************************/
// helpers
/**
* @param {Array} a
* @param {Array} b
* @returns {Array}
* @access protected
*/
DBSCAN.prototype._mergeArrays = function(a, b) {
var len = b.length;
for (var i = 0; i < len; i++) {
var P = b[i];
if (a.indexOf(P) < 0) {
a.push(P);
}
}
return a;
};
/**
* Calculate euclidean distance in multidimensional space
*
* @param {Array} p
* @param {Array} q
* @returns {number}
* @access protected
*/
DBSCAN.prototype._euclideanDistance = function(p, q) {
var sum = 0;
var i = Math.min(p.length, q.length);
while (i--) {
sum += (p[i] - q[i]) * (p[i] - q[i]);
}
return Math.sqrt(sum);
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = DBSCAN;
}

213
frontend/node_modules/density-clustering/lib/KMEANS.js generated vendored Normal file
View File

@@ -0,0 +1,213 @@
/**
* KMEANS clustering
*
* @author Lukasz Krawczyk <contact@lukaszkrawczyk.eu>
* @copyright MIT
*/
/**
* KMEANS class constructor
* @constructor
*
* @param {Array} dataset
* @param {number} k - number of clusters
* @param {function} distance - distance function
* @returns {KMEANS}
*/
function KMEANS(dataset, k, distance) {
this.k = 3; // number of clusters
this.dataset = []; // set of feature vectors
this.assignments = []; // set of associated clusters for each feature vector
this.centroids = []; // vectors for our clusters
this.init(dataset, k, distance);
}
/**
* @returns {undefined}
*/
KMEANS.prototype.init = function(dataset, k, distance) {
this.assignments = [];
this.centroids = [];
if (typeof dataset !== 'undefined') {
this.dataset = dataset;
}
if (typeof k !== 'undefined') {
this.k = k;
}
if (typeof distance !== 'undefined') {
this.distance = distance;
}
};
/**
* @returns {undefined}
*/
KMEANS.prototype.run = function(dataset, k) {
this.init(dataset, k);
var len = this.dataset.length;
// initialize centroids
for (var i = 0; i < this.k; i++) {
this.centroids[i] = this.randomCentroid();
}
var change = true;
while(change) {
// assign feature vectors to clusters
change = this.assign();
// adjust location of centroids
for (var centroidId = 0; centroidId < this.k; centroidId++) {
var mean = new Array(maxDim);
var count = 0;
// init mean vector
for (var dim = 0; dim < maxDim; dim++) {
mean[dim] = 0;
}
for (var j = 0; j < len; j++) {
var maxDim = this.dataset[j].length;
// if current cluster id is assigned to point
if (centroidId === this.assignments[j]) {
for (var dim = 0; dim < maxDim; dim++) {
mean[dim] += this.dataset[j][dim];
}
count++;
}
}
if (count > 0) {
// if cluster contain points, adjust centroid position
for (var dim = 0; dim < maxDim; dim++) {
mean[dim] /= count;
}
this.centroids[centroidId] = mean;
} else {
// if cluster is empty, generate new random centroid
this.centroids[centroidId] = this.randomCentroid();
change = true;
}
}
}
return this.getClusters();
};
/**
* Generate random centroid
*
* @returns {Array}
*/
KMEANS.prototype.randomCentroid = function() {
var maxId = this.dataset.length -1;
var centroid;
var id;
do {
id = Math.round(Math.random() * maxId);
centroid = this.dataset[id];
} while (this.centroids.indexOf(centroid) >= 0);
return centroid;
}
/**
* Assign points to clusters
*
* @returns {boolean}
*/
KMEANS.prototype.assign = function() {
var change = false;
var len = this.dataset.length;
var closestCentroid;
for (var i = 0; i < len; i++) {
closestCentroid = this.argmin(this.dataset[i], this.centroids, this.distance);
if (closestCentroid != this.assignments[i]) {
this.assignments[i] = closestCentroid;
change = true;
}
}
return change;
}
/**
* Extract information about clusters
*
* @returns {undefined}
*/
KMEANS.prototype.getClusters = function() {
var clusters = new Array(this.k);
var centroidId;
for (var pointId = 0; pointId < this.assignments.length; pointId++) {
centroidId = this.assignments[pointId];
// init empty cluster
if (typeof clusters[centroidId] === 'undefined') {
clusters[centroidId] = [];
}
clusters[centroidId].push(pointId);
}
return clusters;
};
// utils
/**
* @params {Array} point
* @params {Array.<Array>} set
* @params {Function} f
* @returns {number}
*/
KMEANS.prototype.argmin = function(point, set, f) {
var min = Number.MAX_VALUE;
var arg = 0;
var len = set.length;
var d;
for (var i = 0; i < len; i++) {
d = f(point, set[i]);
if (d < min) {
min = d;
arg = i;
}
}
return arg;
};
/**
* Euclidean distance
*
* @params {number} p
* @params {number} q
* @returns {number}
*/
KMEANS.prototype.distance = function(p, q) {
var sum = 0;
var i = Math.min(p.length, q.length);
while (i--) {
var diff = p[i] - q[i];
sum += diff * diff;
}
return Math.sqrt(sum);
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = KMEANS;
}

269
frontend/node_modules/density-clustering/lib/OPTICS.js generated vendored Normal file
View File

@@ -0,0 +1,269 @@
/**
* @requires ./PriorityQueue.js
*/
if (typeof module !== 'undefined' && module.exports) {
var PriorityQueue = require('./PriorityQueue.js');
}
/**
* OPTICS - Ordering points to identify the clustering structure
*
* @author Lukasz Krawczyk <contact@lukaszkrawczyk.eu>
* @copyright MIT
*/
/**
* OPTICS class constructor
* @constructor
*
* @param {Array} dataset
* @param {number} epsilon
* @param {number} minPts
* @param {function} distanceFunction
* @returns {OPTICS}
*/
function OPTICS(dataset, epsilon, minPts, distanceFunction) {
/** @type {number} */
this.epsilon = 1;
/** @type {number} */
this.minPts = 1;
/** @type {function} */
this.distance = this._euclideanDistance;
// temporary variables used during computation
/** @type {Array} */
this._reachability = [];
/** @type {Array} */
this._processed = [];
/** @type {number} */
this._coreDistance = 0;
/** @type {Array} */
this._orderedList = [];
this._init(dataset, epsilon, minPts, distanceFunction);
}
/******************************************************************************/
// pulic functions
/**
* Start clustering
*
* @param {Array} dataset
* @returns {undefined}
* @access public
*/
OPTICS.prototype.run = function(dataset, epsilon, minPts, distanceFunction) {
this._init(dataset, epsilon, minPts, distanceFunction);
for (var pointId = 0, l = this.dataset.length; pointId < l; pointId++) {
if (this._processed[pointId] !== 1) {
this._processed[pointId] = 1;
this.clusters.push([pointId]);
var clusterId = this.clusters.length - 1;
this._orderedList.push(pointId);
var priorityQueue = new PriorityQueue(null, null, 'asc');
var neighbors = this._regionQuery(pointId);
// using priority queue assign elements to new cluster
if (this._distanceToCore(pointId) !== undefined) {
this._updateQueue(pointId, neighbors, priorityQueue);
this._expandCluster(clusterId, priorityQueue);
}
}
}
return this.clusters;
};
/**
* Generate reachability plot for all points
*
* @returns {array}
* @access public
*/
OPTICS.prototype.getReachabilityPlot = function() {
var reachabilityPlot = [];
for (var i = 0, l = this._orderedList.length; i < l; i++) {
var pointId = this._orderedList[i];
var distance = this._reachability[pointId];
reachabilityPlot.push([pointId, distance]);
}
return reachabilityPlot;
};
/******************************************************************************/
// protected functions
/**
* Set object properties
*
* @param {Array} dataset
* @param {number} epsilon
* @param {number} minPts
* @param {function} distance
* @returns {undefined}
* @access protected
*/
OPTICS.prototype._init = function(dataset, epsilon, minPts, distance) {
if (dataset) {
if (!(dataset instanceof Array)) {
throw Error('Dataset must be of type array, ' +
typeof dataset + ' given');
}
this.dataset = dataset;
this.clusters = [];
this._reachability = new Array(this.dataset.length);
this._processed = new Array(this.dataset.length);
this._coreDistance = 0;
this._orderedList = [];
}
if (epsilon) {
this.epsilon = epsilon;
}
if (minPts) {
this.minPts = minPts;
}
if (distance) {
this.distance = distance;
}
};
/**
* Update information in queue
*
* @param {number} pointId
* @param {Array} neighbors
* @param {PriorityQueue} queue
* @returns {undefined}
* @access protected
*/
OPTICS.prototype._updateQueue = function(pointId, neighbors, queue) {
var self = this;
this._coreDistance = this._distanceToCore(pointId);
neighbors.forEach(function(pointId2) {
if (self._processed[pointId2] === undefined) {
var dist = self.distance(self.dataset[pointId], self.dataset[pointId2]);
var newReachableDistance = Math.max(self._coreDistance, dist);
if (self._reachability[pointId2] === undefined) {
self._reachability[pointId2] = newReachableDistance;
queue.insert(pointId2, newReachableDistance);
} else {
if (newReachableDistance < self._reachability[pointId2]) {
self._reachability[pointId2] = newReachableDistance;
queue.remove(pointId2);
queue.insert(pointId2, newReachableDistance);
}
}
}
});
};
/**
* Expand cluster
*
* @param {number} clusterId
* @param {PriorityQueue} queue
* @returns {undefined}
* @access protected
*/
OPTICS.prototype._expandCluster = function(clusterId, queue) {
var queueElements = queue.getElements();
for (var p = 0, l = queueElements.length; p < l; p++) {
var pointId = queueElements[p];
if (this._processed[pointId] === undefined) {
var neighbors = this._regionQuery(pointId);
this._processed[pointId] = 1;
this.clusters[clusterId].push(pointId);
this._orderedList.push(pointId);
if (this._distanceToCore(pointId) !== undefined) {
this._updateQueue(pointId, neighbors, queue);
this._expandCluster(clusterId, queue);
}
}
}
};
/**
* Calculating distance to cluster core
*
* @param {number} pointId
* @returns {number}
* @access protected
*/
OPTICS.prototype._distanceToCore = function(pointId) {
var l = this.epsilon;
for (var coreDistCand = 0; coreDistCand < l; coreDistCand++) {
var neighbors = this._regionQuery(pointId, coreDistCand);
if (neighbors.length >= this.minPts) {
return coreDistCand;
}
}
return;
};
/**
* Find all neighbors around given point
*
* @param {number} pointId
* @param {number} epsilon
* @returns {Array}
* @access protected
*/
OPTICS.prototype._regionQuery = function(pointId, epsilon) {
epsilon = epsilon || this.epsilon;
var neighbors = [];
for (var id = 0, l = this.dataset.length; id < l; id++) {
if (this.distance(this.dataset[pointId], this.dataset[id]) < epsilon) {
neighbors.push(id);
}
}
return neighbors;
};
/******************************************************************************/
// helpers
/**
* Calculate euclidean distance in multidimensional space
*
* @param {Array} p
* @param {Array} q
* @returns {number}
* @access protected
*/
OPTICS.prototype._euclideanDistance = function(p, q) {
var sum = 0;
var i = Math.min(p.length, q.length);
while (i--) {
sum += (p[i] - q[i]) * (p[i] - q[i]);
}
return Math.sqrt(sum);
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = OPTICS;
}

View File

@@ -0,0 +1,180 @@
/**
* PriorityQueue
* Elements in this queue are sorted according to their value
*
* @author Lukasz Krawczyk <contact@lukaszkrawczyk.eu>
* @copyright MIT
*/
/**
* PriorityQueue class construcotr
* @constructor
*
* @example
* queue: [1,2,3,4]
* priorities: [4,1,2,3]
* > result = [1,4,2,3]
*
* @param {Array} elements
* @param {Array} priorities
* @param {string} sorting - asc / desc
* @returns {PriorityQueue}
*/
function PriorityQueue(elements, priorities, sorting) {
/** @type {Array} */
this._queue = [];
/** @type {Array} */
this._priorities = [];
/** @type {string} */
this._sorting = 'desc';
this._init(elements, priorities, sorting);
};
/**
* Insert element
*
* @param {Object} ele
* @param {Object} priority
* @returns {undefined}
* @access public
*/
PriorityQueue.prototype.insert = function(ele, priority) {
var indexToInsert = this._queue.length;
var index = indexToInsert;
while (index--) {
var priority2 = this._priorities[index];
if (this._sorting === 'desc') {
if (priority > priority2) {
indexToInsert = index;
}
} else {
if (priority < priority2) {
indexToInsert = index;
}
}
}
this._insertAt(ele, priority, indexToInsert);
};
/**
* Remove element
*
* @param {Object} ele
* @returns {undefined}
* @access public
*/
PriorityQueue.prototype.remove = function(ele) {
var index = this._queue.length;
while (index--) {
var ele2 = this._queue[index];
if (ele === ele2) {
this._queue.splice(index, 1);
this._priorities.splice(index, 1);
break;
}
}
};
/**
* For each loop wrapper
*
* @param {function} func
* @returs {undefined}
* @access public
*/
PriorityQueue.prototype.forEach = function(func) {
this._queue.forEach(func);
};
/**
* @returns {Array}
* @access public
*/
PriorityQueue.prototype.getElements = function() {
return this._queue;
};
/**
* @param {number} index
* @returns {Object}
* @access public
*/
PriorityQueue.prototype.getElementPriority = function(index) {
return this._priorities[index];
};
/**
* @returns {Array}
* @access public
*/
PriorityQueue.prototype.getPriorities = function() {
return this._priorities;
};
/**
* @returns {Array}
* @access public
*/
PriorityQueue.prototype.getElementsWithPriorities = function() {
var result = [];
for (var i = 0, l = this._queue.length; i < l; i++) {
result.push([this._queue[i], this._priorities[i]]);
}
return result;
};
/**
* Set object properties
*
* @param {Array} elements
* @param {Array} priorities
* @returns {undefined}
* @access protected
*/
PriorityQueue.prototype._init = function(elements, priorities, sorting) {
if (elements && priorities) {
this._queue = [];
this._priorities = [];
if (elements.length !== priorities.length) {
throw new Error('Arrays must have the same length');
}
for (var i = 0; i < elements.length; i++) {
this.insert(elements[i], priorities[i]);
}
}
if (sorting) {
this._sorting = sorting;
}
};
/**
* Insert element at given position
*
* @param {Object} ele
* @param {number} index
* @returns {undefined}
* @access protected
*/
PriorityQueue.prototype._insertAt = function(ele, priority, index) {
if (this._queue.length === index) {
this._queue.push(ele);
this._priorities.push(priority);
} else {
this._queue.splice(index, 0, ele);
this._priorities.splice(index, 0, priority);
}
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = PriorityQueue;
}

37
frontend/node_modules/density-clustering/lib/Utils.js generated vendored Normal file
View File

@@ -0,0 +1,37 @@
function Utils() {
}
KMEANS.prototype.getRandomVector = function(extremes) {
var maxDim = extremes.length;
var x = [];
var r = 0;
// calculate radius of n-sphere which covers all points in dataset
var nSphereRadius = 0;
for (var i = 0; i < maxDim; i++) {
var extreme = extremes[i];
var er = Math.max(extreme.center - extreme.min, extreme.center - extreme.max);
if (er > nSphereRadius)
nSphereRadius = er;
}
for (var i = 0; i < maxDim; i++) {
var val = (Math.random() * 2) - 1;
// adjust to radius of n-sphere
x.push(val);
r += val * val;
}
r = Math.sqrt(r);
for (var i = 0; i < maxDim; i++) {
x[i] /= r;
// resize to fit n-sphere
x[i] *= nSphereRadius;
x[i] += extremes[i].center;
}
return x;
}

View File

@@ -0,0 +1,9 @@
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
DBSCAN: require('./DBSCAN.js'),
KMEANS: require('./KMEANS.js'),
OPTICS: require('./OPTICS.js'),
PriorityQueue: require('./PriorityQueue.js')
};
}

46
frontend/node_modules/density-clustering/package.json generated vendored Normal file
View File

@@ -0,0 +1,46 @@
{
"name": "density-clustering",
"version": "1.3.0",
"description": "Density Based Clustering in JavaScript",
"main": "./lib/index.js",
"directories": {
"example": "example",
"test": "test"
},
"dependencies": {},
"devDependencies": {
"mocha": "^2.2.4",
"should": "^5.2.0",
"gulp": "^3.9.0",
"gulp-concat": "^2.5.2",
"gulp-uglify": "^1.2.0",
"gulp-resolve-dependencies": "^2.1.0"
},
"scripts": {
"test": "mocha -R spec"
},
"repository": {
"type": "git",
"url": "https://github.com/LukaszKrawczyk/density-clustering.git"
},
"keywords": [
"DBSCAN",
"OPTICS",
"K-Means",
"clustering",
"cluster",
"analysis",
"machine",
"learning",
"statistics"
],
"author": {
"name": "Lukasz Krawczyk"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/LukaszKrawczyk/density-clustering/issues"
},
"homepage": "https://github.com/LukaszKrawczyk/density-clustering"
}

View File

@@ -0,0 +1,73 @@
require('should');
var DBSCAN = require('../lib/index.js').DBSCAN;
describe('DBSCAN', function() {
describe('run', function() {
it('should return correct clusters for regular density set', function() {
var dbscan = new DBSCAN();
var dataset = [
[1, 1], [0, 1], [1, 0],
[10, 10], [10, 13], [13, 13],
[30, 30], [30, 33], [49, 49], [33, 33], [36, 36]
];
// small radius
dbscan.run(dataset, 5, 2)
.should.be.eql([
[0, 1, 2],
[3, 4, 5],
[6, 7, 9, 10]
]);
dbscan.noise.should.eql([8]);
// big radius
dbscan.run(dataset, 50, 2).should.be.eql([
[0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 8]
]);
dbscan.noise.should.eql([]);
});
});
describe('regionQuery', function() {
it('should return nearest neighborhood of a point', function() {
var dataset = [
[1, 1], [2, 2], [3, 3],
[50, 50], [51, 51]
];
var dbscan = new DBSCAN(dataset);
dbscan.epsilon = 1;
dbscan._regionQuery(1).should.eql([1]);
dbscan.epsilon = 2;
dbscan._regionQuery(1).should.eql([0, 1, 2]);
dbscan._regionQuery(4).should.eql([3, 4]);
dbscan.epsilon = 100;
dbscan._regionQuery(1).should.eql([0, 1, 2, 3, 4]);
});
});
describe('mergeArrays', function() {
it('should merge two arrays', function() {
var dbscan = new DBSCAN();
dbscan._mergeArrays([1, 2, 3], [2, 3, 4, 5])
.should.eql([1, 2, 3, 4, 5]);
dbscan._mergeArrays([2, 3, 4, 5], [1, 2, 3])
.should.eql([2, 3, 4, 5, 1]);
});
});
describe('euclideanDistance', function() {
it('should return distance between two points', function() {
var dbscan = new DBSCAN();
dbscan._euclideanDistance([1, 1], [3, 1]).should.eql(2);
dbscan._euclideanDistance([1, 1], [1, 3]).should.eql(2);
});
});
});

View File

@@ -0,0 +1,70 @@
require('should');
var KMEANS = require('../lib/index.js').KMEANS;
describe('KMEANS', function() {
describe('run', function() {
it('should return correct clusters', function() {
var kmeans = new KMEANS();
var k = 3;
var dataset = [
[1,1],[0,1],[1,0],
[10,10],[10,13],[13,13],
[54,54],[55,55],[89,89],[57,55]
];
var clusters = kmeans.run(dataset, k);
clusters.should.have.lengthOf(k);
clusters.forEach(function(cluster) {
(cluster instanceof Array).should.be.true;
cluster.length.should.be.greaterThan(0);
});
});
it('should return correct clusters for high dimensional data', function() {
var kmeans = new KMEANS();
var k = 4;
var dataset = generateData(k, 10, 10);
var clusters = kmeans.run(dataset, k);
clusters.should.have.lengthOf(k);
clusters.forEach(function(cluster) {
(cluster instanceof Array).should.be.true;
cluster.length.should.be.greaterThan(0);
});
});
});
describe('randomCentroid', function() {
it('should return extremes', function() {
var dataset = [
[-10, -20], [0,0], [30, 20]
];
var kmeans = new KMEANS(dataset);
var centroid = kmeans.randomCentroid();
centroid[0].should.be.within(-10, 30);
centroid[1].should.be.within(-20, 20);
});
});
});
function generateData(clusters, points, dimensions) {
var dataset = [];
for (var i = 0; i < clusters; i++) {
for (var p = 0; p < points; p++) {
var point = new Array(dimensions);
for (var d = 0; d < dimensions; d++) {
point[d] = Math.random() + (i * 100);
}
dataset.push(point);
}
}
return dataset;
}

View File

@@ -0,0 +1,98 @@
require('should');
var clustering = require('../lib/index.js');
var OPTICS = clustering.OPTICS;
describe('OPTICS', function() {
describe('run', function() {
it('should test regular density set', function() {
var dataset = [
[1, 1], [0, 1], [1, 0],
[10, 10], [10, 11], [11, 10],
[50, 50], [51, 50], [50, 51],
[100, 100]
];
var optics = new OPTICS();
var clusters = optics.run(dataset, 2, 2);
clusters.should.be.eql([
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[9]
]);
});
it('should test various density set', function() {
var dataset = [
[0, 0], [6, 0], [-1, 0], [0, 1], [0, -1],
[45, 45], [45.1, 45.2], [45.1, 45.3], [45.8, 45.5],
[45.2, 45.3],
[50, 50], [56, 50], [50, 52], [50, 55], [50, 51]
];
var optics = new OPTICS();
var clusters = optics.run(dataset, 6, 2);
clusters.should.be.eql([
[0, 2, 3, 4],
[1],
[5, 6, 7, 9, 8],
[10, 14, 12, 13],
[11]
]);
});
});
describe('regionQuery', function() {
it('should return nearest neighborhood of a point', function() {
var optics = new OPTICS();
optics.dataset = [
[1, 1], [2, 2], [3, 3],
[50, 50], [51, 51]
];
optics.epsilon = 2;
optics._regionQuery(1).should.eql([0, 1, 2]);
optics._regionQuery(4).should.eql([3, 4]);
optics.epsilon = 100;
optics._regionQuery(1).should.eql([0, 1, 2, 3, 4]);
});
});
describe('euclideanDistance', function() {
it('should return distance between two points', function() {
var optics = new OPTICS();
optics._euclideanDistance([1, 1], [3, 1]).should.eql(2);
optics._euclideanDistance([1, 1], [1, 3]).should.eql(2);
});
});
describe('getReachabilityPlot', function() {
it('should return reachability plot', function() {
var optics = new OPTICS();
var plot;
var dataset = [
[1, 1], [0, 1], [1, 0],
[10, 10], [10, 11], [11, 10]
];
optics.run(dataset, 2, 2);
plot = optics.getReachabilityPlot();
plot.should.eql([
[0, undefined], [1, 1], [2, 1],
[3, undefined], [4, 1], [5, 1]
]);
// reachability plot should be always the same for different epsilon values
optics.run(dataset, 10, 2);
plot = optics.getReachabilityPlot();
plot.should.eql([
[0, undefined], [1, 1], [2, 1],
[3, undefined], [4, 1], [5, 1]
]);
});
});
});

View File

@@ -0,0 +1,27 @@
require('should');
var PriorityQueue = require('../lib/index.js').PriorityQueue;
describe('PriorityQueue', function() {
describe('insert', function() {
it('should return correct result', function() {
var p = new PriorityQueue();
p.insert(1, 4);
p.insert(2, 1);
p.insert(3, 2);
p.insert(4, 3);
p.getElements().should.eql([1, 4, 3, 2]);
p.getPriorities().should.eql([4, 3, 2, 1]);
});
});
describe('init', function() {
it('should initialize queue correctly', function() {
var p = new PriorityQueue([1, 2, 3, 4], [4, 1, 2, 3]);
p.getElements().should.eql([1, 4, 3, 2]);
p.getPriorities().should.eql([4, 3, 2, 1]);
});
});
});