/*********************************************************************** 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/ **********************************************************************/ /** * <p> * @author Written by Juli�n Luengo Mart�n 03/12/2006 * @version 0.1 * @since JDK 1.5 * </p> */ package keel.Algorithms.Preprocess.Missing_Values.fkmeans; import java.io.*; import java.util.*; import keel.Dataset.*; /** * <p> * This class represents a group of centers (centroids) of a set of fuzzy clusters * </p> */ public class fuzzygCenter { String[][] gravCenters; int numCenters; double[][] membershipOf; int ndatos; double m; /** Creates a new instance of gCenter */ public fuzzygCenter() { gravCenters = null; membershipOf = null; numCenters = 0; ndatos = 0; m = 0; } /** * <p> * Creates a new instance of gCenter with provided number of centers, number of instances of the * data set and number of attributes * </p> * @param k Fixed number of centroids * @param ndatos number of instances in the data set related to this object * @param nvariables number of attributes * @param fuzzifier The parameter m (> 1) used to fuzzify the clusters */ public fuzzygCenter(int k, int ndatos, int nvariables, double fuzzifier) { gravCenters = new String[k][nvariables]; numCenters = k; m = fuzzifier; membershipOf = new double[ndatos][k]; this.ndatos = ndatos; } /** * <p> * Computes the distance between a instances (without previous normalization) and * one clusters (i.e. its centroid). * </p> * @param i The reference instance * @param k The cluster number * @return The Euclidean distance between i and k */ public double distance(Instance i, int k) { double dist = 0; int in = 0; int out = 0; int tipo = 0; int direccion = 0; int nvariables; nvariables = Attributes.getNumAttributes(); for (int l = 0; l < nvariables; l++) { Attribute a = Attributes.getAttribute(l); direccion = a.getDirectionAttribute(); tipo = a.getType(); if (direccion == Attribute.INPUT) { if (tipo != Attribute.NOMINAL && !i.getInputMissingValues(in) && gravCenters[k][l].compareTo("<null>")!=0) { // real value, apply euclidean distance dist += Math.sqrt((i.getInputRealValues(in) - (new Double( gravCenters[k][l]).doubleValue())) * (i.getInputRealValues(in) - (new Double( gravCenters[k][l]).doubleValue()))); } else { if (!i.getInputMissingValues(in) && i.getInputNominalValues(in) != gravCenters[k][l]) dist += 1; } in++; } else { if (direccion == Attribute.OUTPUT) { if (tipo != Attribute.NOMINAL && !i.getOutputMissingValues(out)) { dist += (i.getOutputRealValues(out) - (new Double( gravCenters[k][l]).doubleValue())) * (i.getOutputRealValues(out) - (new Double( gravCenters[k][l]).doubleValue())); } else { if (!i.getOutputMissingValues(out) && i.getOutputNominalValues(out) != gravCenters[k][l]) dist += 1; } out++; } } } return dist; } /** * <p> * this function initializes a center with the values of a given instance. * </p> * @param i the initialization instance * @param c the index of the cluster to be initialized */ public void copyCenter(Instance i, int c) { int in = 0; int out = 0; int tipo = 0; int direccion = 0; int nvariables; nvariables = Attributes.getNumAttributes(); for (int l = 0; l < nvariables; l++) { Attribute a = Attributes.getAttribute(l); direccion = a.getDirectionAttribute(); tipo = a.getType(); if (direccion == Attribute.INPUT) { if (tipo != Attribute.NOMINAL && !i.getInputMissingValues(in)) { // real value, apply euclidean distance gravCenters[c][l] = String .valueOf(i.getInputRealValues(in)); } else { if (!i.getInputMissingValues(in)) gravCenters[c][l] = i.getInputNominalValues(in); else{ gravCenters[c][l] = "<null>"; } } in++; } else { if (direccion == Attribute.OUTPUT) { if (tipo != Attribute.NOMINAL && !i.getOutputMissingValues(out)) { gravCenters[c][l] = String.valueOf(i .getOutputRealValues(out)); } else { if (!i.getOutputMissingValues(out)) { gravCenters[c][l] = i.getOutputNominalValues(out); } else gravCenters[c][l] = "<null>"; } out++; } } } } /** * <p> * Recalculates all the centroids using a given InstanceSet, to reduce the * sum of the distances for each object from the centroid of the cluster to which the object belongs * </p> * @param IS The reference InstanceSet */ public void recalculateCenters(InstanceSet IS) { int[] nInst = new int[numCenters]; double tmp; double Utotal = 0.0; Instance i; int c; int in = 0; int out = 0; int tipo = 0; int direccion = 0; int nvariables; FreqList[][] modes; String[][] oldGC; nvariables = Attributes.getNumAttributes(); modes = new FreqList[numCenters][nvariables]; oldGC = gravCenters; gravCenters = new String[numCenters][nvariables]; for (int a = 0; a < numCenters; a++) { Utotal = 0.0; for (int b = 0; b < ndatos; b++) { Utotal += membershipOf[b][a]; } for (int b = 0; b < nvariables; b++) { gravCenters[a][b] = "a"; modes[a][b] = new FreqList(); } c = a; for (int m = 0; m < ndatos; m++) { i = IS.getInstance(m); in = 0; out = 0; for (int l = 0; l < nvariables; l++) { Attribute at = Attributes.getAttribute(l); direccion = at.getDirectionAttribute(); tipo = at.getType(); if (direccion == Attribute.INPUT) { if (tipo != Attribute.NOMINAL && !i.getInputMissingValues(in)) { if(gravCenters[c][l].compareTo("a") == 0) gravCenters[c][l] = new String("0"); tmp = new Double(gravCenters[c][l]).doubleValue(); tmp += membershipOf[m][a] * i.getInputRealValues(in); gravCenters[c][l] = String.valueOf(tmp); } else { if (tipo == Attribute.NOMINAL && !i.getInputMissingValues(in)) modes[c][l].AddElement(i .getInputNominalValues(in)); } in++; } else { if (direccion == Attribute.OUTPUT) { if (tipo != Attribute.NOMINAL && !i.getOutputMissingValues(out)) { if(gravCenters[c][l].compareTo("a") == 0) gravCenters[c][l] = new String("0"); tmp = new Double(gravCenters[c][l]) .doubleValue(); tmp += membershipOf[m][a] * i.getOutputRealValues(out); gravCenters[c][l] = String.valueOf(tmp); } else { if (tipo == Attribute.NOMINAL && !i.getOutputMissingValues(out)) { modes[c][l].AddElement(i .getOutputNominalValues(out)); } out++; } } } } } for (int l = 0; l < nvariables; l++) { Attribute at = Attributes.getAttribute(l); direccion = at.getDirectionAttribute(); tipo = at.getType(); if (tipo == Attribute.NOMINAL) { if (modes[c][l].numElems() > 0) { gravCenters[c][l] = (modes[c][l].mostCommon()) .getValue(); } else {//what do we do if no valid value is available among the instances of this cluster for this attribute? //gravCenters[c][l] = new String("<null>"); //instead of the previous solution, lets leave the old attribute in the centroid as is gravCenters[c][l] = oldGC[c][l]; } } if (tipo != Attribute.NOMINAL) { if(gravCenters[a][l].compareTo("a") != 0){ tmp = new Double(gravCenters[a][l]).doubleValue(); tmp = tmp / Utotal; gravCenters[a][l] = String.valueOf(tmp); } else{//what do we do if no valid value is available among the instances of this cluster for this attribute? //gravCenters[a][b] = new String("<null>"); //instead of the previous solution, lets leave the old attribute in the centroid as is gravCenters[a][l] = oldGC[a][l]; } } } } } /** * <p> * Computes the memebership degree of a given instance to all the clusters * </p> * @param i The instance to update the memberships * @param orderOf_i The index of the instance */ public void setMembershipOf(Instance i, int orderOf_i) { double sum = 0.0; double res = 0.0; for (int k = 0; k < numCenters; k++) { res = this.distance(i, k); if (res == 0.0) { res = Float.MIN_VALUE; } membershipOf[orderOf_i][k] = Math.pow(res, -2.0 / (m - 1.0)); sum += membershipOf[orderOf_i][k]; } // System.out.print(orderOf_i + " "); for (int k = 0; k < numCenters; k++) { membershipOf[orderOf_i][k] = membershipOf[orderOf_i][k] / sum; // System.out.print(membershipOf[orderOf_i][k] + " "); } //System.out.println(); } /** * <p> * Returns the membership degree of the instance for a given cluster * </p> * @param orderOf_i the index of the instance * @param k the index of the considered cluster * @return the membership degree of instance i to cluster k */ public double getMembershipOf(int orderOf_i, int k) { return membershipOf[orderOf_i][k]; } /** * <p> * Computes the nearest cluster to the given instance * (for nominal values only) * </p> * @param inst The instance we are interested to compare * @return The index of the nearest cluster */ public int nearestCenter(Instance inst) { int nearest = 0; double minDist = this.distance(inst, 0); double distAct; int in = 0; int out = 0; int tipo = 0; int direccion = 0; for (int k = 1; k < numCenters; k++) { distAct = this.distance(inst, k); if (distAct < minDist) { minDist = distAct; nearest = k; } } return nearest; } /** * <p> * Returns the cluster to which the given instance belongs to * </p> * @param orderOf_i The index of the instance * @return The index of the cluster to this isntance belongs to. */ public int getClusterOf(Instance i) { return this.nearestCenter(i); } /** * <p> * Get the value of an attribute of the indicated centroid * </p> * @param cluster The index of the cluster (centroid) * @param position The attribute (dimension) to be obtained * @return the current value of the dimension of the given cluster */ public String valueAt(int cluster, int position) { return gravCenters[cluster][position]; } }