/*********************************************************************** 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.Associative_Classification.ClassifierCPAR; import java.util.*; /** * This class stores information to manage the PRM procedure. * This algorithm modifies FOIL to achieve higher accuracy and efficiency. * * * @author Written by Jesus Alcala (University of Granada) 09/02/2010 * @version 1.0 * @since JDK1.5 */ public class PRM { double alfa, delta, min_gain; int nClasses, nData; myDataset train; DataBase dataBase; RuleBase ruleBase; int[] P; int[] N; PNArray A; int[] Pc; int[] Nc; PNArray Ac; /** * <p> * Default Constructor * </p> */ public PRM() { } /** * <p> * Parameters Constructor * </p> * @param dataBase DataBase Set of training data which is necessary to compute PRM * @param train myDataset Training data set with information to compute PRM (mainly, the training examples) * @param ruleBase RuleBase Set of rules to be pruned * @param alfa double Weight decay factor * @param delta double Number of best rules we will take in account for each example * @param min_gain double Minimum gain threshold to be used */ public PRM(DataBase dataBase, myDataset train, RuleBase ruleBase, double alfa, double delta, double min_gain) { this.dataBase = dataBase; this.train = train; this.ruleBase = ruleBase; this.alfa = alfa; this.delta = delta; this.min_gain = min_gain; this.nClasses = this.train.getnClasses(); this.nData = this.train.getnData(); this.P = new int[this.nData]; this.N = new int[this.nData]; this.A = new PNArray(train, dataBase); this.Pc = new int[this.nData]; this.Nc = new int[this.nData]; this.Ac = new PNArray(train, dataBase); } /** * <p> * Main function of the method: it prunes the rulebase to obtain the final set of rules. * </p> */ public void generatePR () { int i, j; boolean stop, addLiteral; double totalWeight, bestGain; Literal lit; Rule r, ruleAux, ruleAux1; ArrayList<Rule> listRules; ArrayList<Literal> listGain; listRules = new ArrayList<Rule> (); // this.listGain = new ArrayList<Literal> (); for (i=0; i < this.nClasses; i++) { this.train.iniWeight(); this.iniPN(i); this.A.ini(i); totalWeight = this.delta * this.train.numberInstances(i); listRules.clear(); // this.listGain.clear(); stop = false; while ((this.getTotalWeight() > totalWeight) && !stop) { if (listRules.size() > 0) { r = listRules.get(0); listRules.remove(0); this.calculatePNc(r); this.calculateAc(r); } else { r = new Rule (train, dataBase, i); this.copyPN(); this.copyA(); } addLiteral = true; while ((r.getnAnts() < this.dataBase.numVariablesUsed()) && addLiteral) { // this.listGain.clear(); listGain = r.getGain(this.min_gain, this.Ac); if (listGain.size() > 0) { ruleAux = r.clone(); if (listGain.size() > 1) Collections.sort(listGain); lit = listGain.get(0); bestGain = lit.getGain(); r.setLabel(lit.getVariable(), lit.getValue()); this.changePNAc(lit); for (j=1; j < listGain.size(); j++) { lit = listGain.get(j); if (lit.getGain() >= (bestGain * 0.99)) { ruleAux1 = ruleAux.clone(); ruleAux1.setLabel(lit.getVariable(), lit.getValue()); listRules.add(ruleAux1); } else j = listGain.size(); } listGain.clear(); } else addLiteral = false; } if (r.getnAnts() > 0) { r.calculateLaplace(this.train); this.ruleBase.add(r); for (j=0; j < this.nData; j++) { if (this.Pc[j] > 0) { this.A.reducePositive(j); this.train.reduceWeight(j, this.alfa); this.A.incrPositive(j); } } } else stop = true; } } this.ruleBase.sort(); } /** * <p> * It initializes positive and negative values for each example for a given class * </p> * @param clas int Class to initialize positive and negative values of each example */ public void iniPN(int clas) { int i; for (i=0; i < this.nData; i++) { if (this.train.getOutputAsInteger(i) == clas) { this.P[i] = 1; this.N[i] = 0; } else { this.P[i] = 0; this.N[i] = 1; } } } /** * <p> * Function to copy P and N values to an auxiliar structure * </p> */ public void copyPN() { int i; for (i=0; i < this.nData; i++) { this.Pc[i] = this.P[i]; this.Nc[i] = this.N[i]; } } /** * <p> * Function to copy a PNArray to an auxiliar PNArray * </p> */ public void copyA() { this.Ac.copy(this.A); } /** * <p> * It computes positive and negative values for each example in the training set * by means a given rule * </p> * @param r Rule Rule used to compute P and N */ public void calculatePNc(Rule r) { int i; for (i=0; i < this.nData; i++) { if (r.matching(this.train.getExample(i)) > 0.0) { if (this.train.getOutputAsInteger(i) == r.getClas()) { this.Pc[i] = 1; this.Nc[i] = 0; } else { this.Pc[i] = 0; this.Nc[i] = 1; } } else { this.Pc[i] = 0; this.Nc[i] = 0; } } } /** * <p> * It computes the PNArray A' from a rule r * </p> * @param r Rule Rule used to compute the PNArray */ public void calculateAc(Rule r) { this.Ac.ini(r); } /** * <p> * It modifies positive and negative values and the PNArray of each example from a given literal * </p> * @param lit Literal Given literal to modify P, N and Ac */ public void changePNAc (Literal lit) { int j; int[] example; for (j=0; j < this.nData; j++) { example = this.train.getExample(j); if (this.Pc[j] > 0) { if (example[lit.getVariable()] != lit.getValue()) { this.Pc[j] = 0; this.Ac.reducePositive(j); } } else if (this.Nc[j] > 0) { if (example[lit.getVariable()] != lit.getValue()) { this.Nc[j] = 0; this.Ac.reduceNegative(j); } } } } /** * <p> * It returns the total weight of the positive classification * </p> * @return double Total weight */ public double getTotalWeight() { int i; double total; total = 0.0; for (i=0; i < this.nData; i++) { if (this.P[i] > 0) total += this.train.getWeight(i); } return (total); } }