/*********************************************************************** This file is part of KEEL-software, the Data Mining tool for regression, classification, clustering, pattern mining and so on. Copyright (C) 2004-2010 F. Herrera (herrera@decsai.ugr.es) L. S�nchez (luciano@uniovi.es) J. Alcal�-Fdez (jalcala@decsai.ugr.es) S. Garc�a (sglopez@ujaen.es) A. Fern�ndez (alberto.fernandez@ujaen.es) J. Luengo (julianlm@decsai.ugr.es) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ **********************************************************************/ package keel.Algorithms.Instance_Generation.VQ; import keel.Algorithms.Instance_Generation.Basic.PrototypeSet; import keel.Algorithms.Instance_Generation.Basic.Prototype; import keel.Algorithms.Instance_Generation.*; import keel.Algorithms.Instance_Generation.utilities.*; import keel.Algorithms.Instance_Generation.LVQ.*; import keel.Algorithms.Instance_Generation.utilities.KNN.*; import java.util.*; /** * Cluster of a prototype set. * @author diegoj */ public class Cluster { /** Centroid/Center of the cluster. */ protected Prototype centroid; /** Set of prototypes (minus the center) that forms the cluster. */ protected PrototypeSet set; /** Class of all the prototypes of the Cluster. */ protected double label; /** * Asssigns the center of the cluster. * @param centroid New center of the cluster. */ public void setCentroid(Prototype centroid){ this.centroid = centroid; } /** * Asssigns the class of the cluster. * @param label New label of the cluster. */ public void setLabel(double label){ this.label = label; } /** * Asssigns the set of prototypes of the cluster. * @param set New set of the cluster. */ public void setSet(PrototypeSet set){ this.set = set; } /** * Get the class of the cluster. * @return class of the elements of the cluster. */ public double getLabel(){ return label; } /** * Get the elements of the cluster. * @return set of the cluster. */ public PrototypeSet getPrototypeSet(){ return set; } /** * Add one element to the cluster. * @param t New prototype to be added to the cluster. */ public void add(Prototype t){ set.add(t); } /** * Get one element of the cluster. * @param i Index of the element to be returned. * @return ith prototype of the cluster. */ public Prototype get(int i){ return set.get(i); } /** * Construct a new cluster. * @param centroid Centroid of the cluster. * @param set Set of the cluster. */ public Cluster(Prototype centroid, PrototypeSet set) { this.centroid = centroid; this.set = set; this.label = centroid.label(); } /** * Construct a new cluster. * @param set Set of the cluster. * @param centroid Centroid of the cluster. */ public Cluster(PrototypeSet set, Prototype centroid) { this.centroid = centroid; this.set = set; this.label = centroid.label(); } /** * Returns the center of the cluster. * @return Center of the cluster. */ public Prototype center(){ return centroid; } /** * Returns the center of the cluster. * @return Center of the cluster. */ public Prototype getCentroid(){ return centroid; } /** * Returns the Medium Squared Error of the cluster. * @return MSE of the cluster. */ public double fitness() { double acca = 0.0; for(Prototype pa : set) acca += Distance.dSquared(pa, centroid); return acca; } /** * Computes the average prototype of the cluster. * @return Average prototype of the cluster. */ public Prototype avg(){ return set.avg(); } /** * Returns the size of the cluster. * @return Size of the cluster. */ public int size(){ return set.size(); } /** * Use the nearest neighbor condition to make a partition in two cluster which have got this centers. * @param center1 Center of the first set. * @param center2 Center of the second set. * @return Pair of clusters. */ protected Pair<Cluster, Cluster> partititonWhoseCentersAre(Prototype center1, Prototype center2) { PrototypeSet one = new PrototypeSet(); PrototypeSet two = new PrototypeSet(); PrototypeSet centerSet = new PrototypeSet(); centerSet.add(center1); centerSet.add(center2); Debug.endsIf(center1 == center2, "Centers are the same, it is not allowed."); for(Prototype p : set) { Prototype q = centerSet.nearestTo(p); if(q == center1) { one.add(p); //Debug.errorln("ONE"); } else if(q == center2) { two.add(p); //Debug.errorln("TWOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"); } else if(q==null) Debug.goout("q is null"); else Debug.goout("partitionWhoseCentersAre gone wrong wrong wrong!"); } Cluster c1 = new Cluster(one, center1); Cluster c2 = new Cluster(two, center2); return new Pair<Cluster,Cluster>(c1, c2); } /** * Distorsion of the cluster (sum of distances of the prototypes to the center). * @return Sumatory of the distances of the set to the center. */ protected double distorsion(Prototype center) { double acc = 0; for(Prototype p : set) acc += Distance.d(p, center); return acc/(double)set.size(); } /** * Distorsion of two sets, given two centers. * @param centers Centers of the pair of clusters. * @param part Clusters. * @return Sum of the distorison(part1,center1)+distorison(part2,center2) */ protected static double distorsion(Pair<Prototype,Prototype> centers, Pair<Cluster,Cluster> part) { double d1 = part.first().distorsion(centers.first()); double d2 = part.second().distorsion(centers.second()); return d1 + d2; } /*public boolean isNearestPrototype(Prototype pseudoCenter) { int count = 0; for(Prototype p : set) if(pseudoCenter != p) { Prototype q = set.nearestTo(p); if(Distance.d(p, pseudoCenter) <= Distance.d(p, q)) ++count; } return count > 0; }*/ /** * Part the cluster by the LBG method. * @param epsilon Maximum error tolerated. * @return A partition of the cluster in two new clusters. */ public Pair<Cluster,Cluster> _2LBGPartition(double epsilon) { int size = set.size(); int last = size-1; double D1 = Double.POSITIVE_INFINITY; ArrayList<Integer> r = null; //boolean nearestOfSomebody = false; //do //{ r = RandomGenerator.generateDifferentRandomIntegers(0, last, 2); Prototype p1 = set.get(r.get(0)); Prototype p2 = set.get(r.get(1)); //Debug.errorln("Elegimos " + r.get(0) + " last es " + last); //Debug.errorln("Elegimos " + r.get(1) + " last es " + last); // nearestOfSomebody = isNearestPrototype(p1) && isNearestPrototype(p2); //} //while(!nearestOfSomebody); //old centers Pair<Prototype,Prototype> Y = new Pair<Prototype,Prototype>(p1, p2); //empieza el juego boolean termination = false; Pair<Cluster,Cluster> partition = null; int it=0; do { //Debug.errorln("Iteración " + (it++)); //Partición por la nearest-neighbor condition Pair<Cluster, Cluster> P = partititonWhoseCentersAre(Y.first(), Y.second()); double Dm = distorsion(Y, P); //Debug.errorln("Distorsion: " + Dm); double value = Math.abs(D1 - Dm) / Dm; //Debug.errorln("Cociente = " + value + " epsilon es " + epsilon); if (value <= epsilon) { //return P; termination = true; partition = P; } else { D1 = Dm; Prototype newCenter1 = P.first().avg();//CC Prototype newCenter2 = P.second().avg();//CC Y = new Pair<Prototype, Prototype>(newCenter1, newCenter2); } } while (!termination); return partition; } /** * Returns the centers of the cluster obtained by LBG method. * @param epsilon Maximum error tolerated. * @return Centers of the LBG clusters. */ public Pair<Prototype,Prototype> centersOfLBGCLuster(double epsilon) { Pair<Cluster,Cluster> c = _2LBGPartition(epsilon); return new Pair<Prototype,Prototype>(c.first().center(), c.second().center()); } /** * Informs if the centroid of the cluster is its nearest prototype. * @param p Prototype to be tested. * @return TRUE if p nearest prototype is the centroid of the cluster, FALSE in other chase. */ public boolean isCentroidItsNearestPrototoype(Prototype p) { return centroid == set.nearestTo(p); } }