/*********************************************************************** 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.LVQ; import keel.Algorithms.Instance_Generation.Basic.PrototypeSet; import keel.Algorithms.Instance_Generation.Basic.PrototypeGenerator; import keel.Algorithms.Instance_Generation.Basic.Prototype; import keel.Algorithms.Instance_Generation.Basic.PrototypeGenerationAlgorithm; import keel.Algorithms.Instance_Generation.*; import keel.Algorithms.Instance_Generation.BasicMethods.*; import keel.Algorithms.Instance_Generation.utilities.*; import keel.Algorithms.Instance_Generation.utilities.KNN.*; import keel.Dataset.*; import java.util.*; import org.core.*; /** * Implements LVQPRU algorithm * @author diegoj */ public class LVQPRU extends PrototypeGenerator { /** Minimum class part set. */ protected static int MINIMUM_CLASS_SET_SIZE = 2; // Minimum reduced set. //protected static int MINIMUM_SET_SIZE = 2; /** Percentage of prototypes for each class in initial reduction. */ protected double percentageOfPrototypesPerClass = 10.0; /** Percentage of prototypes. */ protected double percentageOfPrototypes = 10.0; /** Number of prototypes that will be generated. */ protected int numberOfPrototypes = 10; /** Number of iterations of the LVQPRU algorithm. */ protected int numberOfIterations = 1000; /** Window width of the LVQ2.1 algorithm. */ protected double windowWidth = 0.1; /** Number of iterations of the internal LVQ2.1 mapping. */ protected int numberOfIterationsLVQ2_1 = 10; /** Alpha constant of the internal LVQ2.1 mapping. */ protected double alpha_0 = 0.01; /** Size of the neighborhood used in KNN */ protected int k = 2; /** * Performs a LVQ1-reduction of the set. * @param set Set to be reduced. * @return Reduced set by the LVQ1 method. */ private PrototypeSet makeInitialReductionPerClass(PrototypeSet set) { if(set.size()<=2) { PrototypeSet result = new PrototypeSet(); result.add(set.avg()); return result; } int nP = getSetSizeFromPercentage(set, this.percentageOfPrototypesPerClass); nP = Math.max(nP, MINIMUM_CLASS_SET_SIZE); //Debug.errorln("Set size (en makeLVQ1Reduction) " + set.size()); //Debug.errorln("Num prots " + nP); //Debug.errorln("numIter " + numberOfIterations); //Debug.errorln("numProt " + numberOfPrototypes); //Debug.errorln("alpha " + alpha_0); //Debug.errorln("window width " + windowWidth); LVQ1 lvq1 = new LVQ1(set, numberOfIterations, nP, alpha_0); PrototypeSet reducedByLVQ1 = lvq1.reduceSet(); return reducedByLVQ1; } /** * Performs a LVQ2.1-reduction of the set. * @param set Set to be reduced. * @return Reduced set by the LVQ2.1 method. */ private PrototypeSet makeLVQ2_1Reduction(PrototypeSet set) { if(set.size()<2) { PrototypeSet result = new PrototypeSet(); result.add(set.avg()); return result; } //Debug.errorln("Set size (en makeLVQ2_1Reduction) " + set.size()); //Debug.errorln("numIter " + numberOfIterations); // Debug.errorln("numProt " + numberOfPrototypes); //Debug.errorln("alpha " + alpha_0); //Debug.errorln("window width " + windowWidth); int numP = Math.min(set.size(), numberOfPrototypes); //Debug.errorln("LVQ2.1 reduce con " + numP); LVQ2_1 lvq2_1 = new LVQ2_1(set, numberOfIterations, numP, alpha_0, windowWidth); PrototypeSet reducedByLVQ2_1 = lvq2_1.reduceSet(); return reducedByLVQ2_1; } /** * Constructs a new LVQPRU algorithm. * @param _trainingDataSet * @param parameters */ public LVQPRU(PrototypeSet _trainingDataSet, Parameters parameters) { super(_trainingDataSet, parameters); this.algorithmName="LVQPRU"; numberOfIterations = parameters.getNextAsInt(); percentageOfPrototypesPerClass = parameters.getNextAsDouble(); percentageOfPrototypes = parameters.getNextAsDouble(); numberOfPrototypes = this.getSetSizeFromPercentage(percentageOfPrototypes); numberOfIterationsLVQ2_1 = parameters.getNextAsInt(); alpha_0 = parameters.getNextAsDouble(); windowWidth = parameters.getNextAsDouble(); k = parameters.getNextAsInt(); } /** * Builds a LVQPRU algorithm. * @param numIter Number of iterations of the process. * @param pcNpc Percentage of number of prototypes per class. Used in initial reduction. * @param pcN Percentage of number of prototypes. * @param numIterLVQ2_1 Number iterations performed by the LVQ2.1 algorithm. * @param a Alpha parameter of the LVQ2.1 algorithm. * @param w Window width of the LVQ2.1 associated algorithm. * */ public LVQPRU(PrototypeSet _trainingDataSet, int numIter, double pcNpc, double pcN, int numIterLVQ2_1, double a, double w, int k) { super(_trainingDataSet); numberOfIterations = numIter; //int minNpc = minimumNumberOfPrototypesPerClass(); //numberOfInitialPrototypesPerClass = Npc; percentageOfPrototypesPerClass = pcNpc; percentageOfPrototypes = pcN; //if(Npc > minNpc) // numberOfInitialPrototypesPerClass = minNpc; numberOfIterationsLVQ2_1 = numIterLVQ2_1; alpha_0 = a; windowWidth = w; this.algorithmName="LVQPRU"; this.k = k; } /** * Returns the index of the minimum element of an array. * @param array ArrayList. * @return Index of the minimum value of array. */ protected static int indexOfMinElement(ArrayList<Double> array) { double min = array.get(0); int minIndex = 0; int i=0; for(double d : array) { if(d < min) { min = d; minIndex = i; } ++i; } return minIndex; } /*private void print(PrototypeSet R) { HashMap<Double,Integer> f = R.getFrequencyOfClasses(); ArrayList<Double> s = new ArrayList<Double>(f.keySet()); for(double c : s) Debug.errorln("De clase " + c + " hay " + f.get(c)); }*/ /** * Execute the method LVQPRU and returns the condensed set * @return Prototype set modified from the training data set by a LVQPRU method. */ @Override public PrototypeSet reduceSet() { PrototypeSet T = trainingDataSet.copy(); //Debug.errorln("Empezamos"); //ArrayList<Double> classes = T.nonVoidClasses(); ArrayList<PrototypeSet> parts = T.classPartition(); ArrayList<PrototypeSet> reducedParts = new ArrayList<PrototypeSet>(); for(PrototypeSet ps : parts) { PrototypeSet LVQ1reduced = makeInitialReductionPerClass(ps); reducedParts.add(LVQ1reduced); //Debug.errorln("Parte tiene " + ps.size() + " elementos"); //Debug.errorln("Reduced tiene " + LVQ1reduced.size() + " elementos"); //print(LVQ1reduced); } // Reduce the set, erasing noisy prototypes and relabeling wrong prots' PrototypeSet R = new PrototypeSet(reducedParts); //Debug.errorln("Tenemos al colega R con " + R.size() + " prototypos"); PrototypeSet newR = new PrototypeSet(); for(Prototype p : R) { PrototypeSet nn = KNN.getNearestNeighbors(p, trainingDataSet, k); PrototypeSet nnWithSameClass = nn.getFromClass(p.label()); if(nnWithSameClass.size() > 0) newR.add(p); else if(nn.size()>0) { double newClass = nn.mostFrequentClass(); p.setClass(newClass); newR.add(p); } } R = newR; // print(R); //Debug.errorln("Hemos llegao a la reducción del LVQ2.1"); R = makeLVQ2_1Reduction(R); //Debug.errorln("Hemos llegau a CNN"); //Condensing CNN.makeReductionOf(R); boolean end = false; int acc = LVQPRU.absoluteAccuracy(R, trainingDataSet); //Prototype chosen = null; ArrayList<Double> E = new ArrayList<Double>(R.size()); int R_size = R.size(); for (int i = 0; i < R_size; ++i) E.add(0.0); int index = 0; for (Prototype p : R) p.setIndex(index++); int iterations = 0; do { //Debug.errorln(index + " iteration"); for(Prototype p : R) { PrototypeSet nn = KNN.getNearestNeighbors(p, R, 2); double l = nn.get(0).label(); double m = nn.get(1).label(); double n = p.label(); int i = nn.get(0).getIndex(); if(n == l && n!=m) E.set(i, E.get(i)+1); if(n!=l && n==m) E.set(i,E.get(i)-1); ++i; } int iE = indexOfMinElement(E); Prototype erroneus = R.get(iE); //PrototypeSet R2 = new PrototypeSet(R); R.remove(iE); //R2 = makeLVQ2_1Reduction(R); int currAcc = LVQPRU.absoluteAccuracy(R, trainingDataSet); end = currAcc < acc; //Debug.errorln("Current Acc " + currAcc + " < " + acc + "? " + end); if(!end) { acc = currAcc; R = makeLVQ2_1Reduction(R); } else { R.add(erroneus); } ++iterations; } while(!end && (iterations > numberOfIterations)); //R.applyThresholds(); return R; } /** * General main for all the prototoype generators * Arguments: * 0: Filename with the training data set to be condensed. * 1: Filename wich will contain the test data set * 3: k Number of neighbors used in the KNN function * @param args Arguments of the main function. */ public static void main(String[] args) { Parameters.setUse("LVQPRU", "<seed> <number of iterations> <percentage of prots. by class> <percentage of prots> <number of iterations LVQ2_1> <WindowWidth> <alpha_0> <k (of KNN)>"); Parameters.assertBasicArgs(args); //Debug.setStdDebugMode(true); PrototypeSet training = PrototypeGenerationAlgorithm.readPrototypeSet(args[0]); PrototypeSet test = PrototypeGenerationAlgorithm.readPrototypeSet(args[1]); //int numIter, int Npc, int numIterLVQ2_1, double w, double a long seed = Parameters.assertExtendedArgAsInt(args,2,"seed",0,Long.MAX_VALUE); LVQPRU.setSeed(seed); int numIter = Parameters.assertExtendedArgAsInt(args,3,"iterations of optimal-LVQ3 reduction", 1, Integer.MAX_VALUE); double pcNpc = Parameters.assertExtendedArgAsDouble(args,4,"percentage of number of prototypes per class", 0, 100); double pcN = Parameters.assertExtendedArgAsDouble(args,5,"percentage of number of prototypes", 0, 100); int numIterLVQ2_1 = Parameters.assertExtendedArgAsInt(args,6,"iterations of LVQ2.1 reduction", 1, Integer.MAX_VALUE); double a = Parameters.assertExtendedArgAsDouble(args,7,"alpha0 parameter of the LVQ2.1 internal reduction", 0, 1); double w = Parameters.assertExtendedArgAsDouble(args,8,"window width parameter of the LVQ2.1 internal reduction", 0, 1); int k = Parameters.assertExtendedArgAsInt(args,9,"size of neighborhood of KNN", 1, 3); LVQPRU generator = new LVQPRU(training, numIter, pcNpc, pcN, numIterLVQ2_1, a, w, k); PrototypeSet resultingSet = generator.execute(); int accuracy1NN = KNN.classficationAccuracy(resultingSet, test); generator.showResultsOfAccuracy(Parameters.getFileName(), accuracy1NN, test); } }