/***********************************************************************
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/
**********************************************************************/
/**
*
* File: Chromosome.java
*
* A chromosome implementation for FS algorithms
*
* @author Written by Joaqu�n Derrac (University of Granada) 13/11/2008
* @version 1.0
* @since JDK1.5
*
*/
package keel.Algorithms.Preprocess.Feature_Selection.Shared;
import org.core.*;
public class Chromosome implements Comparable<Object> {
//Cromosome data structure
private int genes[];
private double fitnessValue;
private boolean valid;
private static double data[][];
private static int dataOutput[];
private static int nInstances;
private static int nFeatures;
private static int nClasses;
private static double beta;
private static double mutationProb;
private static int K;
/**
* Builder.
*
* @param size Initial size
*/
public Chromosome (int size) {
double u;
genes = new int[size];
for (int i=0; i<size; i++) {
u = Randomize.Rand();
if (u < 0.5) {
genes[i] = 0;
}
else {
genes[i] = 1;
}
}
valid=false;
}
/**
* Builder.
*
* @param info Body of the chromosome
*/
public Chromosome (int info []) {
genes = new int[info.length];
for (int i=0; i<info.length; i++) {
genes[i]=info[i];
}
valid=false;
}
/**
* Builder.
*
* @param info Body of the chromosome
* @param fitness Fitness of the chromosome
*/
public Chromosome (int info [],double fitness) {
genes = new int[info.length];
for (int i=0; i<info.length; i++) {
genes[i]=info[i];
}
fitnessValue=fitness;
valid=true;
}
/**
* Stores the training data
*
* @param trainData Training data
* @param trainOutput Training output
*/
public static void setData(double trainData[][],int trainOutput []){
nInstances=trainData.length;
nFeatures=trainData[0].length;
data=new double [nInstances][nFeatures];
dataOutput=new int [nInstances];
for(int i=0;i<nInstances;i++){
System.arraycopy(trainData, 0, data, 0, nInstances);
}
System.arraycopy(trainOutput, 0, dataOutput, 0, nInstances);
}
/**
* Sets beta value
*
* @param value Value for beta
*/
public static void setBeta(double value){
beta=value;
}
/**
* Sets mutation value
*
* @param value Value for mutation
*/
public static void setMutationProb(double value){
mutationProb=value;
}
/**
* Sets K value
*
* @param value Value for K
*/
public static void setK(int value){
K=value;
}
/**
* Sets the number of classes
*
* @param value Number of classes
*/
public static void setNClasses(int value){
nClasses=value;
}
/**
* Get the body of a chromosome
*
* @return Body of a chromosome
*/
public int [] getGenes(){
return genes;
}
/**
* Get the number of genes selected
*
* @return Number of genes selected
*/
public int getNGenes(){
int count = 0;
for(int i=0;i<genes.length;i++){
if(genes[i]==1){
count++;
}
}
return count;
}
/**
* Get the fitness value
*
* @return Fitness value
*/
public double getFitness(){
return fitnessValue;
}
/**
* Tests if the chromosome is valid
*
* @return True if the chromosome is valid. False if not
*/
public boolean getValid(){
return valid;
}
/**
* Computes pruned Euclidean distance
*
* @param indexA First instance
* @param indexB Second instance
*
* @return Distance between instances
*/
private double prunedEuclideanDistance(int indexA,int indexB){
double length=0.0;
double value;
for (int i=0; i<nFeatures; i++) {
value = data[indexA][i]-data[indexB][i];
length += (double)genes[i]*value*value;
}
length = Math.sqrt(length);
return length;
}
/*
* Fitness function
*/
public void evaluate () {
double acc;
double red;
acc=classifyData();
red=getReductionRate();
fitnessValue=(beta*acc)+((1.0-beta)*red);
valid=true;
}
/**
* Gets reduction rate
*
* @return Reduction rate
*/
private double getReductionRate(){
double rate=0.0;
int count=0;
for(int i=0;i<genes.length;i++){
count+=genes[i];
}
rate= 1.0-((double)count/(double)genes.length);
return rate;
}
/**
* Gets accuracy rate
*
* @return Accuracy rate
*/
private double classifyData(){
double acc=0.0;
int result;
int errors=0;
for(int i=0;i<data.length;i++){
result=knnClassifier(data[i],i);
if(result!=dataOutput[i]){
errors++;
}
}
acc= 1.0-((double)errors/(double)data.length);
return acc;
}
/**
* Classify an example by means of the knn classifier
*
* @param example Example to classifiy
* @param index Instance to avoid
*
* @return CLass of the example
*/
private int knnClassifier(double [] example, int index){
double minDist[];
int nearestN[];
int selectedClasses[];
double dist;
int prediction;
int predictionValue;
boolean stop;
nearestN = new int[K];
minDist = new double[K];
for (int i=0; i<K; i++) {
nearestN[i] = 0;
minDist[i] = Double.MAX_VALUE;
}
//KNN Method starts here
for (int i=0; i<data.length; i++) {
if(i!=index){
dist = prunedEuclideanDistance(index,i);
//see if it's nearer than our previous selected neigbours
stop=false;
for(int j=0;j<K && !stop;j++){
if (dist < minDist[j]) {
for (int l = K - 1; l >= j+1; l--) {
minDist[l] = minDist[l - 1];
nearestN[l] = nearestN[l - 1];
}
minDist[j] = dist;
nearestN[j] = i;
stop=true;
}
}
}
}
//we have check all the instances... see what is the most present class
selectedClasses= new int[nClasses];
for (int i=0; i<nClasses; i++) {
selectedClasses[i] = 0;
}
for (int i=0; i<K && nearestN[i]!=-1; i++) {
selectedClasses[dataOutput[nearestN[i]]]+=1;
}
prediction=-1;
predictionValue=0;
for (int i=0; i<nClasses; i++) {
if (predictionValue < selectedClasses[i]) {
predictionValue = selectedClasses[i];
prediction = i;
}
}
return prediction;
}
/**
* PMX cross operator
*
* @param parent Parent chromosome
*
* @return Offspring
*/
public int [] crossPMX (int [] parent) {
int point1,point2;
int down,up;
int [] offspring;
point1 = Randomize.Randint (0, parent.length-1);
point2 = Randomize.Randint (0, parent.length-1);
if (point1 > point2) {
up = point1;
down = point2;
}
else {
up = point2;
down = point1;
}
//crossing first offspring (self)
for(int i=down; i<up; i++){
genes[i]=parent[i];
}
//crossing second offspring (outter)
offspring= new int [parent.length];
for(int i=0; i<down; i++){
offspring[i]=parent[i];
}
for(int i=down; i<up; i++){
offspring[i]=genes[i];
}
for(int i=up; i<parent.length; i++){
offspring[i]=parent[i];
}
valid=false;
return offspring;
}
/**
* Mutation Operator
*/
public void mutation() {
int i;
boolean change=false;
for (i=0; i<genes.length; i++) {
if (Randomize.Rand() < mutationProb) {
genes[i]=(genes[i]+1)%2;
change=true;
}
}
if(change){
valid=false;
}
}
/**
* Compare to method
*
* @param o1 Chromosome to compare
*
* @return Relative order
*/
public int compareTo (Object o1) {
if (this.fitnessValue > ((Chromosome)o1).fitnessValue)
return -1;
else if (this.fitnessValue < ((Chromosome)o1).fitnessValue)
return 1;
else return 0;
}
/**
* To string method
*
* @return String representation of the chromosome
*/
public String toString() {
int i;
String temp = "[";
for (i=0; i<genes.length; i++){
temp += genes[i];
}
temp += ", " + String.valueOf(fitnessValue);
return temp;
}
}//end-class