/***********************************************************************
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/
**********************************************************************/
/*
* Created on 27-feb-2005
*/
package keel.Algorithms.Genetic_Rule_Learning.Hider;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
/**
* @author Sebas
*/
public class Discretizacion {
/**
* 'BaseDatos' object to discretize
*/
private BaseDatos bd = null;
/**
* 'Vector' object to store cuts from different attributes
*/
private Vector cortes = null;
/**
* @param cort
*/
public Discretizacion(Vector cort) {
cortes = cort;
}
/**
* @param b
*/
public Discretizacion(BaseDatos b) {
bd = b;
cortes = new Vector();
}
/**
* @param b
* @param cort
*/
public Discretizacion(BaseDatos b, Vector cort) {
bd = b;
cortes = cort;
}
/*
public Discretizacion(String fichero)
{
bd=new BaseDatos(fichero);
cortes=new Vector();
}
*/
/**
* @return Returns the bd.
*/
public BaseDatos getBd() {
return bd;
}
/**
* @param b The bd to set.
*/
public void setBd(BaseDatos b) {
bd = b;
}
/**
* Makes discretization in database
* @throws Exception
*/
public void discretiza() throws Exception {
//Look through every continuous attribute from database
for (int i = 0; i < bd.getNumAtributos(); i++) {
//If it's a continuous attribute...
if (((Vector) bd.getBase().get(0)).get(i).getClass().toString().
indexOf("Double") >= 0) {
//Sort 'Vector' by current 'i' attribute
Collections.sort(bd.getBase(),
new AtributoComparator(i, bd.getClase()));
//Initialize cuts
inicializaCortesAtributo(i);
HashMap uniones = new HashMap();
Union union = null;
for (int j = 0; j < ((Vector) cortes.get(i)).size() - 2; j++) {
Corte corteJ = (Corte) ((Vector) cortes.get(i)).get(j);
Corte corteJ1 = (Corte) ((Vector) cortes.get(i)).get(j + 1);
Corte corteJ2 = (Corte) ((Vector) cortes.get(i)).get(j + 2);
//Store as 'Union' the cut to delete and the goodness of that deletion
if (condicion(corteJ, corteJ1, corteJ2, i)) {
//'corteJ1' is the cut that divides two intervals, so it will be the one to delete
//Here stores the cut to delete and the goodness of that deletion
double bond = bondad(i, corteJ.getCorte(),
corteJ2.getCorte());
Double etiqueta = new Double(corteJ1.getCorte());
//Now, gets the majority output value
int clase = claseMayoritaria(i, corteJ.getCorte(),
corteJ2.getCorte());
union = new Union(corteJ1, bond, clase);
uniones.put(etiqueta, union);
}
}
while (uniones.size() > 0) {
//First, join intervals that their union will be maximum goodness
//and get a new intervals set
//that means we delete the appropriate cut from cut's 'Vector'
//Search the unions' 'Map' to find the one with maximum goodness
int cMaxBond = -1;
double bondadMaxima = 0.0;
Object[] arrayUniones = uniones.values().toArray();
for (int u = 0; u < arrayUniones.length; u++) {
if (((Union) arrayUniones[u]).getBondad() >
bondadMaxima) {
bondadMaxima = ((Union) arrayUniones[u]).getBondad();
cMaxBond = u;
}
}
//Store cuts that define contiguous intervals
int corteEliminado = ((Vector) cortes.get(i)).indexOf(((
Union) arrayUniones[cMaxBond]).getCorte()); //Index of deleted cut
//These are sorted bottom-up as in cuts' 'Vector'...
int iniIant = corteEliminado - 2; //Initial cut of the interval before the new one
int finIant = corteEliminado - 1; //Final cut of the interval before the new one (initial cut of the new interval)
//Only add '1' because the deletion of the cut.
int iniIpost = corteEliminado; //Initial cut of the interval after the new one (final cut of the new interval)
int finIpost = corteEliminado + 1; //Final cut of the interval after the new one
Corte cIni = (Corte) ((Vector) cortes.get(i)).get(
corteEliminado - 1);
Corte cMed = (Corte) ((Vector) cortes.get(i)).get(
corteEliminado);
Corte cFin = (Corte) ((Vector) cortes.get(i)).get(
corteEliminado + 1);
//If still matches the union condition...
if (condicion(cIni, cMed, cFin, i)) {
//Delete this cut to join the intervals
((Vector) cortes.get(i)).remove(((Union) arrayUniones[
cMaxBond]).getCorte());
//Before deletion, actualize goodness and majority output value of new interval
//(interval's goodness is the goodness of its upper cut)
//(interval's output value is the output value of its lower cut)
if (corteEliminado >= 0) {
((Corte) ((Vector) cortes.get(i)).get(
corteEliminado)).setBondad(bondadMaxima);
((Corte) ((Vector) cortes.get(i)).get(
corteEliminado -
1)).setClase(((Union) arrayUniones[cMaxBond]).
getClase());
}
//Delete from 'Map' the 'Union' yet done
uniones.remove(new Double(((Union) arrayUniones[
cMaxBond]).getCorte().getCorte()));
//Check if contiguous intervals of the new one (created by the union done)
//can join with this new one.....
cIni = null;
cMed = null;
cFin = null;
//Next interval...
//If exist next and previous intervals...
if (iniIant >= 0 && finIant > iniIant && iniIpost >= 0 &&
iniIpost < (((Vector) cortes.get(i)).size() - 1) &&
finIpost < ((Vector) cortes.get(i)).size()) {
cIni = (Corte) ((Vector) cortes.get(i)).get(finIant);
cMed = (Corte) ((Vector) cortes.get(i)).get(
iniIpost);
cFin = (Corte) ((Vector) cortes.get(i)).get(
finIpost);
}
//If doesn't exist the next interval, do nothing
/*
else if(iniIpost > ((Vector)cortes.get(i)).size() || finIpost >= ((Vector)cortes.get(i)).size())
{
}
*/
//If exists the next interval but doesn't exists the previous one
else if (finIant <= 0 && finIant > iniIant &&
iniIpost >= 0 &&
iniIpost <
(((Vector) cortes.get(i)).size() - 1) &&
finIpost < ((Vector) cortes.get(i)).size()) {
cIni = (Corte) ((Vector) cortes.get(i)).get(0);
cMed = (Corte) ((Vector) cortes.get(i)).get(
iniIpost);
cFin = (Corte) ((Vector) cortes.get(i)).get(
finIpost);
}
//It could be an error
else if (!(iniIpost > ((Vector) cortes.get(i)).size() ||
finIpost >= ((Vector) cortes.get(i)).size())) {
Exception e = new Exception(
"Neither next nor previous intervals exist");
throw e;
}
//If there are any possible union, add it to the 'Union' objects 'Vector'
if (cIni != null && cMed != null && cFin != null &&
condicion(cIni, cMed, cFin, i)) {
//cMed (finIant) is the cut that divide both intervals, so it will be the one to delete
//Here store the cut to delete and the goodness of the union
double bond = bondad(i, cIni.getCorte(),
cFin.getCorte());
int clase = claseMayoritaria(i, cIni.getCorte(),
cFin.getCorte());
union = new Union(cMed, bond, clase);
uniones.put(new Double(cMed.getCorte()), union);
}
//Previous interval...
//If exist next and previous intervals...
if (iniIant >= 0 && finIant > 0 && finIant > iniIant &&
iniIpost < ((Vector) cortes.get(i)).size()) {
cIni = (Corte) ((Vector) cortes.get(i)).get(iniIant);
cMed = (Corte) ((Vector) cortes.get(i)).get(finIant);
cFin = (Corte) ((Vector) cortes.get(i)).get(
iniIpost);
}
//If exists the previous interval but doesn't exists the next one
else if (iniIant >= 0 && finIant > 0 &&
finIant > iniIant &&
iniIpost >= ((Vector) cortes.get(i)).size()) {
cIni = (Corte) ((Vector) cortes.get(i)).get(iniIant);
cMed = (Corte) ((Vector) cortes.get(i)).get(finIant);
cFin = (Corte) ((Vector) cortes.get(i)).get(((
Vector) cortes.get(i)).size() - 1);
}
//If doesn't exist the previous interval, do nothing
/*
else if(iniIant < 0 || finIant <= 0)
{
}
*/
//It could be an error
else if (!(iniIant < 0 || finIant <= 0)) {
Exception e = new Exception(
"Neither next nor previous intervals exist");
throw e;
}
//If there are any possible union, add it to the 'Union' objects 'Vector'
if (cIni != null && cMed != null && cFin != null &&
condicion(cIni, cMed, cFin, i)) {
//cMed (finIant) is the cut that divide both intervals, so it will be the one to delete
//Here store the cut to delete and the goodness of the union
double bond = bondad(i, cIni.getCorte(),
cFin.getCorte());
int clase = claseMayoritaria(i, cIni.getCorte(),
cFin.getCorte());
union = new Union(cMed, bond, clase);
uniones.put(new Double(cMed.getCorte()), union);
}
} else { //if(condicion(...)
//If the cut doesn't match the condition in 'condicion(...)', delete it only from the 'Map'
//don't delete it from cuts' 'Vector'
uniones.remove(new Double(((Union) arrayUniones[
cMaxBond]).getCorte().getCorte()));
}
}
} else { //If it's a discrete attribute
//System.err.println("Aki ->"+bd.getRangos(i));
cortes.add(bd.getRangos(i));
}
}
}
/**
*
* @param cortes2
* @param campo
* @throws Exception
*/
public void imprimeCortes(Vector cortes2, int campo) throws Exception {
for (int i = 0; i < cortes2.size(); i++) {
Corte c1 = (Corte) ((Vector) cortes2.get(campo)).get(i);
Corte c2 = (Corte) ((Vector) cortes2.get(campo)).get(i + 1);
Corte c3 = (Corte) ((Vector) cortes2.get(campo)).get(i + 2);
if (condicion(c1, c2, c3, campo)) {
System.out.println("Corte: " + c2.getCorte() + " Bondad: " +
bondad(campo, c1.getCorte(), c3.getCorte()));
} else {
System.out.println("Corte: " + c2.getCorte() + " Bondad: 0");
}
}
System.out.println("--------------------------------------------------------------------------------------");
}
/*
public Vector inicializaCortes()
{
cortes=new Vector();
Vector cortesAtributo=null;
//Vector base=bd.getBase();
//Recorro todos los atributos continuos de la base de datos
for(int i=0;i < bd.getNumAtributos();i++)
{
cortesAtributo=new Vector();
//Si el atributo es continuo...
//if(((Vector)base.get(0)).get(i).getClass().toString().equals("Double"))
if(((Vector)bd.getBase().get(0)).get(i).getClass().toString().indexOf("Double") >= 0)
{
//Ordenamos el vector por el atributo i
Collections.sort(bd.getBase(),new AtributoComparator(i,BaseDatos.getClase()));
//A�adimos el primer elemento a los intervalos
Corte cInicial=new Corte((Integer)((Vector)bd.getBase().get(0)).get(BaseDatos.getClase()),(Double)((Vector)bd.getBase().get(0)).get(i));
cortesAtributo.add(cInicial);
Double corte=null;
//Cogemos el primer valor del atributo como valor inicial del intervalo inicial
double iniIntervaloActual=((Double)((Vector)bd.getBase().get(0)).get(i)).doubleValue();
//Recorremos los ejemplos...
for(int j=0;j < bd.getNumEjemplos()-1;j++)
{
//Cogemos el valor del atributo 'i' en el ejemplo 'j'
double vj=((Double)((Vector)bd.getBase().get(j)).get(i)).doubleValue();
//Cogemos el valor del atributo 'i' en el siguiente ejemplo (el 'j+1')
double vj1=((Double)((Vector)bd.getBase().get(j+1)).get(i)).doubleValue();
//Cogemos el valor de la clase mayoritaria en el ejemplo 'j'
int clasej=claseMayoritaria(i,((Double)((Vector)bd.getBase().get(j)).get(i)).doubleValue());
//Cogemos el valor de la clase mayoritaria en el siguiente ejemplo (el 'j+1')
int clasej1=claseMayoritaria(i,((Double)((Vector)bd.getBase().get(j+1)).get(i)).doubleValue());
//Si alguna clase mayoritaria vale MIN_VALUE significa que ha habido empate en ese intervalo
if((vj != vj1 || clasej == Integer.MIN_VALUE || clasej1 == Integer.MIN_VALUE) && (clasej != clasej1 || puro(bd,vj,i) != puro(bd,vj1,i)))
{
double aux=suma(vj,vj1);
aux/=2.0;
corte=new Double(aux);
double finIntervaloActual=corte.doubleValue();
//Calculamos la bondad del intervalo
double bondadIntervalo=bondad(i,iniIntervaloActual,finIntervaloActual);
//El corte final del intervalo (finIntervaloActual) es el que lleva la bondad
Corte c=new Corte(clasej1,corte,bondadIntervalo);
cortesAtributo.add(c);
//El corte es tambi�n el valor inicial del siguiente intervalo
iniIntervaloActual=corte.doubleValue();
}
}
//A�adimos el �ltimo elemento a los intervalos
Double corteFin=(Double)((Vector)bd.getBase().get(bd.getNumEjemplos()-1)).get(i);
double bondadIntervalo=bondad(i,iniIntervaloActual,corteFin.doubleValue());
Corte cFinal=new Corte((Integer)((Vector)bd.getBase().get(bd.getNumEjemplos()-1)).get(BaseDatos.getClase()),corteFin,bondadIntervalo);
cortesAtributo.add(cFinal);
//A�adimos el vector de cortes del atributo al vector general de cortes
//El tama�o del vector general ser� el n�mero de atributos
cortes.add(cortesAtributo);
}
}
return(cortes);
}
*/
/**
* Inicializa los cortes para la discretizaci�n
* @param i
* @throws Exception
*/
public void inicializaCortesAtributo(int i) throws Exception {
//Look through every continuous attribute in database
Vector cortesAtributo = new Vector();
//Add first element to intervals
Corte cInicial = new Corte((Integer) ((Vector) bd.getBase().get(0)).get(
bd.getClase()), (Double) ((Vector) bd.getBase().get(0)).get(i));
cortesAtributo.add(cInicial);
Double corte = null;
//Take first value of attribute range as initial value of initial interval
double iniIntervaloActual = ((Double) ((Vector) bd.getBase().get(0)).
get(i)).doubleValue();
//Look through the elements...
for (int j = 0; j < bd.getNumEjemplos() - 1; j++) {
//Take the value of 'i' attribute in 'j' element
double vj = ((Double) ((Vector) bd.getBase().get(j)).get(i)).
doubleValue();
//Take the value of 'i' attribute in next element ('j+1')
double vj1 = ((Double) ((Vector) bd.getBase().get(j + 1)).get(i)).
doubleValue();
//Take the value of majority output attribute in 'j' element
int clasej = claseMayoritaria(i,
((Double) ((Vector) bd.getBase().
get(j)).get(i)).doubleValue());
//Take the value of majority output attribute in next element ('j+1')
int clasej1 = claseMayoritaria(i,
((Double) ((Vector) bd.getBase().
get(j + 1)).get(i)).doubleValue());
//If any majority output attribute has the value MIN_VALUE, that means that there is a tie in the interval
if ((vj != vj1 || clasej == Integer.MIN_VALUE ||
clasej1 == Integer.MIN_VALUE) &&
(clasej != clasej1 || puro(vj, i) != puro(vj1, i))) {
double aux = suma(vj, vj1);
aux /= 2.0;
corte = new Double(aux);
double finIntervaloActual = corte.doubleValue();
//Calculate interval goodness
double bondadIntervalo = bondad(i, iniIntervaloActual,
finIntervaloActual);
//The final cut of interval (finIntervaloActual) is the one that contains the goodness
Corte c = new Corte(clasej1, corte, bondadIntervalo);
cortesAtributo.add(c);
//This cut is also the the initial value of next interval
iniIntervaloActual = corte.doubleValue();
}
}
//Add last element to intervals
Double corteFin = (Double) ((Vector) bd.getBase().get(bd.getNumEjemplos() -
1)).get(i);
double bondadIntervalo = bondad(i, iniIntervaloActual,
corteFin.doubleValue());
Corte cFinal = new Corte((Integer) ((Vector) bd.getBase().get(bd.
getNumEjemplos() - 1)).get(bd.getClase()), corteFin,
bondadIntervalo);
cortesAtributo.add(cFinal);
//Add cuts' 'Vector' of this attribute to general cuts' 'Vector'
//The number of attributes will be general 'Vector' size
cortes.add(cortesAtributo);
}
/**
*
* @param v
* @param campo
* @return p
* @throws Exception
*/
private boolean puro(double v, int campo) throws Exception {
boolean p = true;
//The vector is sorted by field 'campo' values
//so it allow us to apply binary search
int ini = 0, fin = bd.getNumEjemplos() - 1, med = -1;
boolean enc = false;
double actual;
while (fin >= ini && !enc) {
med = (ini + fin) / 2;
actual = ((Double) ((Vector) bd.getBase().get(med)).get(campo)).
doubleValue();
if (v == actual) {
//When found, return the first position it has been found
while (v == actual && med > 0) {
actual = ((Double) ((Vector) bd.getBase().get(--med)).get(
campo)).doubleValue();
}
if (v != actual) {
med++;
}
enc = true;
} else {
if (v < actual) {
fin = med - 1;
} else {
ini = med + 1;
}
}
}
if (med > -1 && enc && med < bd.getNumEjemplos()) {
//Check purity of 'v' beginning in 'med' position
//that is the position it has been found
int i = med + 1;
actual = ((Double) ((Vector) bd.getBase().get(med)).get(campo)).
doubleValue();
int clase = ((Integer) ((Vector) bd.getBase().get(med)).get(bd.
getClase())).intValue();
while (actual == v && p && i < bd.getNumEjemplos()) {
actual = ((Double) ((Vector) bd.getBase().get(i)).get(campo)).
doubleValue();
int claseActual = ((Integer) ((Vector) bd.getBase().get(i)).get(
bd.getClase())).intValue();
if (actual == v && clase != claseActual) {
p = false;
}
i++;
}
} else {
Exception e = new Exception(
"Something wrong happens with vector size. ini: " + ini +
", fin: " + fin);
throw e;
}
return p;
}
/**
* Calculate the goodness
* @param campo
* @param vIni
* @param vFin
* @return b
* @throws Exception
*/
private double bondad(int campo, double vIni, double vFin) throws Exception {
double b = 0;
//First, obtain output values in interval and its frequencies
//The vector is sorted by field 'campo' values
//so it allow us to apply binary search
int ini = 0, fin = bd.getNumEjemplos() - 1, med = -1;
boolean enc = false;
double actual;
//Use a 'Map' to contain frequencies of every value of output attribute
Map frecuencias = new HashMap();
while (fin >= ini && !enc) {
med = (ini + fin) / 2;
//System.out.println("Mira :: Ini = "+ini+"; Med = "+med+"; Fin = "+fin);
//Take attribute value
actual = ((Double) ((Vector) bd.getBase().get(med)).get(campo)).
doubleValue();
if (vIni <= actual && actual <= vFin) {
//When found, go to the first position of the value
while (vIni <= actual && med > 0) {
actual = ((Double) ((Vector) bd.getBase().get(--med)).get(
campo)).doubleValue();
}
if (vIni > actual) {
med++;
}
enc = true;
} else {
if (actual < vIni) {
ini = med + 1;
} else if (actual >= vFin) {
fin = med - 1;
}
}
}
int mayoritaria = -1;
int mayorClase = -1;
if (med > -1 && enc) {
actual = ((Double) ((Vector) bd.getBase().get(med)).get(campo)).
doubleValue();
int clase = ((Integer) ((Vector) bd.getBase().get(med)).get(bd.
getClase())).intValue();
int valorAnt = 0;
mayoritaria = clase;
mayorClase = clase;
while
(
vIni <= actual &&
(
(actual < vFin &&
vFin !=
((Double) ((Vector) bd.getBase().
get(bd.getNumEjemplos() - 1)).
get(campo)).doubleValue())
|| //If it's the last value of elements, then the interval is (<=)
(actual <= vFin &&
vFin ==
((Double) ((Vector) bd.getBase().
get(bd.getNumEjemplos() - 1)).
get(campo)).doubleValue())
)
&&
med < bd.getNumEjemplos()
) { //while
if (frecuencias.containsKey(new Integer(clase))) {
valorAnt = ((Integer) frecuencias.get(new Integer(clase))).
intValue();
} else {
valorAnt = 0;
}
frecuencias.put(new Integer(clase), new Integer(valorAnt + 1));
//Obtain the majority output value
int valorClase = ((Integer) frecuencias.get(new Integer(clase))).
intValue();
int valorMayor = ((Integer) frecuencias.get(new Integer(
mayoritaria))).intValue();
if (valorClase > valorMayor) {
mayoritaria = clase;
}
//Obtain the greatest output value in 'Map' that will be used as limit foor the loop
if (clase > mayorClase) {
mayorClase = clase;
}
med++;
if (med < bd.getNumEjemplos()) {
actual = ((Double) ((Vector) bd.getBase().get(med)).get(
campo)).doubleValue();
clase = ((Integer) ((Vector) bd.getBase().get(med)).get(bd.
getClase())).intValue();
}
}
//The frequencies of output values are in 'frecuencias' 'Map' and
//majority output value is in 'mayoritaria'
//Also the greatest output value in 'Map' is in 'mayorClase' to limit the loop
double suma = 1.0;
for (int f = 0; f <= mayorClase; f++) {
if (f != mayoritaria && frecuencias.containsKey(new Integer(f)) &&
((Integer) frecuencias.get(new Integer(f))).intValue() > 0) {
suma += ((Integer) frecuencias.get(new Integer(f))).
doubleValue();
}
}
//Calculate interval goodness
b = ((Integer) frecuencias.get(new Integer(mayoritaria))).
doubleValue() / suma;
} else {
Exception e = new Exception(
"Something wrong happens with vector size. ini: " + ini +
", fin: " + fin + ", med: " + med + ", enc: " + enc +
", mayoritaria: " + mayoritaria + ", vIni: " + vIni +
", vFin: " + vFin + ", Campo: "+ campo);
throw e;
}
return b;
}
/**
*
* @param campo
* @param vIni
* @return the majority class for the interval
* @throws Exception
*/
private int claseMayoritaria(int campo, double vIni) throws Exception {
//First, obtain output values in interval and its frequencies
//The vector is sorted by field 'campo' values
//so it allow us to apply binary search
int ini = 0, fin = bd.getNumEjemplos() - 1, med = -1;
boolean enc = false;
double actual;
//Use a 'Vector' to contain output values' frequencies
Map frecuencias = new HashMap();
while (fin >= ini && !enc) {
med = (ini + fin) / 2;
//Take attribute value
actual = ((Double) ((Vector) bd.getBase().get(med)).get(campo)).
doubleValue();
if (vIni == actual) { //Search for 'vIni' because is the first value in ['vIni','vFin')
//When found, go to the first position of the value
while (vIni == actual && med > 0) {
actual = ((Double) ((Vector) bd.getBase().get(--med)).get(
campo)).doubleValue();
}
if (vIni != actual) {
med++;
}
enc = true;
} else {
if (vIni < actual) {
fin = med - 1;
} else if (actual < vIni) {
ini = med + 1;
}
}
}
int mayoritaria = -1;
if (med > -1 && enc) {
//Begin at first position of value ('med')
int valorAnt = 0;
boolean repetida = false; //Used to know if there are more than one majority output value
actual = ((Double) ((Vector) bd.getBase().get(med)).get(campo)).
doubleValue();
int clase = ((Integer) ((Vector) bd.getBase().get(med)).get(bd.
getClase())).intValue();
mayoritaria = clase;
while (vIni == actual && med < bd.getNumEjemplos()) {
if (frecuencias.containsKey(new Integer(clase))) {
valorAnt = ((Integer) frecuencias.get(new Integer(clase))).
intValue();
} else {
valorAnt = 0;
}
frecuencias.put(new Integer(clase), new Integer(valorAnt + 1)); //Add one more to the frequency of this output value
//Obtain the majority output value
int valorClase = ((Integer) frecuencias.get(new Integer(clase))).
intValue();
int valorMayor = ((Integer) frecuencias.get(new Integer(
mayoritaria))).intValue();
if (valorClase > valorMayor) {
mayoritaria = clase;
}
med++;
if (med < bd.getNumEjemplos()) {
actual = ((Double) ((Vector) bd.getBase().get(med)).get(
campo)).doubleValue();
clase = ((Integer) ((Vector) bd.getBase().get(med)).get(bd.
getClase())).intValue();
}
}
//Look for others majority output values (same frequency)
Object[] arrayFrecs = frecuencias.values().toArray();
Object[] arrayClases = frecuencias.keySet().toArray();
int c = 0;
int frecMayoritaria = ((Integer) frecuencias.get(new Integer(
mayoritaria))).intValue();
while (c < arrayFrecs.length && !repetida) {
int frecActual = ((Integer) arrayFrecs[c]).intValue();
int claseActual = ((Integer) arrayClases[c]).intValue();
if (frecActual == frecMayoritaria && claseActual != mayoritaria) {
repetida = true;
}
c++;
}
//The frequencies of output values are in 'frecuencias' 'Map' and
//majority output value is in 'mayoritaria'. Variable 'repetida' is true if there is tie between several majority output values
if (repetida) {
//There is more than one majority output value, so return MIN_VALUE
mayoritaria = Integer.MIN_VALUE;
}
} else {
Exception e = new Exception(
"Something wrong happens with vector size. ini: " + ini +
", fin: " + fin + ", med: " + med + ", enc: " + enc +
", mayoritaria: " + mayoritaria + ", vIni: " + vIni);
throw e;
}
return mayoritaria;
}
/**
*
* @param campo
* @param vIni
* @param vFin
* @return the majority class for the interval
* @throws Exception
*/
private int claseMayoritaria(int campo, double vIni, double vFin) throws
Exception {
//First, obtain output values in interval and its frequencies
//The vector is sorted by field 'campo' values
//so it allow us to apply binary search
int ini = 0, fin = bd.getNumEjemplos() - 1, med = -1;
boolean enc = false;
double actual;
//Use a 'Vector' to contain output values' frequencies
Map frecuencias = new HashMap();
while (fin >= ini && !enc) {
med = (ini + fin) / 2;
//Take attribute value
actual = ((Double) ((Vector) bd.getBase().get(med)).get(campo)).
doubleValue();
if (vIni <= actual && actual < vFin) {
//When found, go to the first position of the value
while (vIni <= actual && med > 0) {
actual = ((Double) ((Vector) bd.getBase().get(--med)).get(
campo)).doubleValue();
}
if (vIni != actual) {
med++;
}
enc = true;
} else {
if (vFin <= actual) {
fin = med - 1;
} else if (actual < vIni) {
ini = med + 1;
}
}
}
int mayoritaria = -1;
if (med > -1 && enc) {
//Begin at first position of value ('med')
int valorAnt = 0;
boolean repetida = false; //Used to know if there are more than one majority output value
actual = ((Double) ((Vector) bd.getBase().get(med)).get(campo)).
doubleValue();
int clase = ((Integer) ((Vector) bd.getBase().get(med)).get(bd.
getClase())).intValue();
mayoritaria = clase;
while (vIni <= actual && actual < vFin && med < bd.getNumEjemplos()) {
if (frecuencias.containsKey(new Integer(clase))) {
valorAnt = ((Integer) frecuencias.get(new Integer(clase))).
intValue();
} else {
valorAnt = 0;
}
frecuencias.put(new Integer(clase), new Integer(valorAnt + 1)); //Add one more to the frequency of this output value
//Obtain majority output value
int valorClase = valorAnt + 1;
int valorMayor = ((Integer) frecuencias.get(new Integer(
mayoritaria))).intValue();
if (valorClase > valorMayor) {
mayoritaria = clase;
}
med++;
if (med < bd.getNumEjemplos()) {
actual = ((Double) ((Vector) bd.getBase().get(med)).get(
campo)).doubleValue();
clase = ((Integer) ((Vector) bd.getBase().get(med)).get(bd.
getClase())).intValue();
}
}
//Look for others majority output values (same frequency)
Object[] arrayFrecs = frecuencias.values().toArray();
Object[] arrayClases = frecuencias.keySet().toArray();
int c = 0;
int frecMayoritaria = ((Integer) frecuencias.get(new Integer(
mayoritaria))).intValue();
while (c < arrayFrecs.length && !repetida) {
int frecActual = ((Integer) arrayFrecs[c]).intValue();
int claseActual = ((Integer) arrayClases[c]).intValue();
if (frecActual == frecMayoritaria && claseActual != mayoritaria) {
repetida = true;
}
c++;
}
//The frequencies of output values are in 'frecuencias' 'Map' and
//majority output value is in 'mayoritaria'. Variable 'repetida' is true if there is tie between several majority output values
if (repetida) {
//There is more than one majority output value, so return MIN_VALUE
mayoritaria = Integer.MIN_VALUE;
}
} else {
Exception e = new Exception(
"Something wrong happens with vector size. ini: " + ini +
", fin: " + fin + ", med: " + med + ", enc: " + enc +
", mayoritaria: " + mayoritaria + ", vIni: " + vIni);
throw e;
}
return mayoritaria;
}
/*
private void obtieneFrecuencias(int campo)
{
//El vector est� ordenado por los valores del campo 'campo'
//as� q nos permite utilizar la b�squeda binaria
double actual;
double anterior=-1;
double antiguo=-1;
int i=0;
int valorAnt=0;
//Creamos un vector para contener las ocurrencias de cada valor del campo clase
Vector frecuencias=new Vector();
actual=((Double)((Vector)bd.getBase().get(0)).get(campo)).doubleValue();
int clase=((Integer)((Vector)bd.getBase().get(0)).get(bd.getClase())).intValue();
while(i < bd.getNumEjemplos())
{
if(i > 0)
{
if(actual == anterior && anterior >= 0)
{
if(frecuencias.size() > clase && frecuencias.get(clase) != null)
{
valorAnt=((Integer)frecuencias.get(clase)).intValue();
}
else
{
if(frecuencias.size() < (clase+1))
frecuencias.setSize(clase+1);
valorAnt=0;
}
frecuencias.setElementAt(new Integer(valorAnt+1),clase); //Apuntamos una ocurrencia m�s de la clase
anterior=actual;
actual=((Double)((Vector)bd.getBase().get(++i)).get(campo)).doubleValue();
clase=((Integer)((Vector)bd.getBase().get(++i)).get(bd.getClase())).intValue();
}
else
{
//A�adimos el vector de frecuencias para
bd.addFrecuencias(frecuencias);
//Comenzamos con un vector nuevo
frecuencias=new Vector();
if(frecuencias.size() > clase && frecuencias.get(clase) != null)
{
valorAnt=((Integer)frecuencias.get(clase)).intValue();
}
else
{
if(frecuencias.size() < (clase+1))
frecuencias.setSize(clase+1);
valorAnt=0;
}
frecuencias.setElementAt(new Integer(valorAnt+1),clase); //Apuntamos una ocurrencia m�s de la clase
anterior=actual;
actual=((Double)((Vector)bd.getBase().get(++i)).get(campo)).doubleValue();
clase=((Integer)((Vector)bd.getBase().get(++i)).get(bd.getClase())).intValue();
}
}
else //Si es el primer valor...
{
if(frecuencias.size() < (clase+1))
frecuencias.setSize(clase+1);
valorAnt=0;
frecuencias.setElementAt(new Integer(valorAnt+1),clase); //Apuntamos una ocurrencia m�s de la clase
anterior=actual;
actual=((Double)((Vector)bd.getBase().get(++i)).get(campo)).doubleValue();
clase=((Integer)((Vector)bd.getBase().get(++i)).get(bd.getClase())).intValue();
}
for(int f=0;f < frecuencias.size();f++)
{
if(frecuencias.get(f) == null)
frecuencias.setElementAt(new Integer(0),f);
}
}
}
*/
/**
*
* @param j
* @param j1
* @param j2
* @param campo
* @return true if intervals Ii=[j, j1] and Ii+1=[j1, j2] are available to join themselves and false otherwise
* @throws Exception
*/
private boolean condicion(Corte j, Corte j1, Corte j2, int campo) throws
Exception {
//Interval Ii=[j,j1]
//Interval Ii+1=[j1,j2]
//Check that both intervals have the same output value
//Interval output value is the output value of the lower limit, then output values for Ii and Ii+1 will be j and j1
int claseI = j.getClase();
int claseI1 = j1.getClase();
boolean dev = false;
if (claseI != claseI1 && claseI != Integer.MIN_VALUE &&
claseI1 != Integer.MIN_VALUE) {
dev = false;
} else {
//Interval goodness is the goodness of the upper limit, then goodnesses for Ii and Ii+1 will be j1's and j2's ones
double bondadI = j1.getBondad();
double bondadI1 = j2.getBondad();
//Calculate intervals' goodness
double media = divide(suma(bondadI, bondadI1), 2.0);
//Calculate union's goodness
double bondadUnion = bondad(campo, j.getCorte(), j2.getCorte());
dev = (bondadUnion >= media);
}
return (dev);
}
/**
* @return Returns the cortes.
*/
public Vector getCortes() {
return cortes;
}
/**
* @param cort The cortes to set.
*/
public void setCortes(Vector cort) {
cortes = cort;
}
public String toString() {
String s = "";
Iterator it = this.getCortes().iterator();
int i = 0;
while (it.hasNext()) {
Vector v = (Vector) it.next();
Iterator it2 = v.iterator();
s += "\nAtributo: " + (String)this.getBd().getNombres().get(i) +
"\n";
s += "-----------------------------------------\n";
while (it2.hasNext()) {
Corte c = (Corte) it2.next();
s += c.getCorte() + ", " + c.getClase() + ", " + c.getBondad() +
"\n";
}
i++;
}
return s;
}
/**
*
* @param a
* @param b
* @return a+b
*/
public static double suma(double a, double b) { //return a+b
BigDecimal A = new BigDecimal("" + a);
BigDecimal B = new BigDecimal("" + b);
BigDecimal C = A.add(B);
return C.doubleValue();
}
/**
*
* @param a
* @param b
* @return a-b
*/
public static double resta(double a, double b) { //return a-b
BigDecimal A = new BigDecimal("" + a);
BigDecimal B = new BigDecimal("" + b);
BigDecimal C = A.subtract(B);
return C.doubleValue();
}
/**
*
* @param a
* @param b
* @return a*b
*/
public static double multiplica(double a, double b) { //return a*b
BigDecimal A = new BigDecimal("" + a);
BigDecimal B = new BigDecimal("" + b);
BigDecimal C = A.multiply(B);
return C.doubleValue();
}
/**
*
* @param a
* @param b
* @return a/b
*/
public static double divide(double a, double b) { //return a/b
BigDecimal A = new BigDecimal("" + a);
BigDecimal B = new BigDecimal("" + b);
BigDecimal C = A.divide(B, 3, BigDecimal.ROUND_HALF_DOWN);
return C.doubleValue();
}
/*
private double suma(double a, double b)
{
double c=a+b;
double r=0;
String decimales=String.valueOf(c);
String s[]=decimales.split("[.]");
if (s[1].lastIndexOf("9") > s[1].indexOf("9") || s[1].lastIndexOf("0") > s[1].indexOf("0"))
{
int n=0;
if(s[1].indexOf("9") > 0)
{
String num=new String();
for(int i=0;i < s[1].indexOf("9");i++)
{
num+=s[1].charAt(i);
}
n=Integer.parseInt(num);
n++;
}
else if(s[1].indexOf("0") > 0)
{
String num=new String();
for(int i=0;i < s[1].indexOf("0");i++)
{
num+=s[1].charAt(i);
}
n=Integer.parseInt(num);
}
r=Double.parseDouble(s[0]+"."+n);
}
else
{
r=c;
}
return r;
}
*/
}