/**
* Name: Agent Based Clustering
* Author: Jean-Danie Zucker with Patrick Taillandier's and Arnaud Grignard's Help
* Description: This model displays the step to stpe algorithm of k-means
* See for https://en.wikipedia.org/wiki/K-means_clustering ...
* Clustering
* The k-medoid could be added
* To be added stop the simulation when convergence is reached
* To be added an overlay
* To be added position the points at the begining usug user interaction model...
*/
model MASKMEANS
global
{
// the number of classes to create (kmeans)
// It corresponds to the centroids
int k ;
// the number of points
int N ;
//number of dimensions
int dimensions <- 2;
float globalIntraDistance <- 0.0;
bool converged <- false;
font regular <- font("Helvetica", 14, # bold);
init
{
//create datapoints agents
create datapoints number: N
{
if (dimensions = 3)
{
location <- { rnd(100), rnd(100), rnd(100) };
}
if (dimensions = 2)
{
location <- { rnd(100), rnd(100) };
}
}
//create centroid agents
create centroids number: k
{
if (dimensions = 3)
{
location <- { rnd(100), rnd(100), rnd(100) };
}
if (dimensions = 2)
{
location <- { rnd(100), rnd(100) };
}
}
int K <- length(centroids);
if (K > 0) {loop i from:0 to: K-1 { ask centroids[i] { color_kmeans <- hsb(i/K,1,1); }}}
//give a random color to each centroid (i.e. to each datapoints agents of the group)
// loop c over: centroids { rgb col <- rnd_color(255); ask c { color_kmeans <- col;}}
}
reflex pauseAtConvergence when: converged { do pause;
}
reflex assign_points_to_centroid when: even(cycle)
{
// The "assignment" step is also referred to as expectation step,
ask centroids
{
mypoints <- list ([]);
}
loop pt over: datapoints
{
ask pt
{
if not empty(centroids) {
mycenter <- centroids closest_to self;
color_kmeans <- mycenter.color_kmeans;
add self to: mycenter.mypoints;
}
}
}
}
reflex update_centroids when: not even(cycle)
{
// the "update step" as maximization step,
// making this algorithm a variant of the generalized expectation-maximization algorithm.
//We give a random color to each group (i.e. to each datapoints agents of the group)
ask centroids where (not empty(each.mypoints))
{
location <- mean(mypoints collect each.location);
float oldist <- myIntraDistance;
myIntraDistance <- mypoints sum_of (each distance_to self);
converged <- (oldist-myIntraDistance) with_precision(2) = 0;
}
globalIntraDistance <- centroids sum_of (each.myIntraDistance);
}
}
species datapoints
{
rgb color_kmeans <- rgb(225,225,225) ;
centroids mycenter;
aspect kmeans_aspect2D
{
draw circle(2) color: color_kmeans border:color_kmeans-25;
}
aspect kmeans_aspect3D
{
draw sphere(2) color: color_kmeans ;
}
}
species centroids
{
rgb color_kmeans <- rgb(225,225,225);
list mypoints;
float myIntraDistance <- 0.0;
aspect kmeans_aspect2D
{
// explicitly loops over a copy of the points to avoid concurrency issues with the simulation
loop pt over: copy(mypoints)
{
draw line([location, pt]) + 0.1 color: color_kmeans;
}
draw cross(3, 0.5) color: color_kmeans border:color_kmeans-25;
}
aspect kmeans_aspect3D
{
loop pt over: mypoints
{
draw line([location, pt], 0.2) color: color_kmeans;
}
draw cube(5) color: color_kmeans border: # black;
}
}
experiment clustering2D type: gui
{
parameter "Number of clusters to split the data into" var: k init:4 category: "KMEANS";
parameter "Number of points to be clustered" var: N init: 500;
point target <- { 20, 95 };
output
{
display map_kmeans
{
species datapoints aspect: kmeans_aspect2D transparency:0.4;
species centroids aspect: kmeans_aspect2D;
graphics "Full target"
{
draw rectangle(120, 4) color: # yellow at: { 50, 2 };
draw rectangle(120, 4) color: # yellow at: target + { 30, 2 };
if (not even(cycle))
{
// the "update step" as maximization step, (a mean is done to recenter)
if ! (globalIntraDistance = 0) {
draw "Current step was an estimation Step (each point is assigned the color of his nearest centroid" at:{ 12, 2 } font: regular color: # green;
draw "Current sum of cluster intra-distance " + globalIntraDistance with_precision(1) at:{ 12, 4 } font: regular color: # black;
}
if converged {draw "Algorithm has converged !" + " cycle "+ cycle at:{ 60, 4 } font: regular color: # red;}
draw "Next step is a maximisation step the centroid will move to the center of its associated points" at: target + { 0, 3 } font: regular color: # red;
} else
{
if ! (globalIntraDistance = 0) {
draw "Current step was a maximisation step the centroid moved to the center of its associated points" at: { 12, 2 } font: regular color: # red;
draw "Current sum of cluster intra-distance " + globalIntraDistance with_precision(1) at:{ 12, 4 } font: regular color: # black;
}
if converged {draw "Algorithm has converged !" at:{ 60, 4 } font: regular color: # red;}
draw "Next step is an estimation Step (each point is assigned the color of his nearest centroid" at: target + { 0, 3 } font: regular color: # green;
}
}
}
}
}
experiment clustering3D type: gui
{
parameter "Number of clusters to split the data into" var: k init:4 min: 0 max: 10 category: "KMEANS";
parameter "Number of points to be clustered" var: N init:1000 ;
parameter "Number of dimensions (2D or 3D)" var: dimensions init: 3 min: 2 max: 3;
font regular <- font("Helvetica", 14, # bold);
point target <- { 20, 95 };
// The display is explicitly synchronized to avoid concurrency issues (if the points are changed in the simulation while being displayed)
output synchronized: true
{
display map_kmeans type: opengl
{
species datapoints aspect: kmeans_aspect3D transparency:0.4;
species centroids aspect: kmeans_aspect3D;
}
}
}