/***********************************************************************
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 Rosa Venzala (University of Granada) 02/06/2008
* @author Modified by Xavi Sol� (La Salle, Ram�n Llull University - Barcelona) 16/12/2008
* @version 1.1
* @since JDK1.2
* </p>
*/
package keel.Algorithms.Hyperrectangles.EACH;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import keel.Dataset.*;
import java.util.*;
import java.lang.*;
import java.text.DecimalFormat;
import org.core.*;
public class EACH {
/**
* <p>
* Main methods of thw EACHsd algorithm
* </p>
*/
private Dataset train ;
private Dataset test;
private String outFile;
private String outTrainFile;
private String outTestFile;
private String []classes=null;
private String []testClasses=null;
private String []nameAttributes=null;
private RuleSet rulesSet;
private Selector s;
private Complex rule;
private EachDataSet dataTrain,testData;
// To evaluate the rules
private RuleQualityEvaluation evalRule;
private int sampleForClassEvaluation[];
private int sampleForTestClass[];
private long seed;
// nominal(0) or numeric(1)
private int []types;
private InstanceSet IS;
private int size;
private Hyperrectangle H[];
private int numH;
private int match1,match2;
private HyperrectangleSet Hset;
private int choseen[];
private double before[][]=null;
private double dataWithoutNor[][]=null;
private Hyperrectangle hyp;
public EACH(){
}
/**
* <p>
* Constructor
* </p>
* @param fTrain Train file
* @param fTest Test file
* @param fOutTrain Out-put file Train
* @param fOutTest Out-put file Test
* @param fOut Out-put file
* @param seed Seed
* @param delta Delta
* @param secondChance Second chance
*/
public EACH(String fTrain,String fTest,
String fOutTrain,
String fOutTest, String fOut,long seed,double delta, int secondChance){
outFile = fOut;outTrainFile = fOutTrain;
outTestFile = fOutTest;
dataTrain = new EachDataSet();
testData = new EachDataSet();
train=new Dataset();
test=new Dataset();
//s=new Selector(0,0,0.);
this.seed=seed;
size=1;
try {
train.readSet(fTrain, true);
test.readSet(fTest,false);
train.computeMostComon();//eval.calculaMasComunes();
test.computeMostComon();
dataTrain = createSet(train);
testData = createSet(test);
rulesSet=new RuleSet();
types=new int [train.getNInPuts()];
types=train.typesVariable();
classes=train.giveClasses();
testClasses=test.giveClasses();
nameAttributes=train.getNames();
double[][]lista;//almacenamos para cada atributo la lista ordenada de valores
lista=train.getListValues();
H=new Hyperrectangle[train.getNData()/*size*/];
/*elegidos=new int[size];//esto antes de inicializar la memoria
inicializaMemoria(size);*/
numH=size;//inicialmente numH es 1
int []desordenadas=ramdomDataGeneration();//desordenamos las instancias en el train set
dataWithoutNor=new double[train.getNData()][];
for(int i=0;i<train.getNData();i++)dataWithoutNor[i]=new double[train.getNInPuts()];
before=train.getX();
for(int i=0;i<train.getNData();i++){
for(int j=0;j<train.getNInPuts();j++)dataWithoutNor[i][j]=before[i][j];
}
train.normalize();//Convierte todos los valores del conjunto de datos en el intervalo [0,1] a la hora de facilitar los calculos de las distancias
IS=train.getInstanceSet();
//la memoria inicial solo contiene un H point
H[0]=new Hyperrectangle(train.getNInPuts(),train.getX(desordenadas[0]),train.getC(desordenadas[0]),desordenadas[0]);
IS.getInstance(desordenadas[0]).print();System.out.println();
for(int i=1;i<train.getNData();i++)H[i]=new Hyperrectangle();
int matches[]=new int[2];
int claseH1,claseH2,claseE;
double pesos[]=new double[train.getNInPuts()];
for(int i=0;i<train.getNInPuts();i++)pesos[i]=1.;
Hset=new HyperrectangleSet(H,train.getNInPuts(),train.getNData(),size,delta);
//Hset.setMaxMinValuesAtrib(train.getemaximo(),train.geteminimo());
Hset.setWeightAtrib(pesos);
for(int i=0;i<train.getNInPuts();i++)
System.out.println(train.getMinimum()[i]+" "+train.getMaximum()[i]);
//main loop
/*empezamos en 1 pq la primera instancia ya se ha clasificado*/
for(int i=1;i<train.getNData();i++){
//MATCHING PROCESS
//find the two closest matches to the new example
//obtenemos los indices de los 2 H mas cercano al ejemplo actual i
matches=Hset.distance(train.getX(desordenadas[i]));
match1=matches[0];match2=matches[1];
claseH1=H[matches[0]].getClassAttribute();
claseH2=H[matches[1]].getClassAttribute();
claseE=train.getC(desordenadas[i]);
//H[matches[0]].print();System.out.print(",");H[matches[1]].print();
//System.out.println("CLASES "+claseE+" "+claseH1+" "+claseH2);
//si se produce un matching con H1
if(claseE==claseH1){
System.out.println("MATCH CON prime "+match1+" que es : "/*+H[matches[0]].getNumInstance()*/);
hyp=Hset.getHyperrectangle(match1);
hyp.print();
IS.getInstance(desordenadas[i]).print();System.out.println();
//adjust weight for success
//generalize exemplar
H[match1].adjustWeightSuccess();
H[match1].generalizeExemplar(train.getX(desordenadas[i]),desordenadas[i]);
}
else{
//adjust weight for failure
H[match1].adjustWeightFailure();
if(secondChance==1){
if(claseE==claseH2){
System.out.println("MATCH CON l sgunda "+match2/*+H[match2].getNumInstance()*/);
hyp=Hset.getHyperrectangle(match2);
hyp.print();
IS.getInstance(desordenadas[i]).print();System.out.println();
//adjust weight for success and generalize exemplar
H[match2].adjustWeightSuccess();
H[match2].generalizeExemplar(train.getX(desordenadas[i]),desordenadas[i]);
}
else{
//adjust weight for failure
H[match2].adjustWeightFailure();
//store the example as a new exemplar
H[numH]=new Hyperrectangle(train.getNInPuts(),train.getX(desordenadas[i]),train.getC(desordenadas[i]),desordenadas[i]);
Hset.store_in_memory(H[numH]);
numH++;
System.out.println("no match, crear un nuevo H, soy "+desordenadas[i]);
IS.getInstance(desordenadas[i]).print();System.out.println();
Hset.adjustFeatureWeights(train.getX(desordenadas[i]),match1);
}
}//del if greedy false
else{//VARIANTE GREEDY
//SI ERROR(CLASEe!=CLASEH1)DIRECTAMENTE CREAR UN NUEVO H
H[numH]=new Hyperrectangle(train.getNInPuts(),train.getX(desordenadas[i]),train.getC(desordenadas[i]),desordenadas[i]);
Hset.store_in_memory(H[numH]);
numH++;
System.out.println("no match, crear un nuevo H, soy "+desordenadas[i]);
IS.getInstance(desordenadas[i]).print();System.out.println();
Hset.adjustFeatureWeights(train.getX(desordenadas[i]),match1);
}
}
//}//del if
}
//creamos una regla por cada H
for(int i=0;i<numH;i++){
//AHORA PODEMOS CALCULAR EL VOLUMEN DE CADA H
H[i].calculeVolume();
rule=createRule(i);
complexEvaluation(rule,dataTrain);
rulesSet.addRule(rule);
}
rulesSet.adjuntClassNames(classes);
rulesSet.adjuntClassName(nameAttributes[train.getNInPuts()]);
//conjunto_reglas.print(1);
//EVALUAMOS LA CALIDAD DE LAS REGLAS
int [] clasesEval;
clasesEval = train.getC();
sampleForClassEvaluation = new int[train.getNClasses()];
for (int j = 0; j < train.getNClasses(); j++) {
sampleForClassEvaluation[j] = 0;
for (int i = 0; i < dataTrain.size(); i++) {
if (/*valorClases[j]*/j == clasesEval[i]) {
sampleForClassEvaluation[j]++;
}
}}
clasesEval = test.getC();
sampleForTestClass = new int[test.getNClasses()];
for (int j = 0; j < test.getNClasses(); j++) {
sampleForTestClass[j] = 0;
for (int i = 0; i < testData.size(); i++) {
if (/*valorClases[j]*/j == clasesEval[i]) {
sampleForTestClass[j]++;
}
}}
evalRule = new RuleQualityEvaluation(rulesSet, dataTrain, testData,
sampleForClassEvaluation, sampleForTestClass,classes,testClasses);
//GENERAMOS LA SALIDA
generaSalida();
}
catch (IOException e) {
System.err.println("There was a problem while trying to read the dataset files:");
System.err.println("-> " + e);
}
}
/**
* <p>
* Desordenar aleatoriamente un vector de numeros
* </p>
* @return v, el vector desordenado
*/
private int[] ramdomDataGeneration(){
int aux,indice;
int []v=new int [train.getNData()];
Randomize.setSeed(seed);
for(int i=0;i<train.getNData();i++)v[i]=i;
for(int i=0;i<train.getNData()-1;i++){
indice=Randomize.Randint(i+1,train.getNData());//desde i+1 a ndatos-1
//intercambiamos los valores de estas posiciones
aux=v[i];v[i]=v[indice];v[indice]=aux;
}
return v;
}
/*Devuelve true si el elemento buscado ya esta en el vector
*Vamos a usar esta fucion para detectar si una instancia ya se ha incluido en la
*memoria inicial, para no volverla a incluir
*/
private boolean yetChossen(int []vector, int util,int buscado){
boolean encontrado=false;
for(int i=0;i<util;i++){
if(vector[i]==buscado)encontrado=true;
}
return encontrado;
}
/*Crea una regla para un hyperrectangulo
*El consecuente de la regla es la clase de H
*return la regla creada
*/
private Complex createRule(int id){
Complex Regla;
int []v=new int[2];
double []v2=new double[2];
String []nomi=new String[2];
Regla=new Complex(train.getNClasses());
Regla.setClassAttribute(H[id].getClassAttribute());
Regla.addNameAttributes(nameAttributes);
Regla.setWeight(H[id].getWeight());
Regla.setVolume(H[id].getVolume());
Regla.setDimensions(H[id].getDimensions());
Selector s;
for(int i=0;i<train.getNInPuts();i++){
v=H[id].getLowerAndUpperValues(i);
v2[0]=dataWithoutNor[v[0]][i];
v2[1]=dataWithoutNor[v[1]][i];
nomi[0]=train.findNominalValue(i,before[v[0]][i]);
nomi[1]=train.findNominalValue(i,before[v[1]][i]);
if (Attributes.getInputAttribute(i).getType() == Attribute.NOMINAL){
//SI ES UN HOLE CREAR EL SELECTOR SOLO CON UN VALOR, NO CON DOS
//if(H[id].getNumEjemplos()==1){
//no es el numero de puntos sino el numero de valores
//distintos en cada selector, o 1 o 2
if(v[0]==v[1]){
s=new Selector(i,0,nomi,v2,1);}
else {s =new Selector(i,0,nomi,v2,2);}
}
else{
if(v[0]==v[1]){
s=new Selector(i,0,v2,1);}
else {s =new Selector(i,0,v2,2);}
}
Regla.addSelector(s);
}
//ahora nuestras reglas las hemos definido de forma diferente
//el conjunto de valores de un selector ahora solo son 2 valores, el minimo
//y el maximo.
return Regla;
}
/**
*
* <p>
* Evaluacion de los complejos sobre el conjunto de ejemplo para ver cuales se
* cubren de cada clase
* </p>
* @param c Complejo a evaluar
* @param e Conjunto de datos
*/
private void complexEvaluation(Complex c, EachDataSet e) {
c.removeDistribution();
for (int i = 0; i < e.size(); i++) {
int cl = e.getData(i).getClassSelector();
if (c.isCovered(e.getData(i))) {
c.incrementDistribution(cl);
}
}
c.computeLaplace();
}
/**
* Calcula los datos estad�ticos necesarios y crea los ficheros KEEL de salida
*/
private void generaSalida() {
Fichero f = new Fichero();
String cad = "";
String miSalida = new String("");
miSalida = train.copyHeaderTest();
int []num_valores=new int [train.getNInPuts()];
//getNumValues2 solo se puede llamar despues de getListValues();
num_valores=train.getNumValues2();
rulesSet.adjuntClassNames(classes);
rulesSet.adjuntClassName(nameAttributes[train.getNInPuts()]);
cad=rulesSet.printString(num_valores);
cad +=Hset.printWeightsAtributes(nameAttributes);
cad += "\n\n" + evalRule.printString();
f.escribeFichero(outFile, cad);
f.escribeFichero(outTrainFile,
miSalida + evalRule.out(dataTrain,true));
f.escribeFichero(outTestFile,
miSalida + evalRule.out(testData,false));
}
/**
* Crea un conjunto de datos (atributos/clase) segun los obtenidos de un fichero de datos
* @param mis_datos Debe ser un conjunto de datos leido del fichero (mirar doc Dataset.java)
* @return El conjunto de datos ya creado, es decir, una lista enlazada de muestras (consultar ConjDatos.java y Muestra.java)
*/
private EachDataSet createSet(Dataset mis_datos) {
EachDataSet datos = new EachDataSet(); //Creo un nuevo conjunto de datos
int tam = mis_datos.getNInPuts(); //Pillo el nmero de atributos de entrada (suponemos una sola salida [clase])
double[] vars = new double[tam]; //Creamos el vector que guardar�los valores de los atributos (aun siendo enteros o enum)
double[][] X;
int[] C;
int clase = 0; //Variable que contendr�el valor para la clase
X = mis_datos.getX();
C = mis_datos.getC();
for (int i = 0; i < mis_datos.getNData(); i++) {
//System.out.print("\n"+i+":");
for (int j = 0; (j < tam); j++) {
//System.out.print(" "+X[i][j]);
if (mis_datos.isMissing(i, j)) {
vars[j] = mis_datos.mostCommon(j);
} else { //CAMBIAR POR OTROS METODOS DE MANEJO DE VALORES PERDIDOS (15-NN).
vars[j] = X[i][j]; //Double.parseDouble(mis_datos.getDatosIndex(i, j)); //pillo el valor del atributo j para el ejemplo i
}
}
//if (!salir) {
clase = C[i]; //Integer.parseInt(mis_datos.getDatosIndex(i, tam));
Sample m = new Sample(vars, clase, tam); //Creo un nuevo dato del conjunto con sus variables, su clase y el num variables
m.setPosFile(i);
datos.addData(m);
//}
}
return datos;
}
}