/***********************************************************************
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.Genetic_Rule_Learning.LogenPro;
import org.core.Randomize;
/**
* <p>
* @author Written by Alberto Fern�ndez (University of Granada) 01/01/2007
* @author Modified by Francisco Jos� Berlanga (University of Ja�n) 09/12/2008
* @version 1.0
* @since JDK 1.6
* </p>
*/
public class Individual implements Comparable {
/**
* <p>
* An individual of the population
* </p>
*/
Condition[] Arbol;
boolean[] tokens;
String clase;
int fp, tp, fn, tn;
boolean n_e;
double fitness;
double soporte_min, w1, w2;
int num_emparejados;
int num_anys;
/**
* <p>
* Constructor
* </p>
* @param dataset myDataset Set of examples
* @param min_support double Minimun support parameter for the fitness function
* @param w1 double Weight of the Confidence factor in the fitness function
* @param w2 double Weight of the Support factor in the fitness function
*/
public Individual(myDataset dataset, double min_support, double w1,
double w2) {
int variables = dataset.getnInputs();
Arbol = new Condition[variables];
num_anys = 0;
for (int i = 0; i < variables; i++) {
assignCondition(i, dataset);
}
clase = dataset.getOutputValue(Randomize.RandintClosed(0, dataset.getnClasses()));
soporte_min = min_support;
this.w1 = w1;
this.w2 = w2;
n_e = true;
tokens = new boolean[dataset.getnData()];
}
/**
* <p>
* Determines if an example is covered by the individual
* </p>
* @param ejemplo double[] Example to compare
* @param perdidos boolean [] True in those values of the example which are missing-values
* @return boolean TRUE if the individual matches the example. FALSE otherwise.
*/
public boolean matching(double[] ejemplo, boolean [] perdidos) {
boolean salida = true;
for (int i = 0; i < ejemplo.length && salida == true; i++) {
salida = Arbol[i].matching(ejemplo[i], perdidos[i]);
}
return (salida);
}
/**
* <p>
* Evaluates (calculate the fitness of) the individual
* </p>
* @param dataset myDataset Set of examples
*/
public void evaluate(myDataset dataset) {
num_emparejados = 0;
int num_correctamente_emparejados = 0;
int ejemplos_clase_individuo = dataset.numberInstances(this.clase);
for (int i = 0; i < dataset.getnData(); i++) {
tokens[i] = false;
if (this.matching(dataset.getExample(i), dataset.getMissing(i))) {
num_emparejados++;
tokens[i] = true;
if (this.clase.equalsIgnoreCase(dataset.getOutputAsString(i))) {
num_correctamente_emparejados++;
}
}
}
double support = (double) num_emparejados / dataset.getnData();
double normalized_cf = 0.0;
double prob = (double) ejemplos_clase_individuo /
dataset.getnData();
if (num_correctamente_emparejados > 0) {
double cf = (double) num_correctamente_emparejados /
num_emparejados;
normalized_cf = cf * Math.log(cf / prob);
}
if (support < soporte_min) {
fitness = support;
} else {
fitness = (w1 * support) + (w2 * normalized_cf);
}
n_e = false;
}
/**
* <p>
* Returns the class in the consequent of the individual
* </p>
* @return String The name of the class in the consequent of the individual
*/
public String getClase() {
return (this.clase);
}
/**
* <p>
* Prints the tree encoded in the individual as a string
* </p>
* @return String Contains the tree encoded in the individual
*/
public String printIndividual_bk() {
// Se imprime el IF
String regla = new String("IF ");
for (int i = 0; i < Arbol.length - 1; i++) {
regla += Arbol[i].print();
regla += "AND";
}
regla += Arbol[Arbol.length - 1].print();
regla += ", Class = " + clase + ", " + fitness;
return regla;
}
/**
* <p>
* Prints the tree encoded in the individual as a string
* </p>
* @return String Contains the tree encoded in the individual
*/
public String printIndividual() {
String regla = new String("");
for (int i = 0; i < Arbol.length - 1; i++) {
regla += Arbol[i].print();
if (Arbol[i].getType() != Arbol[i].ANY){
regla += "AND";
}
}
regla += Arbol[Arbol.length - 1].print();
regla += ": " + clase + ", Fitness: " + fitness;
return regla;
}
/**
* <p>
* It assigns a condition to the atribute in position "atributo"
* </p>
* @param atributo int The position of the attribute
* @param dataset myDataset The set of examples
*/
private void assignCondition(int atributo, myDataset dataset) {
if ((Randomize.Rand() > 0.5) && (num_anys < dataset.getnInputs() - 1)) {
Condition c = new Condition(0, Condition.ANY, dataset.nameVar(atributo));
Arbol[atributo] = c;
num_anys++;
} else {
assignConditionNoAny(atributo, dataset);
}
}
/**
* <p>
* It check it is possible to apply the dropping condition operator, which only can be applied if
* the number of "ANY" condition is the tree is less than number of input variables minus one.
* </p>
* @param atributos int Number of input variables
* @return boolean TRUE is if posible to apply the dropping condition operator. FALSE otherwise.
*/
public boolean applicableDropping(int atributos) {
return (num_anys < (atributos - 1));
}
/**
* <p>
* It assigns a condition to the atribute in position "atributo", but different to "ANY"
* </p>
* @param atributo int The position of the attribute
* @param dataset myDataset The set of examples
*/
public void assignConditionNoAny(int atributo, myDataset dataset) {
if (dataset.getType(atributo) == dataset.REAL) {
int tipo = Randomize.RandintClosed(2, Condition.TIPOMAX + 1);
if (tipo == Condition.ENTRE) {
double valor1 = Randomize.RanddoubleClosed(dataset.
getMin(atributo), dataset.getMax(atributo) + 1);
double valor2 = Randomize.RanddoubleClosed(dataset.
getMin(atributo), dataset.getMax(atributo));
if (valor1 > valor2) {
Condition c = new Condition(valor2, valor1,dataset.nameVar(atributo));
Arbol[atributo] = c;
} else {
Condition c = new Condition(valor1, valor2,dataset.nameVar(atributo));
Arbol[atributo] = c;
}
} else {
double valor1 = Randomize.RanddoubleClosed(dataset.
getMin(atributo), dataset.getMax(atributo));
Condition c = new Condition(valor1, tipo,dataset.nameVar(atributo));
Arbol[atributo] = c;
}
} else if (dataset.getType(atributo) == dataset.INTEGER) {
int tipo = Randomize.RandintClosed(0, Condition.TIPOMAX + 1);
if (tipo == Condition.ENTRE) {
double valor1 = Randomize.RandintClosed((int) dataset.
getMin(atributo), (int) dataset.getMax(atributo) + 1);
double valor2 = Randomize.RandintClosed((int) dataset.
getMin(atributo), (int) dataset.getMax(atributo) + 1);
if (valor1 > valor2) {
Condition c = new Condition(valor2, valor1,dataset.nameVar(atributo));
Arbol[atributo] = c;
} else {
Condition c = new Condition(valor1, valor2,dataset.nameVar(atributo));
Arbol[atributo] = c;
}
} else {
double valor1 = Randomize.RandintClosed((int) dataset.
getMin(atributo), (int) dataset.getMax(atributo) + 1);
Condition c = new Condition(valor1, tipo,dataset.nameVar(atributo));
Arbol[atributo] = c;
}
} else {
double valor = Randomize.RandintClosed((int) dataset.
getMin(atributo), (int) dataset.getMax(atributo) + 1);
Condition c = new Condition(valor, Condition.IGUAL,dataset.nameVar(atributo));
Arbol[atributo] = c;
}
}
/**
* <p>
* It changes the class in the consequent of the individual by a new one
* </p>
* @param dataset myDataset The set of examples
*/
public void assignNewClass(myDataset dataset) {
String clase_old = this.clase;
String clase_new = this.clase;
do {
clase_new = dataset.getOutputValue(Randomize.RandintClosed(0, dataset.getnClasses()));
} while (clase_old == clase_new);
this.clase = clase_new;
//System.out.println("Changing Class");
}
/**
* <p>
* It sets the condition for the variable in position "atributo" to ANY
* </p>
* @param atributo int The position of the variable
* @param nombre String The name of the variable
*/
public void setAny(int atributo, String nombre) {
Condition c = new Condition(0, Condition.ANY, nombre);
Arbol[atributo] = c;
num_anys++;
}
/**
* <p>
* It returns the condition for the variable in position "atributo"
* </p>
* @param atributo int The position of the variable
* @return Condition Condition for the variable
*/
public Condition getCondition(int atributo) {
return Arbol[atributo].clone();
}
/**
* <p>
* It sets to "c" the condition for the variable in position "atributo"
* </p>
* @param atributo int The position of the variable
* @param c Condition Condition for the variable
*/
public void setCondition(int atributo, Condition c) {
Arbol[atributo] = c;
}
/**
* <p>
* Constructor (create the individual as a copy of another individual)
* </p>
* @param padre Individual The individual used to assign the values to the new one
*/
public Individual(Individual padre) {
Arbol = new Condition[padre.Arbol.length];
for (int i = 0; i < Arbol.length; i++) {
Arbol[i] = padre.getCondition(i);
}
n_e = false;
clase = padre.getClase();
soporte_min = padre.soporte_min;
w1 = padre.w1;
w2 = padre.w2;
tokens = new boolean[padre.tokens.length];
}
/**
* <p>
* It returns if the individual has been evaluated o not
* </p>
* @return boolean TRUE is the individual has been evaluated. FALSE otherwise.
*/
public boolean non_evaluated() {
return n_e;
}
/**
* <p>
* It returns the number of examples that the individual matches
* </p>
* @return int Number of matched examples by the individual
*/
public int ideal() {
return this.num_emparejados;
}
/**
* <p>
* It sets the fitness of the individual to "fitness"
* </p>
* @param fitness double A fitness value
*/
public void setFitness(double fitness) {
this.fitness = fitness;
}
/**
* <p>
* It returns the fitness of the individual
* </p>
* @return double The fitness value of the individual
*/
public double getFitness() {
return this.fitness;
}
/**
* <p>
* It checks is the example in position "idEjemplo" is covered by the individual
* </p>
* @return boolean TRUE if the example in position "idEjemplo" is covered. FALSE otherwise
*/
public boolean isCovered(int idEjemplo) {
return tokens[idEjemplo];
}
/**
* <p>
* It checks is the condition for the variable in position "atributo" is equal to ANY
* </p>
* @return boolean TRUE if the condition is ANY. FALSE otherwise
*/
public boolean isAny(int atributo) {
return (Arbol[atributo].getType() == Condition.ANY);
}
/**
* <p>
* It generates a tree that matches the given example
* </p>
* @param example double[] The given example
* @param train myDataset The set of examples
*/
public void replace(double example[], myDataset train) {
n_e = true;
fitness = 0.0;
for (int i = 0; i < train.getnInputs(); i++) {
if (train.getType(i) == train.NOMINAL) {
Condition c = new Condition(example[i], Condition.IGUAL, train.nameVar(i));
} else {
double aleat1 = train.getMin(i);
double aleat2 = train.getMax(i);
if (example[i] == train.getMax(i)) {
Condition c = new Condition(example[i],
Condition.MENORIGUAL, train.nameVar(i));
Arbol[i] = c;
} else if (example[i] == train.getMin(i)) {
Condition c = new Condition(example[i],
Condition.MAYORIGUAL, train.nameVar(i));
Arbol[i] = c;
} else {
do {
aleat1 = Randomize.RanddoubleClosed(train.getMin(i),
train.getMax(i));
} while (aleat1 >= example[i]);
do {
aleat2 = Randomize.RanddoubleClosed(train.getMin(i),
train.getMax(i));
} while (aleat2 <= example[i]);
}
Condition c = new Condition(aleat1, aleat2, train.nameVar(i));
Arbol[i] = c;
}
}
}
/**
* <p>
* Compares the fitness value of two individuals
* </p>
* @return int Returns -1 if the the fitness of the first individual is lesser than the fitness of the second one.
* 1 if the the fitness of the first individual is greater than the fitness of the second one.
* 0 if both individuals have the same fitness value
*/
public int compareTo(Object a) {
if (((Individual) a).fitness < this.fitness) {
return -1;
}
if (((Individual) a).fitness > this.fitness) {
return 1;
}
return 0;
}
}