/***********************************************************************
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.ClassifierFuzzyFCRA;
import java.util.*;
import org.core.*;
/**
* This class contains the representation of a Rule Set
*
* @author Written by Jesus Alcala (University of Granada) 09/02/2010
* @version 1.0
* @since JDK1.5
*/
public class RuleBase {
ArrayList<Rule> ruleBase;
DataBase dataBase;
myDataset train;
int n_variables;
double fitness;
/**
* Maximization
* @param a int first number
* @param b int second number
* @return boolean true if a is better than b
*/
public boolean BETTER(int a, int b) {
if (a > b) return true;
return false;
}
/**
* <p>
* Default Constructor
* </p>
*/
public RuleBase() {
}
/**
* <p>
* Parameters Constructor
* </p>
* @param dataBase DataBase Set of training data which is necessary to generate a rule
* @param train myDataset Training data set with information to construct the rule base (mainly, the training examples)
*/
public RuleBase(DataBase dataBase, myDataset train) {
this.ruleBase = new ArrayList<Rule> ();
this.dataBase = dataBase;
this.train = train;
this.n_variables = dataBase.numVariables();
this.fitness = 0.0;
}
/**
* <p>
* Clone Function
* </p>
*
* @return a copy of the RuleBase
*/
public RuleBase clone() {
RuleBase br = new RuleBase();
br.ruleBase = new ArrayList<Rule> ();
for (int i = 0; i < this.ruleBase.size(); i++) br.ruleBase.add((this.ruleBase.get(i)).clone());
br.dataBase = this.dataBase;
br.train = this.train;
br.n_variables = this.n_variables;
br.fitness = this.fitness;
return (br);
}
/**
* <p>
* It adds a rule to the rule base
* </p>
* @param rule Rule Rule to be added
*/
public void add(Rule rule) {
this.ruleBase.add(rule);
}
/**
* <p>
* It adds a rule to the rule base
* </p>
* @param itemset Itemset itemset to be added
*/
public void add(Itemset itemset) {
int i;
Item item;
int[] antecedent = new int[n_variables];
for (i=0; i < n_variables; i++) antecedent[i] = -1; // Don't care
for (i=0; i < itemset.size(); i++) {
item = itemset.get(i);
antecedent[item.getVariable()] = item.getValue();
}
Rule r = new Rule(this.dataBase);
r.asignaAntecedente(antecedent);
r.setConsequent(itemset.getClas());
r.setConfidence(itemset.getSupportClass() / itemset.getSupport());
r.setSupport(itemset.getSupportClass());
this.ruleBase.add(r);
}
/**
* <p>
* Function to get a rule from the rule base
* </p>
* @param pos int Position in the rule base where the desired rule is stored
* @return Rule The desired rule
*/
public Rule get(int pos) {
return (this.ruleBase.get(pos));
}
/**
* <p>
* It returns the number of rules in the rule base
* </p>
* @return int Rule base's size
*/
public int size() {
return (this.ruleBase.size());
}
/**
* <p>
* Function to sort the rule base
* </p>
*/
public void sort () {
Collections.sort(this.ruleBase);
}
/**
* <p>
* It removes the rule stored in the given position
* </p>
* @param pos int Position where the rule we want to remove is
* @return Rule Removed rule
*/
public Rule remove(int pos) {
return (this.ruleBase.remove(pos));
}
/**
* <p>
* Function to evaluate the whole rule base by using the training dataset
* </p>
* @return double Fitness of the rule base
*/
public double evaluate() {
int nHits, Prediction;
nHits = 0;
for (int j = 0; j < train.size(); j++) {
Prediction = this.FRM_WR(train.getExample(j));
if (train.getOutputAsInteger(j) == Prediction) nHits++;
}
this.fitness = (100.0 * nHits) / (1.0 * this.train.size());
return (this.fitness);
}
/**
* <p>
* It returns the class which better fits to the given example
* </p>
* @param example int[] Example to be classified
* @return int Output class
*/
public int FRM(double[] example) {
return FRM_WR(example);
}
private int FRM_WR(double[] example) {
int clas = -1;
double max = 0.0;
for (int i = 0; i < this.ruleBase.size(); i++) {
Rule r = this.ruleBase.get(i);
double DF = r.matching(example);
if (DF > max) {
max = DF;
clas = r.getClas();
}
}
return clas;
}
/**
* <p>
* Function to return the fitness of the rule base
* </p>
* @return double Fitness of the rule base
*/
public double getAccuracy() {
return (this.fitness);
}
/**
* <p>
* Function to eliminate the redundant rules
* </p>
*/
public void reduceRules() {
int i, j;
Rule rulei, rulej;
this.sort();
for (i=0; i < this.ruleBase.size(); i++) {
rulei = this.ruleBase.get(i);
for (j = i+1; j < this.ruleBase.size(); j++) {
rulej = this.ruleBase.get(j);
if (rulei.isSubset(rulej)) {
this.ruleBase.remove(j);
j--;
}
}
}
}
/**
* <p>
* Function to adjust fuzzy confidences (Nozaki method)
* </p>
* @param n1 double learning rate
* @param n2 double learning rate
* @param Jmax int number of iterations
*/
public void adaptiveRules(double n1, double n2, int Jmax) {
int i, j, k, bestRule;
double max, DF, conf;
Rule r;
for (i=0; i < Jmax; i++) {
for (j = 0; j < this.train.size(); j++) {
max = -1;
bestRule = -1;
for (k = 0; k < this.ruleBase.size(); k++) {
r = this.ruleBase.get(k);
DF = r.matching(this.train.getExample(j));
if (DF > max) {
max = DF;
bestRule = k;
}
}
if (bestRule > -1) {
r = this.ruleBase.get(bestRule);
conf = r.getConfidence();
if (train.getOutputAsInteger(j) == r.getClas()) r.setConfidence(conf + (n1 * (1 - conf)));
else r.setConfidence(conf - (n2 * conf));
}
}
}
}
/**
* <p>
* It prints the whole rulebase
* </p>
* @return String The whole rulebase
*/
public String printString() {
int i, j, ant;
String [] names = train.names();
String [] clases = train.clases();
String stringOut = new String("");
ant = 0;
for (i = 0; i < this.ruleBase.size(); i++) {
Rule r = this.ruleBase.get(i);
stringOut += (i+1)+": ";
for (j = 0; j < n_variables && r.antecedent[j] < 0; j++);
if (j < n_variables && r.antecedent[j] >= 0) {
stringOut += names[j]+" IS " + r.dataBase.print(j,r.antecedent[j]);
ant++;
}
for (j++; j < n_variables-1; j++) {
if (r.antecedent[j] >=0) {
stringOut += " AND " + names[j]+" IS " + r.dataBase.print(j,r.antecedent[j]);
ant++;
}
}
if (j < n_variables && r.antecedent[j] >= 0) {
stringOut += " AND " + names[j]+" IS " + r.dataBase.print(j,r.antecedent[j]) + ": " + clases[r.clas];
ant++;
}
else stringOut += ": " + clases[r.clas];
stringOut += " CF: " + r.getConfidence() + "\n";
}
stringOut += "\n\n";
stringOut += "@supp and CF:\n\n";
for (i = 0; i < this.ruleBase.size(); i++) {
Rule rule = this.ruleBase.get(i);
stringOut += (i+1)+": ";
stringOut += "supp: " + rule.getSupport() + " AND CF: " + rule.getConfidence() + "\n";
}
stringOut = "@Number of rules: " + this.ruleBase.size() + " Number of Antecedents by rule: " + ant * 1.0 / this.ruleBase.size() + "\n\n" + stringOut;
return (stringOut);
}
/**
* <p>
* It stores the rule base in a given file
* </p>
* @param filename String Name for the rulebase file
*/
public void saveFile(String filename, double minFS, double minFC) {
String stringOut = new String("");
stringOut = printString();
stringOut += "\n\n@Minimum Support: " + minFS + " Minimum Confidence: " + minFC + "\n\n";
Files.writeFile(filename, stringOut);
}
}