/*********************************************************************** This file is part of KEEL-software, the Data Mining tool for regression, classification, clustering, pattern mining and so on. Copyright (C) 2004-2010 J. Alcal�-Fdez (jalcala@decsai.ugr.es) A. Fern�ndez (alberto.fernandez@ujaen.es) S. Garc�a (sglopez@ujaen.es) F. Herrera (herrera@decsai.ugr.es) L. S�nchez (luciano@uniovi.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: WKNN.java * * An implementation of a KNN classifier able to manage weights for instances and features * * @author Written by Joaqu�n Derrac (University of Granada) 13/1/2010 * @version 1.1 * @since JDK1.5 * */ package keel.Algorithms.Coevolution.CIW_NN; import java.util.Arrays; class WKNN{ private static double data[][]; private static int output[]; private static int nearestN; private static double minDist; private static double FW[]; private static int IS[]; private static double IW[]; private static int K; private static int nClasses; /** * Sets the K parameter of the KNN * * @param value */ public static void setK(int value){ if((value>0)&&(value<100)){ K=value; } } /** * Sets the number of classes of data * * @param value */ public static void setNClasses(int value){ nClasses=value; } /** * Sets training data for the KNN * * @param newData New training data */ public static void setData(double newData[][]){ data=new double [newData.length][newData[0].length]; for(int i=0;i<newData.length;i++){ System.arraycopy(newData[i],0,data[i], 0, newData[0].length); } } /** * Sets training output for the KNN * * @param newOutput New training output */ public static void setOutput(int newOutput[]){ output=new int [data.length]; System.arraycopy(newOutput,0,output, 0, data.length); } /** * Sets feature weights * * @param weights Feature weights */ public static void setFeatureWeights(double weigths []){ FW= new double [weigths.length]; System.arraycopy(weigths,0,FW, 0, weigths.length); } /** * Sets instance weights * * @param weights Instance weights */ public static void setInstanceWeights(double weigths []){ IW= new double [weigths.length]; System.arraycopy(weigths,0,IW, 0, weigths.length); } /** * Sets selected instances * * @param selected Selected instances */ public static void setInstances(int selected []){ IS= new int [selected.length]; System.arraycopy(selected,0,IS, 0, selected.length); } /** * Computes accuracy * * @return Training accuray */ public static double accuracy(){ int hits; int test; double acc; hits=0; for (int i=0; i<data.length; i++) { test=knnClassify(i); if(test==output[i]){ hits++; } } acc=(double)((double)hits/(double)data.length); return acc; } /** * Classify an instance from the training set * * @param index Index of the instance * * @return Class expected */ public static int classifyTrainInstance(int index){ return knnClassify(index); } /** * Classify a new example * * @param example New example * * @return Class expected */ public static int classifyNewInstance(double example[]){ double dist; int newClass; if(K==1){ nearestN=0; minDist=Double.MAX_VALUE; //1NN Method starts here for (int i=0; i<data.length; i++) { dist = newEuclideanDistance(example,i); //see if it's nearer than our previous selected neigbours if (dist < minDist) { minDist = dist; nearestN = i; } } newClass=output[nearestN]; }else{ double minDistArray[]; int nearestNArray[]; int selectedClasses[]; int prediction; int predictionValue; boolean stop; nearestNArray = new int[K]; minDistArray = new double[K]; Arrays.fill(nearestNArray, 0); Arrays.fill(minDistArray, Double.MAX_VALUE); //KNN Method starts here for (int i=0; i<data.length; i++) { dist = newEuclideanDistance(example,i); //see if it's nearer than our previous selected neighbors stop=false; for(int j=0;j<K && !stop;j++){ if (dist < minDistArray[j]) { for (int l = K - 1; l >= j+1; l--) { minDistArray[l] = minDistArray[l - 1]; nearestNArray[l] = nearestNArray[l - 1]; } minDistArray[j] = dist; nearestNArray[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; i++) { selectedClasses[output[nearestNArray[i]]]+=1; } prediction=0; predictionValue=selectedClasses[0]; for (int i=1; i<nClasses; i++) { if (predictionValue < selectedClasses[i]) { predictionValue = selectedClasses[i]; prediction = i; } } newClass=prediction; } return newClass; } /** * Classify an instance using the KNN classifier * * @param index Index of instance to avoid * * @return Class expected */ private static int knnClassify(int index){ int save; double dist; int newClass; //leave one out save=IS[index]; IS[index]=0; if(K==1){ nearestN=0; minDist=Double.MAX_VALUE; //1NN Method starts here for (int i=0; i<data.length; i++) { if(IS[i]==1){ dist = euclideanDistance(index,i); //see if it's nearer than our previous selected neigbours if (dist < minDist) { minDist = dist; nearestN = i; } } } newClass=output[nearestN]; }else{ double minDistArray[]; int nearestNArray[]; int selectedClasses[]; int prediction; int predictionValue; boolean stop; nearestNArray = new int[K]; minDistArray = new double[K]; Arrays.fill(nearestNArray, 0); Arrays.fill(minDistArray, Double.MAX_VALUE); //KNN Method starts here for (int i=0; i<data.length; i++) { if(IS[i]==1){ dist = euclideanDistance(index,i); //see if it's nearer than our previous selected neighbors stop=false; for(int j=0;j<K && !stop;j++){ if (dist < minDistArray[j]) { for (int l = K - 1; l >= j+1; l--) { minDistArray[l] = minDistArray[l - 1]; nearestNArray[l] = nearestNArray[l - 1]; } minDistArray[j] = dist; nearestNArray[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; i++) { selectedClasses[output[nearestNArray[i]]]+=1; } prediction=0; predictionValue=selectedClasses[0]; for (int i=1; i<nClasses; i++) { if (predictionValue < selectedClasses[i]) { predictionValue = selectedClasses[i]; prediction = i; } } newClass=prediction; } //undo leave-one-out IS[index]=save; return newClass; } /** * Computes the euclidean distance between two training instances * * @param a First instance * @param b Second instance * * @return Euclidean distance */ private static double euclideanDistance(int a,int b){ double length=0.0; double value; double iWeight; iWeight=IW[output[b]]; for (int i=0; i<data[a].length; i++) { value = data[a][i]-data[b][i]; length += FW[i]*value*value; } length = (0.2+(1-iWeight)*0.8)*Math.sqrt(length); return length; } /** * Computes the euclidean distance between atraining instance and a new example * * @param example New example * @param b Training instance * * @return Euclidean distance */ private static double newEuclideanDistance(double example [],int b){ double length=0.0; double value; double iWeight; iWeight=IW[output[b]]; for (int i=0; i<data[b].length; i++) { value = example[i]-data[b][i]; length += FW[i]*value*value; } length = (0.2+(1-iWeight)*0.8)*Math.sqrt(length); return length; } } //end-class