/*********************************************************************** 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/ **********************************************************************/ /* -------------------------------------------------------------------------- */ /* */ /* RULE LIST */ /* */ /* Frans Coenen */ /* */ /* Tuesday 2 March 2004 */ /* */ /* Department of Computer Science */ /* The University of Liverpool */ /* */ /* -------------------------------------------------------------------------- */ /* Class structure AssocRuleMining | +-- RuleList */ // Java packages package keel.Algorithms.Associative_Classification.ClassifierCMAR; import org.core.*; import java.io.*; import java.util.*; import javax.swing.*; /** * Set of utilities to support various Association Rule Mining (ARM) algorithms included in the LUCS-KDD suite of ARM programs. * * @author Frans Coenen 2 March 2004 * @author Modified by Jesus Alcala (University of Granada) 09/02/2010 * @author Modified by Sergio Almecija (University of Granada) 23/05/2010 * @version 1.0 * @since JDK1.5 */ public class RuleList extends AssocRuleMining { /* ------ FIELDS ------ */ // --- Data structures --- /** Rule node in linked list of rules (either ARs or CRs). */ protected class RuleNode { /** Antecedent of AR. */ protected short[] antecedent; /** Consequent of AR. */ protected short[] consequent; /** The confidence value associate with the rule represented by this node. */ double confidenceForRule=0.0; /** Link to next node */ RuleNode next = null; /** Three argument constructor @param antecedent the antecedent (LHS) of the AR. @param consequent the consequent (RHS) of the AR. @param support the associated confidence value. */ private RuleNode(short[] ante, short[]cons, double confValue) { antecedent = ante; consequent = cons; confidenceForRule = confValue; } } /** Rule node in linked list of rules (either ARs or CRs) for CMAR algorithm. */ protected class RuleNodeCMAR { /** Antecedent of AR. */ protected short[] antecedent; /** Consequent of AR. */ protected short[] consequent; /** The confidence value associate with the rule represented by this node. */ double confidenceForRule=0.0; /** The support value associate with the rule represented by this node. */ double supportForRule=0.0; /** The support value associate with the antecedent of the rule represented by this node. */ double suppAntecedent=0.0; /** The support value associate with the consequent of the rule represented by this node. */ double suppConsequent=0.0; /** Link to next node */ RuleNodeCMAR next = null; /** Six argument constructor @param antecedent the antecedent (LHS) of the AR. @param consequent the consequent (RHS) of the AR. @param suppValue the associated support value. @param suppAnte the associated support for the antecedent. @param suppCons the associated support for the consequent. @param comsvalue the associated confidence value. */ private RuleNodeCMAR(short[] ante, short[]cons, double suppValue, double suppAnte, double suppCons, double confValue) { antecedent = ante; consequent = cons; supportForRule = suppValue; suppAntecedent = suppAnte; suppConsequent = suppCons; confidenceForRule = confValue; } } /** The reference to start of the rule list. */ protected RuleNode startRulelist = null; /** The reference to start of the CMAR rule list. */ protected RuleNodeCMAR startCMARrulelist = null; /** 1-D array for observed values for Chi-Squared Testing. */ private double[] obsValues = new double[4]; /** 1-D array for expected values for Chi-Squared Testing. */ private double[] expValues = new double[4]; // --- Chi-Squared Testing Constants --- /** Critical threshold for 25% "significance" level (assuming "degree of freedom" equivalent to 1). */ private static final double THRESHOLD_25 = 1.3233; /** Critical threshold for 25% "significance" level (assuming "degree of freedom" equivalent to 1). */ private static final double THRESHOLD_20 = 1.6424; /** Critical threshold for 10% "significance" level (assuming "degree of freedom" equivalent to 1). */ private static final double THRESHOLD_10 = 2.7055; /** Critical threshold for 5% "significance" level (assuming "degree of freedom" equivalent to 1). */ private static final double THRESHOLD_5 = 3.8415; /** Critical threshold for 2.5% "significance" level (assuming "degree of freedom" equivalent to 1). */ private static final double THRESHOLD_2HALF = 5.0239; /** Critical threshold for 1% "significance" level (assuming "degree of freedom" equivalent to 1). */ private static final double THRESHOLD_1 = 6.6349; /** Critical threshold for 0.5% "significance" level (assuming "degree of freedom" equivalent to 1). */ private static final double THRESHOLD_HALF = 7.8794; // Cover constant /** Minimum times a record mist be covered */ private static int MIN_COVER = 4; // At least 4 rules // --- Chi-Squared Fields --- /** Support value for the antecedent of the rule. */ private double supAntecedent; /** Support value for NOT the antecedent of the rule. */ private double supNotAntecedent; /** Support value for the concequent of the rule. */ private double supConsequent; /** Support value for NOT the concequent of the rule. */ private double supNotConsequent; /** Support for the rule. */ private double supRule; /** Number of records in the input (training) sets. */ private double numRecords; /** Current critical threshold value. */ private double threshold = THRESHOLD_20; // Default /* ------ CONSTRUCTORS ------ */ /** Default constructor to create an instance of the class RuleList */ public RuleList(int delta) { MIN_COVER = delta; } /* ------ METHODS ------ */ /* ---------------------------------------------------------------- */ /* */ /* RULE LINKED LIST ORDERED ACCORDING TO CMAR RANKING */ /* */ /* ---------------------------------------------------------------- */ /* Methods for inserting rules into a linked list of rules ordered according to CMAR ranking. Each rule described in terms of 4 fields: 1) Antecedent (an item set), 2) a consequent (an item set), 3) a total support value and 4) a confidence value (double). */ /* INSERT (ASSOCIATION/CLASSIFICATION) RULE INTO RULE LINKED LIST (ORDERED ACCORDING CONFIDENCE). */ /** Inserts an (association/classification) rule into the linkedlist of rules pointed at by <TT>startRulelist</TT>. <P> List is ordered according to "CMAR" ranking. @param antecedent the antecedent (LHS) of the rule. @param consequent the consequent (RHS) of the rule. @param supportForAntecedent the associated support for the antecedent. @param supportForConsequent the associated support for the consequent. @param supportForRule the associated support value. @param confidenceForRule the associated confidence value. */ protected void insertRinRlistCMARranking(short[] antecedent, short[] consequent, double supportForAntecedent, double supportForConsequent, double supportForRule, double confidenceForRule) { // Test rule using Chi-Squared testing if (!testRuleUsingChiSquaredTesting(supportForAntecedent, supportForConsequent,supportForRule,numRows)) return; // Create new node RuleNodeCMAR newNode = new RuleNodeCMAR(antecedent,consequent, supportForRule,supportForAntecedent, supportForConsequent,confidenceForRule); // Empty rule list situation if (startCMARrulelist == null) { startCMARrulelist = newNode; return; } // Check if more general rule with higher ranking exists. if (moreGeneralRuleExists(newNode)) return; // Add new node to start if (ruleIsCMARgreater(newNode,startCMARrulelist)) { newNode.next = startCMARrulelist; startCMARrulelist = newNode; return; } // Add new node to middle RuleNodeCMAR markerNode = startCMARrulelist; RuleNodeCMAR linkRuleNode = startCMARrulelist.next; while (linkRuleNode != null) { if (ruleIsCMARgreater(newNode,linkRuleNode)) { markerNode.next = newNode; newNode.next = linkRuleNode; return; } markerNode = linkRuleNode; linkRuleNode = linkRuleNode.next; } // Add new node to end markerNode.next = newNode; } /* MORE GENERAL EXISTS */ /** Tests whether a more general rule, with higher ranking, already exists in the rule list. @param rule the rule under consideration. @return true if more general rule with higher ranking exists, and false otherwise. */ private boolean moreGeneralRuleExists(RuleNodeCMAR rule) { RuleNodeCMAR linkRef = startCMARrulelist; // Loop through list while (linkRef!=null) { if (ruleIsMoreGeneral(rule,linkRef) && ruleIsCMARgreater2(rule,linkRef)) return(true); linkRef=linkRef.next; } // Default return return(false); } /* RULE IS MORE GENERAL */ /** Compares two rules and returns true if the first is a more general rule than the second (has fewer antecedent attributes). @param rule1 the given rule to be compared to the second. @param rule2 the rule which the given rule1 is to be compared to. @return true id rule1 is greater then rule2, and false otherwise. */ private boolean ruleIsMoreGeneral(RuleNodeCMAR rule1, RuleNodeCMAR rule2) { if (rule1.antecedent.length < rule2.antecedent.length) return(true); // Otherwise return false return(false); } /* RULE IS CMAR GREATER */ /** Compares two rules and returns true if the first is "CMAR greater" (has a higher ranking) than the second. <P> CMAR ordering is as follows: <OL> <LI>Confidence, a rule <TT>r1</TT> has priority over a rule <TT>r2</TT> if <TT>confidence(r1) > confidence(r2)</TT>. <LI>Support, a rule <TT>r1</TT> has priority over a rule <TT>r2</TT> if <TT>confidence(r1)==confidence(r2) && support(r1)>support(r2) </TT>. <LI>Size of antecedent, a rule <TT>r1</TT> has priority over a rule <TT>r2</TT> if <TT>confidence(r1)==confidence(r2) && support(r1)==spoort(r2) &&|A<SUB>r1</SUB>|<|A<SUB>r2</SUB>| </TT>. </OL> @param rule1 the given rule to be compared to the second. @param rule2 the rule which the given rule1 is to be compared to. @return true id rule1 is greater then rule2, and false otherwise. */ private boolean ruleIsCMARgreater(RuleNodeCMAR rule1, RuleNodeCMAR rule2) { // Compare confidences if (rule1.confidenceForRule > rule2.confidenceForRule) return(true); // If confidences are the same compare support values if (similar2dec(rule1.confidenceForRule,rule2.confidenceForRule)) { if (rule1.supportForRule > rule2.supportForRule) return(true); // If confidences and supports are the same compare antecedents if (similar2dec(rule1.supportForRule,rule2.supportForRule)) { if (rule1.antecedent.length < rule2.antecedent.length) return(true); } } // Otherwise return false return(false); } /* RULE IS CMAR GREATER 2 */ /** Compares two rules, such that the first id more general than the second, and returns true if the first is "CMAR greater" (has a higher ranking) than the second. <P> Method similar to ruleIsCMARgreater method but with the "more general rule" prerequisite. CMAR ordering (founded on confidence and support only) is as follows: <OL> <LI>Confidence, a rule <TT>r1</TT> has priority over a rule <TT>r2</TT> if <TT>confidence(r1) > confidence(r2)</TT>. <LI>Support, a rule <TT>r1</TT> has priority over a rule <TT>r2</TT> if <TT>confidence(r1)==confidence(r2) && support(r1)>support(r2) </TT>. </OL> @param rule1 the given rule to be compared to the second. @param rule2 the rule which the given rule1 is to be compared to. @return true id rule1 is greater then rule2, and false otherwise. */ private boolean ruleIsCMARgreater2(RuleNodeCMAR rule1, RuleNodeCMAR rule2) { // Compare confidences if (rule1.confidenceForRule > rule2.confidenceForRule) return(true); // If confidences are the same compare support values if (similar2dec(rule1.confidenceForRule,rule2.confidenceForRule)) { if (rule1.supportForRule > rule2.supportForRule) return(true); } // Otherwise return false return(false); } /* -------------------------------------------- */ /* */ /* CHI SQUARED TESTING */ /* */ /* -------------------------------------------- */ /* TEST RULE USING CHI SQUARED TESTING */ /** Tests a classification rule with the given parameters to determine the interestingness/surprisingness of the rule. @param supA the support value for the antecedent of the rule. @param supC the support value for the consequent of the rule. @param supAC the support for the rule. @param numR the number of records in the input (training) sets. @return true if Chi squared value is above critical threshold and false otherwise. */ public boolean testRuleUsingChiSquaredTesting(double supA, double supC, double supAC, double numR) { // Calculate Chi squared value double chiSquaredValue = getChiSquaredValue(supA,supC,supAC,numR); // Test Chi Squared value. if (chiSquaredValue>threshold) return(true); else return(false); } /* GET CHI-SQUARED VALUE */ /** Calculates and returns the Chi-Squared value for a rule. @param supA the support value for the antecedent of the rule. @param supC the support value for the consequent of the rule. @param supAC the support for the rule. @param numR the number of records in the input (training) sets. @return the Chi squared value. */ private double getChiSquaredValue(double supA, double supC, double supAC, double numR) { // Set values supAntecedent = supA; supConsequent = supC; supRule = supAC; numRecords = numR; // Calculate observed and expected values calculateObsValues(); calculateExpValues(); // Calculate and return Chi squared value return(calcChiSquaredValue()); } /* CALCULATE OBSERVED VALUES */ /** Calculates observed values for Chi squared testing calculation. */ private void calculateObsValues() { obsValues[0] = supRule; obsValues[1] = supAntecedent - supRule; obsValues[2] = supConsequent - supRule; obsValues[3] = numRecords - supAntecedent - supConsequent + supRule; // Calculate additional support values supNotAntecedent = numRecords - supAntecedent; supNotConsequent = numRecords - supConsequent; } /* CALIULASTE EXPECTED VALUES */ /** Calculates expected values for Chi squared testing calculation. */ private void calculateExpValues() { expValues[0] = (supConsequent * supAntecedent) / numRecords; expValues[1] = (supNotConsequent * supAntecedent) / numRecords; expValues[2] = (supConsequent * supNotAntecedent) / numRecords; expValues[3] = (supNotConsequent * supNotAntecedent) / numRecords; } /* CALCULATE CHI SQUARED VALUE */ /** Calculates the Chi squared values and returns their sum. @return the sum of the Chi Squared values. */ private double calcChiSquaredValue() { double sumChiSquaredValues = 0.0; for (int index=0;index<obsValues.length;index++) { double chiValue = Math.pow((obsValues[index] - expValues[index]),2.0)/expValues[index]; sumChiSquaredValues = sumChiSquaredValues+chiValue; } // Return return(sumChiSquaredValues); } /* ------------------------------------------------------------- */ /* */ /* RULE PRUNING (CMAR) */ /* */ /* ------------------------------------------------------------- */ /* PRUNE USING COVER */ /** Prunes the current CMAR list of rules according to the "cover" principle. @param trainingSet the input data set. */ protected void pruneUsingCover(short[][] trainingSet) { // Initialise cover array int[] cover = new int[trainingSet.length]; // Define rule list references RuleNodeCMAR newStartRef = null; RuleNodeCMAR markerRef = null; RuleNodeCMAR linkRef = startCMARrulelist; // Loop through rule list while (linkRef!=null) { // If no more training records end if (emptyDataSet(trainingSet)) break; // Set cover flag to false, will be set to true of a rule matches // a record. boolean coverFlag=false; // Loop through training set for (int index=0;index<trainingSet.length;index++) { // If record satisfies a rule increment cover element for // record and set cover flag to true to indicate that rule // is required by at least one record if (isSubset(linkRef.antecedent,trainingSet[index])) { cover[index]++; coverFlag=true; } } // If current rule is required by at least one record (cover flag // set to true) add to new rule list if (coverFlag) { if (newStartRef==null) newStartRef=linkRef; else markerRef.next=linkRef; markerRef=linkRef; linkRef=linkRef.next; markerRef.next=null; } else linkRef=linkRef.next; // Remove records from training set if adequately covered for (int index=0;index<cover.length;index++) { if (cover[index]>MIN_COVER) trainingSet[index]=null; } } // Set rule list startCMARrulelist = newStartRef; } /* EMPTY DATA SET */ /** Tests whether a data set is empty or not (all records set to null). @param dataSet the input data set. @return true if empty, false othjerwise. */ private boolean emptyDataSet(short[][] dataSet) { // Loop through given data set for (int index=0;index<dataSet.length;index++) if (dataSet[index]!=null) return(false); // Default return(true); } /* ------------------------------------------------------------- */ /* */ /* CLASSIFIER */ /* */ /* ------------------------------------------------------------- */ /* CLASSIFY RECORD (USING WEIGHTED CHI SQUARED) */ /** Selects the best rule in a rule list according to the Weighted Chi- Squared (WCS) Value. <P> Proceed as follows: <OL> <LI>Collect rules that satisfy the record. if <OL type="i"> <LI>If consequents of all rules are all identical, or only one rule, classify record. <LI>Else group rules according to classifier and determine the combined effect of the rules in each group, the classifier associated with the "strongest group" is then selected. </OL> @param classification the possible classes. @param itemset the record to be classified. @return the class label (or 0 if no class found). */ protected short classifyRecordWCS(short[] itemSet) { RuleNodeCMAR linkRef = startCMARrulelist; RuleNodeCMAR tempRulelist = startCMARrulelist; startCMARrulelist=null; // Obtain rules that satisfy record (iremSet) obtainallRulesForRecord(linkRef,itemSet); // If no rules satisfy record return 0 if (startCMARrulelist==null) { startCMARrulelist = tempRulelist; return(0); } // If only one rule return class if (startCMARrulelist.next== null) { short answer = startCMARrulelist.consequent[0]; startCMARrulelist=tempRulelist; return(answer); } // If more than one rule but all have the same class return calss if (onlyOneClass()) { short answer = startCMARrulelist.consequent[0]; startCMARrulelist=tempRulelist; return(answer); } // Group rules RuleNodeCMAR[] ruleGroups = groupRules(); // Determine Weighted Chi-Squared (WCS) Values for each group double[] wcsValues = calcWCSvalues(ruleGroups); // Select group with best WCS value and return associated label short consequent = selectBestWCS(wcsValues); // Reset global rule list reference startCMARrulelist=tempRulelist; // Return class return(consequent); } /* GROUP RULES */ /** Groups rules contained in a linked list of rules pointed at by <TT>startCMARrulelist</TT> according to their consequent. @return an array of rule groups. */ private RuleNodeCMAR[] groupRules() { // Initialise rule groups data structure RuleNodeCMAR[] ruleGroups = new RuleNodeCMAR[numClasses]; for (int index=0;index<ruleGroups.length;index++) ruleGroups[index]=null; // Loop through rule list RuleNodeCMAR linkRef = startCMARrulelist; while (linkRef!=null) { // Identify index for consequent int index = numOneItemSets-linkRef.consequent[0]; // Add to rule group RuleNodeCMAR ruleCopy = new RuleNodeCMAR(linkRef.antecedent, linkRef.consequent,linkRef.supportForRule, linkRef.suppAntecedent,linkRef.suppConsequent, linkRef.confidenceForRule); ruleCopy.next=ruleGroups[index]; ruleGroups[index]=ruleCopy; // Increment link reference linkRef=linkRef.next; } // Return return(ruleGroups); } /* ONLY ONE CLASS */ /** Checks whether given rule list consequents all refer to the same class or not. @return true if identical consequent in all rules, false otherwise. */ private boolean onlyOneClass() { RuleNodeCMAR linkRef = startCMARrulelist; // Class for first rule. short firstClass = linkRef.consequent[0]; // loop through rest of list. linkRef = linkRef.next; while (linkRef!=null) { if (linkRef.consequent[0]!=firstClass) return(false); linkRef=linkRef.next; } // Default return return(true); } /* CALCULATE WEIGHTED CHI SQUARED VALUE FOR RULE GROUPS */ /** Determines and returns the weighted Chi Squared values for the groups of rules. @param ruleGroups the given groups of rule. @return array of weighted Chi-Squared value for a set of rule groups */ private double[] calcWCSvalues(RuleNodeCMAR[] ruleGroups) { // Dimension array double[] wcsArray = new double[ruleGroups.length]; for (int index=0;index<ruleGroups.length;index++) { RuleNodeCMAR linkRuleNode = ruleGroups[index]; double wcsValue = 0.0; while (linkRuleNode != null) { double chiSquaredValue = getChiSquaredValue(linkRuleNode.suppAntecedent, linkRuleNode.suppConsequent, linkRuleNode.supportForRule,numRecords); double chiSquaredUB = calcChiSquaredUpperBound(linkRuleNode.suppAntecedent, linkRuleNode.suppConsequent); wcsValue = wcsValue + (chiSquaredValue*chiSquaredValue)/chiSquaredUB; linkRuleNode = linkRuleNode.next; } wcsArray[index]=wcsValue; } // Return return(wcsArray); } /* BEST WCS VALUE */ /** Determines the best of the given WCS values and returns the consequent associated with this bet value. @param wcsArray the given array of weighted Chi-Squared value for a set of rule groups. @return the selected consequent. */ private short selectBestWCS(double[] wcsValues) { double bestValue = wcsValues[0]; int bestIndex = 0; for (int index=1;index<wcsValues.length;index++) { if (wcsValues[index]>bestValue) { bestValue=wcsValues[index]; bestIndex=index; } } // Return return((short) (numOneItemSets-bestIndex)); } /* CALCULATE CHI SQUARED VALUE UPPER BOUND */ /** Claculates the upper bound for the Chi-Squared value of a rule. @param suppAnte the support for the antecedent of a rule. @param suppCons the support for the consequent of a rule. @return the Chi-Squared upper bound. */ private double calcChiSquaredUpperBound(double suppAnte, double suppCons) { double term; // Test support for antecedent and confidence and choose minimum if (suppAnte<suppCons) term = Math.pow(suppAnte-((suppAnte*suppCons)/numRecords),2.0); else term = Math.pow(suppCons-((suppAnte*suppCons)/numRecords),2.0); // Determine e double eVlaue = calcWCSeValue(suppAnte,suppCons); // Rerturn upper bound return(term*eVlaue*numRecords); } /* CALCULATE WCS e VALUE. */ /** Calculates and returns the e value for calculating Weighted Chi-Squared (WCS) values. @param suppAnte the support for the antecedent of a rule. @param suppCons the support for the consequent of a rule. @return the ECS e value. */ private double calcWCSeValue(double suppAnte, double suppCons) { double term1 = 1/(suppAnte*suppCons); double term2 = 1/(suppAnte*(numRecords-suppCons)); double term3 = 1/(suppCons*(numRecords-suppAnte)); double term4 = 1/((numRecords-suppAnte)*(numRecords-suppCons)); // Return sum return(term1+term2+term3+term4); } /* ------------------------------------------------------------- */ /* CLASSIFIER (UTILITY METHODS) */ /* ------------------------------------------------------------- */ /** Places all rules that satisfy the given record in a CMAR rule linked list pointed at by startCMARrulelist field, in the order that rules are presented. <P> Used in Weighted Chi-Squared classification (CMAR) algorithm. @param linkref The reference to the start of the existing list of rules. @param itemset the record to be classified. */ private void obtainallRulesForRecord(RuleNodeCMAR linkRef, short[] itemSet) { RuleNodeCMAR newStartRef = null; RuleNodeCMAR markerRef = null; // Loop through linked list of existing rules while (linkRef!=null) { // If rule satisfies record add to new rule list if (isSubset(linkRef.antecedent,itemSet)) { RuleNodeCMAR newNode = new RuleNodeCMAR(linkRef.antecedent, linkRef.consequent,linkRef.supportForRule, linkRef.suppAntecedent,linkRef.suppConsequent, linkRef.confidenceForRule); if (newStartRef==null) newStartRef=newNode; else markerRef.next=newNode; markerRef=newNode; /*if (newStartRef==null) newStartRef=linkRef; else markerRef.next=linkRef; markerRef=linkRef; */ } linkRef=linkRef.next; } // Set rule list startCMARrulelist = newStartRef; } /* ----------------------------------- */ /* */ /* GET METHODS */ /* */ /* ----------------------------------- */ /* GET NUMBER OF RULES */ /** Returns the number of generated rules (usually used in conjunction with classification rule mining algorithms rather than ARM algorithms). @return the number of CRs. */ public int getNumCRs() { int number = 0; RuleNode linkRuleNode = startRulelist; // Loop through linked list while (linkRuleNode != null) { number++; linkRuleNode = linkRuleNode.next; } // Return return(number); } /* GET NUMBER OF CMAR CLASSIFICATION RULES */ /** Returns the number of generated CMAR classification rules. @return the number of CRs. */ public int getNumCMAR_CRs() { int number = 0; RuleNodeCMAR linkRuleNode = startCMARrulelist; // Loop through linked list while (linkRuleNode != null) { number++; linkRuleNode = linkRuleNode.next; } // Return return(number); } /* ----------------------------------- */ /* */ /* SET METHODS */ /* */ /* ----------------------------------- */ /* SET NUMBER OF ROWS */ /** Sets number of rows field. */ protected void setNumRows(int numR) { numRows=numR; } /* SET NUMBER OF CLASSES */ /** Sets number of rows field. */ protected void setNumClasses(int numC) { numClasses=numC; } /* SET NUMBER OF ONE ITEM SETS */ /** Sets number of one item sets field. */ protected void setNumOneItemSets(int nois) { numOneItemSets=nois; } /* SET START CMAR RULE LIST TO NULL. */ protected void setStartCMARrulelistToNull() { startCMARrulelist = null; } /* SET DATA ARRAT */ /** Set 2-D "short" data array reference. */ /*protected void setDataArray(short[][] dArray) { dataArray=dArray; } */ /* SET RECONVERSION ARRAYS */ /** Sets the reconversion array reference values. @param conversionArrayRef the reference to the 2-D array used to renumber coulmns for input data in terms of frequency of single attributes (reordering will enhance performance for some ARM and CARM algorithms). @param reconversionArrayRef the reference to the 1-D array used to reconvert input data column numbers to their original numbering where the input data has been ordered to enhance computational efficienvy. */ protected void setReconversionArrayRefs(int[][] conversionArrayRef, short[] reconversionArrayRef) { conversionArray = conversionArrayRef; reconversionArray = reconversionArrayRef; } /* ------------------------------ */ /* */ /* OUTPUT */ /* */ /* ------------------------------ */ /* OUTPUT CMAR RULE LINKED LIST */ /** Outputs contents of CMAR rule linked list (if any) */ public void outputCMARrules(String filename) { String stringOut = new String(""); stringOut = outputRules(startCMARrulelist); Files.writeFile(filename, stringOut); } /* OUTPUT CMAR RULE LINKED LIST WITH RECONVERSION */ /** Outputs contents of CMAR rule linked list (if any) */ public void outputCMARrulesWithReconversion() { outputRulesWithReconversion(startCMARrulelist); } /** Outputs given CMAR rule list. @param ruleList the given rule list. */ public String outputRules(RuleNodeCMAR ruleList) { String stringOut = new String(""); int number, nAnt; // Check for empty rule list if (ruleList==null) return ("No rules generated!"); // Loop through rule list number = 1; nAnt = 0; RuleNodeCMAR linkRuleNode = ruleList; while (linkRuleNode != null) { nAnt += linkRuleNode.antecedent.length; stringOut += ("(" + number + ") "); stringOut += outputRule(linkRuleNode); stringOut += "\n"; stringOut += (" Conf: " + twoDecPlaces(linkRuleNode.confidenceForRule) + "%, (SuppRule: " + linkRuleNode.supportForRule + ", SuppAnt: " + linkRuleNode.suppAntecedent + ", SuppCons: " + linkRuleNode.suppConsequent + ")"); stringOut += "\n\n"; number++; linkRuleNode = linkRuleNode.next; } stringOut += "\n\n"; stringOut = "@Number of rules: " + getNumCMAR_CRs() + " Number of Antecedents by rule: " + nAnt * 1.0 / getNumCMAR_CRs() + "\n\n" + stringOut; return (stringOut); } /** Outputs a CMAR rule. @param rule the rule to be output. */ private String outputRule(RuleNodeCMAR rule) { String stringOut = new String(""); stringOut += outputItemSet(rule.antecedent); stringOut += " -> "; stringOut += outputItemSet(rule.consequent); return (stringOut); } /* OUTPUT RULE LINKED LIST WITH RECONVERSION */ /** Outputs contents of rule linked list (if any) with reconversion. */ public void outputRulesWithReconversion(RuleNodeCMAR ruleList) { // Check for empty rule list if (ruleList==null) System.out.println("No rules generated!"); outputConversionArrays(); // Loop through rule list int number = 1; RuleNodeCMAR linkRuleNode = ruleList; while (linkRuleNode != null) { System.out.print("(" + number + ") "); outputItemSetWithReconversion(linkRuleNode.antecedent); System.out.print(" -> "); outputItemSet(linkRuleNode.consequent); System.out.println(" " + linkRuleNode.confidenceForRule + "%"); number++; linkRuleNode = linkRuleNode.next; } } /* OUTPUT RULE LINKED LIST WITH DEFAULT */ /** Outputs contents of rule linked list (if any), with reconversion, such that last rule is the defualt rule. */ /*public void outputRulesWithDefault() { int number = 1; RuleNode linkRuleNode = startRulelist; while (linkRuleNode != null) { // Output rule number System.out.print("(" + number + ") "); // Output antecedent if (linkRuleNode.next==null) System.out.print("Default -> "); else { outputItemSet(linkRuleNode.antecedent); System.out.print(" -> "); } // Output concequent outputItemSet(linkRuleNode.consequent); System.out.println(" " + linkRuleNode.confidenceForRule + "%"); // Increment parameters number++; linkRuleNode = linkRuleNode.next; } } */ /* OUTPUT RULE LINKED LIST WITH DEFAULT AND RECONVERSION */ /** Outputs contents of rule linked list (if any), with reconversion, such that last rule is the defualt rule. */ /*public void outputRulesWithDefaultRecon() { int number = 1; RuleNode linkRuleNode = startRulelist; while (true) { // Output rule number System.out.print("(" + number + ") "); // Output antecedent if (linkRuleNode.next==null) { System.out.print("Default -> "); break; } else { outputItemSetWithReconversion(linkRuleNode.antecedent); System.out.print(" -> "); } // Output concequent outputItemSetWithReconversion(linkRuleNode.consequent); System.out.println(" " + linkRuleNode.confidenceForRule + "%"); // Increment parameters number++; linkRuleNode = linkRuleNode.next; } } */ /* OUTPUT NUMBER OF RULES */ /** Outputs number of generated rules (ARs or CARS). */ public void outputNumRules() { System.out.println("Number of rules = " + getNumCRs()); } /* OUTPUT NUMBER OF CMAR RULES */ /** Outputs number of generated rules (ARs or CARS). */ public void outputNumCMARrules() { System.out.println("Number of CMAR rules = " + getNumCMAR_CRs()); } }