/* * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * BinaryRelevanceAttributeEvaluator.java * Copyright (C) 2009-2010 Aristotle University of Thessaloniki, Thessaloniki, Greece */ package mulan.dimensionalityReduction; import mulan.data.MultiLabelInstances; import mulan.transformations.BinaryRelevanceTransformation; import weka.attributeSelection.ASEvaluation; import weka.attributeSelection.AttributeEvaluator; import weka.core.Instances; /** * @author George Traianos * @author Grigorios Tsoumakas */ public class BinaryRelevanceAttributeEvaluator extends ASEvaluation implements AttributeEvaluator { /** final scores for all attributes */ private double[] scores; /** The number of labels */ int numLabels; /**combination approach mode*/ private String CombApprMode; /**normalization mode*/ private String NormMode; /**attribute scoring based either on evaluation scores or ranking*/ private String ScoreMode; /** * a wrapper class for score-based attribute ranking */ public class Rank implements Comparable { /**score of the attribute*/ private double score; /**index of the attribute*/ private int index; /** * constructor * @param score the score to be given * @param index the index to be given */ public Rank(double score, int index) { this.score = score; this.index = index; } public double getScore() { return score; } public int getIndex() { return index; } public int compareTo(Object o) { if (score > ((Rank) o).score) { return 1; } else if (score < ((Rank) o).score) { return -1; } else { return 0; } } } /** * @param ase * @param mlData * @param combapp combination approach mode ("max", "avg", "min") * @param norm normalization mode ("dl", "dm", "none") * @param mode scoring mode ("eval", "rank") */ public BinaryRelevanceAttributeEvaluator(ASEvaluation ase, MultiLabelInstances mlData, String combapp, String norm, String mode) { CombApprMode = combapp; NormMode = norm; ScoreMode = mode; numLabels = mlData.getNumLabels(); int[] labelIndices = mlData.getLabelIndices(); try { int numAttributes = mlData.getFeatureIndices().length; double[][] evaluations = new double[numLabels][numAttributes]; for (int i = 0; i < numLabels; i++) { // create dataset Instances labelInstances = BinaryRelevanceTransformation.transformInstances(mlData.getDataSet(), labelIndices, labelIndices[i]); // build evaluator ase.buildEvaluator(labelInstances); // evaluate features for (int j = 0; j < numAttributes; j++) { evaluations[i][j] = ((AttributeEvaluator) ase).evaluateAttribute(j); } } //scoring of features scores = featureSelection(evaluations); } catch (Exception ex) { ex.printStackTrace(); } } /** * returns a ranking of attributes (where each attribute is represented by its index) * @param scores the attributes' scorelist * @return an ascending ranking of the attributes, based on their scores */ public int[] rankAsc(double scores[]) { /*create a table to hold each attribute's score and index*/ Rank r[] = new Rank[scores.length]; for (int i = 0; i < r.length; i++) { r[i] = new Rank(scores[i], i); } /*sort the table, thus resulting in ascending, score-based ranking*/ java.util.Arrays.sort(r); /*create a ranking table containing only the attributes' indices*/ int ranking[] = new int[r.length]; for (int i = 0; i < r.length; i++) { ranking[i] = r[i].getIndex(); } return ranking; } /** * returns a ranking of attributes (where each attribute is represented by its index) * @param scores the attributes' scorelist * @return a descending ranking of the attributes, based on their scores */ public int[] rankDesc(double scores[]) { int ranking[] = rankAsc(scores); int decr[] = new int[ranking.length]; /*receive the indices in reverse order, thus resulting in descending ranking*/ for (int i = 0; i < decr.length; i++) { decr[i] = ranking[(ranking.length - 1) - i]; } return decr; } /** * orders the ranking scores according to their attributes' original indices * @param ranking a rank table * @return the order of the ranking scores */ public int[] order(int ranking[]) { int order[] = new int[ranking.length]; for (int i = 0; i < ranking.length; i++) { order[ranking[i]] = i + 1; } return order; } /** * highest score combination approach * @param scoreList all attributes' score lists * @param index the index of a specific attribute's score * @return the highest score achieved in any of the the input score lists */ public double highest(double scoreList[][], int index) { double highest = scoreList[0][index]; for (int i = 1; i < scoreList.length; i++) { highest = (scoreList[i][index] > highest ? scoreList[i][index] : highest); } return highest; } /** * lowest score combination approach * @param scoreList all attributes' score lists * @param index the index of a specific attribute's score * @return the lowest score achieved in all of the input score lists */ public double lowest(double scoreList[][], int index) { double lowest = scoreList[0][index]; for (int i = 1; i < scoreList.length; i++) { lowest = (scoreList[i][index] < lowest ? scoreList[i][index] : lowest); } return lowest; } /** * average score combination approach * @param scoreList all attributes' score lists * @param index the index of a specific attribute's score * @return the average score achieved in all the score lists */ public double average(double scoreList[][], int index) { double sum = 0; for (int i = 0; i < scoreList.length; i++) { sum += scoreList[i][index]; } return sum / scoreList.length; } /** * performs attribute selection * @param evaluations evaluation scores * @return an array of scores for all attributes * @throws Exception */ private double[] featureSelection(double evaluations[][]) throws Exception { //perform dm or dl if (!NormMode.equalsIgnoreCase("none")) { if (NormMode.equalsIgnoreCase("dm")) { for (int i = 0; i < evaluations.length; i++) { evaluations[i] = dm(evaluations[i]); } } else if (NormMode.equalsIgnoreCase("dl")) { for (int i = 0; i < evaluations.length; i++) { evaluations[i] = dl(evaluations[i]); } } } //to hold attributes' scores double tempScores[][] = new double[numLabels][]; //rank based scoring of attributes if (ScoreMode.equalsIgnoreCase("rank")) { //perform ranking int ranks[][] = new int[numLabels][]; for (int i = 0; i < evaluations.length; i++) { ranks[i] = rankDesc(evaluations[i]); order(ranks[i]); } //transform ranking into a score for (int i = 0; i < ranks.length; i++) { tempScores[i] = new double[ranks[i].length]; for (int j = 0; j < ranks[i].length; j++) { tempScores[i][j] = (ranks[i].length - 1) + ranks[i][j]; } } } //evaluation score based scoring of attributes else if (ScoreMode.equalsIgnoreCase("eval")) { //simply copy the evaluation scores for (int i = 0; i < evaluations.length; i++) { tempScores[i] = java.util.Arrays.copyOf(evaluations[i], evaluations[i].length); } } //employ a combination approach method double combAppr[] = new double[tempScores[0].length]; if (CombApprMode.equalsIgnoreCase("max")) //highest { for (int i = 0; i < combAppr.length; i++) { combAppr[i] = highest(tempScores, i); } } else if (CombApprMode.equalsIgnoreCase("min")) //lowest { for (int i = 0; i < combAppr.length; i++) { combAppr[i] = lowest(tempScores, i); } } else if (CombApprMode.equalsIgnoreCase("avg")) //average { for (int i = 0; i < combAppr.length; i++) { combAppr[i] = average(tempScores, i); } } //return the scores for all attributes return combAppr; } /** * calculates the norm of a vector * @param vector a numeric array (as a vector) * @return the norm of the given vector */ public static double norm(double vector[]) { double sumsq = 0; for (int i = 0; i < vector.length; i++) { sumsq += Math.pow(vector[i], 2); } return Math.sqrt(sumsq); } /** * normalizes an array (in the range of [0,1]) * @param array a numeric array */ public static void normalize(double array[]) { /*find the largest element*/ double max = array[0]; for (int i = 1; i < array.length; i++) { max = (array[i] > max ? array[i] : max); } /*normalize all elements*/ for (int j = 0; j < array.length; j++) { array[j] /= max; } } /** * divide by length (dl) normalization * @param array a numeric array * @return a dl normalized copy of array */ public static double[] dl(double array[]) { /*a copy of the original array*/ double copy[] = new double[array.length]; copy = java.util.Arrays.copyOf(array, array.length); /*calculate the norm*/ double norm = norm(copy); /*divide each element by the norm*/ for (int i = 0; i < copy.length; i++) { copy[i] /= norm; } return copy; } /** * divide by maximum (dm) normalization * @param array a numeric array * @return a dm normalized copy of array */ public static double[] dm(double array[]) { /*a copy of the original array*/ double copy[] = new double[array.length]; copy = java.util.Arrays.copyOf(array, array.length); /*normalize the copy*/ normalize(copy); return copy; } @Override public double evaluateAttribute(int attribute) throws Exception { return scores[attribute]; } @Override public void buildEvaluator(Instances data) throws Exception { throw new UnsupportedOperationException("Not supported yet."); } }