001 /** 002 * DetailedNFoldEvaluator.java 003 * jCOLIBRI2 framework. 004 * @author Juan A. Recio-García. 005 * @author Lisa Cummins. 006 * GAIA - Group for Artificial Intelligence Applications 007 * http://gaia.fdi.ucm.es 008 * 07/05/2007 009 */ 010 package jcolibri.extensions.evaluation.evaluators; 011 012 import java.util.ArrayList; 013 import java.util.Collection; 014 import java.util.Date; 015 import java.util.List; 016 017 import jcolibri.cbrcore.CBRCase; 018 import jcolibri.cbrcore.CBRCaseBase; 019 import jcolibri.extensions.evaluation.MaintenanceEvaluator; 020 021 import org.apache.commons.logging.LogFactory; 022 023 /** 024 * This evaluation method divides the case base into several random folds (indicated by the user). 025 * For each fold, their cases are used as queries and the remaining folds are used together as case base. 026 * This process is performed several times. 027 * 028 * @author Juan A. Recio García - GAIA http://gaia.fdi.ucm.es 029 * @author Lisa Cummins. 030 * @version 2.0 031 */ 032 public class MaintenanceNFoldEvaluator extends MaintenanceEvaluator 033 { 034 /** 035 * Executes the N-Fold evaluation. 036 * @param numFolds Number of folds (randomly generated). 037 * @param repetitions Number of repetitions 038 */ 039 public void NFoldEvaluation(int numFolds, int repetitions) 040 { try 041 { //Get the time 042 long t = (new Date()).getTime(); 043 int numberOfCycles = 0; 044 045 // Run the precycle to load the case base 046 LogFactory.getLog(this.getClass()).info("Running precycle()"); 047 CBRCaseBase caseBase = app.preCycle(); 048 049 if (!(caseBase instanceof jcolibri.casebase.CachedLinealCaseBase)) 050 LogFactory.getLog(this.getClass()).warn( 051 "Evaluation should be executed using a cached case base"); 052 053 Collection<CBRCase> cases = new ArrayList<CBRCase>(caseBase.getCases()); 054 055 //For each repetition 056 for(int r=0; r<repetitions; r++) 057 { //Create the folds 058 ArrayList<ArrayList<CBRCase>> folds = createFolds(cases, numFolds); 059 060 //For each fold 061 for(int f=0; f<numFolds; f++) 062 { ArrayList<CBRCase> querySet = new ArrayList<CBRCase>(); 063 prepareCases(cases, querySet, f, caseBase, folds); 064 065 //Run cycle for each case in querySet (current fold) 066 for(CBRCase c: querySet) 067 { LogFactory.getLog(this.getClass()).info( 068 "Running cycle() " + numberOfCycles); 069 app.cycle(c); 070 numberOfCycles++; 071 } 072 } 073 } 074 075 //Revert case base to original state 076 caseBase.forgetCases(cases); 077 caseBase.learnCases(cases); 078 079 //Run the poscycle to finish the application 080 LogFactory.getLog(this.getClass()).info("Running postcycle()"); 081 app.postCycle(); 082 083 //Complete the evaluation result 084 report.setTotalTime(t); 085 report.setNumberOfCycles(numberOfCycles); 086 087 } catch (Exception e) 088 { LogFactory.getLog(this.getClass()).error(e); 089 } 090 091 } 092 093 /** 094 * Prepares the cases for evaluation by setting up test and training sets 095 * @param originalCases Complete original set of cases 096 * @param querySet Where queries are to be stored 097 * @param fod The fold number 098 * @param caseBase The case base 099 */ 100 protected void prepareCases(Collection<CBRCase> originalCases, List<CBRCase> querySet, 101 int fold, CBRCaseBase caseBase, ArrayList<ArrayList<CBRCase>> folds) 102 { ArrayList<CBRCase> caseBaseSet = new ArrayList<CBRCase>(); 103 104 //Obtain the query and casebase sets 105 getFolds(fold, querySet, caseBaseSet, folds); 106 107 //Clear the caseBase 108 caseBase.forgetCases(originalCases); 109 110 //Set the cases that acts as casebase in this cycle 111 caseBase.learnCases(caseBaseSet); 112 113 if(this.simConfig != null && this.editMethod != null) 114 { // Perform maintenance on this case base 115 editCaseBase(caseBase); 116 } 117 } 118 119 /** 120 * Divides the given cases into the given number of folds 121 * @param cases the original cases 122 * @param numFolds the number of folds 123 */ 124 protected ArrayList<ArrayList<CBRCase>> createFolds(Collection<CBRCase> cases, int numFolds) 125 { ArrayList<ArrayList<CBRCase>> folds = new ArrayList<ArrayList<CBRCase>>(); 126 int foldsize = cases.size() / numFolds; 127 ArrayList<CBRCase> copy = new ArrayList<CBRCase>(cases); 128 129 for(int f=0; f<numFolds; f++) 130 { ArrayList<CBRCase> fold = new ArrayList<CBRCase>(); 131 for(int i=0; (i<foldsize)&&(copy.size()>0); i++) 132 { int random = (int) (Math.random() * copy.size()); 133 CBRCase _case = copy.get( random ); 134 copy.remove(random); 135 fold.add(_case); 136 } 137 folds.add(fold); 138 } 139 return folds; 140 } 141 142 /** 143 * Clears the current query and case base sets and populates the query set with fold 144 * f and the case base set with the cases not contained in fold f 145 * @param f the fold to use 146 * @param querySet the set of queries 147 * @param caseBaseSet the set of cases 148 */ 149 public static void getFolds(int f, List<CBRCase> querySet, List<CBRCase> caseBaseSet, ArrayList<ArrayList<CBRCase>> folds) 150 { querySet.clear(); 151 caseBaseSet.clear(); 152 153 querySet.addAll(folds.get(f)); 154 155 for(int i=0; i<folds.size(); i++) 156 if(i!=f) 157 caseBaseSet.addAll(folds.get(i)); 158 } 159 160 161 }