/*********************************************************************** 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.M5Rules; import keel.Dataset.Attributes; /** * Class for handling a linear function. */ public final class Function{ int terms[]; double coeffs[]; /** * Constructs a function of constant value */ public Function() { terms = new int[1]; terms[0] = 0; coeffs = new double[1]; coeffs[0] = 0.0; } /** * Constucts a function with all attributes except the class in the inst * @param inst itemsets */ public Function(MyDataset inst) { int i, count = 0; terms = new int[inst.numAttributes()]; for (i = 0; i < inst.numAttributes() - 1; i++) { if (i != inst.getClassIndex()) { terms[++count] = i; } } terms[0] = count; coeffs = new double[count + 1]; } /** * Constructs a function with one attribute * @param attr an attribute */ public Function(int attr) { terms = new int[2]; terms[0] = 1; terms[1] = attr; coeffs = new double[2]; coeffs[0] = 0.0; coeffs[1] = 0.0; } /** * Makes a copy of a function * @return the copy of the function */ public final Function copy() { Function fcopy = new Function(); fcopy.terms = iVectorCopy(terms, terms[0] + 1); fcopy.coeffs = dVectorCopy(coeffs, terms[0] + 1); return fcopy; } public static final double[] dVectorCopy(double a[], int n) { int i; double b[]; b = new double[n]; for (i = 0; i < n; i++) { b[i] = a[i]; } return b; } public final static int[] iVectorCopy(int a[], int n) { int i, b[]; b = new int[n]; for (i = 0; i < n; i++) { b[i] = a[i]; } return b; } /** * Converts a function to a string * @param inst itemsets * @param startPoint the starting point on the screen; used to feed line before reaching beyond 80 characters * @return the converted string * @exception Exception if something goes wrong */ public final String toString(MyDataset inst, int startPoint) throws Exception { int i, j, count1, count, precision = 3; String string; StringBuffer text = new StringBuffer(); count1 = count = startPoint + inst.getClassAttribute().name().length() + 3; string = M5.doubleToStringG(coeffs[0], 1, precision); if (coeffs[0] >= 0.0) { count += string.length(); } else { count += 1 + string.length(); } text.append(inst.getClassAttribute().name() + " = " + string); for (i = 1; i <= terms[0]; i++) { string = M5.doubleToStringG(Math.abs(coeffs[i]), 1, precision); count += 3 + string.length() + inst.getAttribute(terms[i]).name().length(); if (count > 80) { text.append("\n"); for (j = 1; j <= count1 - 1; j++) { text.append(" "); } count = count1 - 1 + 3 + string.length() + inst.getAttribute(terms[i]).name().length(); } if (coeffs[i] >= 0.0) { text.append(" + "); } else { text.append(" - "); } text.append(string + inst.getAttribute(terms[i]).name()); } return text.toString(); } public final String toString() { int i, j, precision = 3; String string; StringBuffer text = new StringBuffer(); string = M5.doubleToStringG(coeffs[0], 1, precision); text.append(Attributes.getOutputAttribute(0).getName() + " = " + string); for (i = 1; i <= terms[0]; i++) { string = M5.doubleToStringG(Math.abs(coeffs[i]), 1, precision); if (coeffs[i] >= 0.0) { text.append(" + "); } else { text.append(" - "); } text.append(string + Attributes.getInputAttribute(terms[i]).getName()); } return text.toString(); } /** * Constructs a new function of which the variable list is a combination of those of two functions * @param f1 function 1 * @param f2 function 2 * @return the newly constructed function */ public final static Function combine(Function f1, Function f2) { Function f = new Function(); f.terms = iVectorCombine(f1.terms, f2.terms); f.coeffs = new double[f.terms[0] + 1]; return f; } public final static int[] iVectorCombine(int[] list1, int[] list2) { int i, j, k, count; int[] list; list = new int[list1[0] + list2[0] + 1]; count = 0; i = 1; j = 1; while (i <= list1[0] && j <= list2[0]) { if (list1[i] < list2[j]) { list[count + 1] = list1[i]; count++; i++; } else if (list1[i] > list2[j]) { list[count + 1] = list2[j]; count++; j++; } else { list[count + 1] = list1[i]; count++; i++; j++; } } if (i > list1[0]) { for (k = j; k <= list2[0]; k++) { list[count + 1] = list2[k]; count++; } } if (j > list2[0]) { for (k = i; k <= list1[0]; k++) { list[count + 1] = list1[k]; count++; } } list[0] = count; return list; } /** * Evaluates a function * @param inst itemsets * @return the evaluation results * @exception Exception if something goes wrong */ public final Results errors(MyDataset inst) throws Exception { int i; double tmp; Results e = new Results(0, inst.numItemsets() - 1); for (i = 0; i <= inst.numItemsets() - 1; i++) { tmp = this.predict(inst.itemset(i)) - inst.itemset(i).getClassValue(); e.sumErr += tmp; e.sumAbsErr += Math.abs(tmp); e.sumSqrErr += tmp * tmp; } e.meanAbsErr = e.sumAbsErr / e.numItemsets; e.meanSqrErr = (e.sumSqrErr - e.sumErr * e.sumErr / e.numItemsets) / e.numItemsets; e.meanSqrErr = Math.abs(e.meanSqrErr); e.rootMeanSqrErr = Math.sqrt(e.meanSqrErr); return e; } /** * Returns the predicted value of itemset i by a function * @param itemset itemset i * @return the predicted value */ public final double predict(Itemset itemset) { int j; double y; y = coeffs[0]; for (j = 1; j <= terms[0]; j++) { y += coeffs[j] * itemset.getValue(terms[j]); } return y; } /** * Detects the most insignificant variable in the funcion * @param sdy the standard deviation of the class variable * @param inst itemsets * @return the index of the most insignificant variable in the function */ public final int insignificant(double sdy, MyDataset inst) { int j, jmin = -1, jmax = -1; double min = 2.0, max = 2.5, sdx, contribution; for (j = 1; j <= terms[0]; j++) { sdx = M5.stdDev(terms[j], inst); if (sdy == 0.0) { contribution = 0.0; } else { contribution = Math.abs(coeffs[j] * sdx / sdy); } if (contribution < min) { min = contribution; jmin = j; } if (contribution > max) { max = contribution; jmax = j; } } if (max > 2.5) { jmin = jmax; } return jmin; } /** * Removes a term from the function * @param j the j-th index in the variable list in the function * @return the new function with the term removed */ public final Function remove(int j) { int i; Function f = new Function(); f.terms = new int[terms[0]]; f.terms[0] = terms[0] - 1; for (i = 1; i < j; i++) { f.terms[i] = terms[i]; } for (i = j; i <= terms[0] - 1; i++) { f.terms[i] = terms[i + 1]; } f.coeffs = new double[f.terms[0] + 1]; return f; } }