Tutorials‎ > ‎

Tutorial 7: Logging the statistics

Experimenting with genetic algorithm requires often to collect data regarding the evolution along the different experiments. In this tutorial we will learn how to capture evolution statistics in .csv and MS Excel files.




There are two three methods to log statistics in Jenes. The first is do-it-yourself by saving data in a file or database. The other two rely on loggers, available since Jenes 1.3.0. The easiest way is to use  a StatisticsLogger. This class is able to automatically record objects that belongs from LoggableStatistics, e.g. Population.Statistics and GeneticAlgorithm.Statistics objects. StatisticsLogger relies on a real logger to actually record the data on some medium. For example, it can make use of a CSVLogger for recording on .csv (i.e. comma separated values) file

072         csvlogger = new StatisticsLogger(
073                     new CSVLogger(new String[]{"LegalHighestScore", "LegalScoreAvg", "LegalScoreDev"}, FOLDER + "knapsackproblem.csv" ) );

or XLSLogger for recording directly in a MS Excel .xls file

075         xlslogge1 = new StatisticsLogger(
076                     new XLSLogger(new String[]{"LegalHighestScore", "LegalScoreAvg", "LegalScoreDev"}, FOLDER + "knapsack1.log.xls" ) );

Sometime it is useful to re-use a spreedsheet. In this case, we can specify which template to use in the constructor method of XLSLogger.

078         xlslogge2 = new StatisticsLogger(
079                     new XLSLogger(new String[]{"LegalHighestScore""LegalScoreAvg" "IllegalScoreAvg"}, FOLDER + "knapsack2.log.xls", FOLDER + "knapsack.tpl.xls" ) );

The third method makes direct use of real logger, for example

081         xlslogge3 = new XLSLogger(new String[]{"LegalHighestScore""LegalScoreAvg" "Run"}, FOLDER + "knapsack3.log.xls");


Loggers are able to process tabular data with a given schema, i.e. a set of labelled fields. The data schema has to be give at construction time. For instance in the first and second case we are interested to record LegalHighestScore, LegalScoreAvg and LegalScoreDev over the generations. In the third case we record LegalHighestScore, LegalScoreAvg and IllegalScoreAvg. Finally in the third case we record LegalHighestScore, LegalScoreAvg and Run, the latter representing the experimentation run number.

If we use StatisticsLogger, the fields has to be labelled the same way statistics are annotated by Loggable( label ). If we use directly the real loggers, we can make use of any label we wish for the schema, as the mapping will be on our charge, as described below.

Note that schema are case sensitive, so "someStatistic" is different from "SomeStatistic", and they are both different from "SOMESTATISTIC".


Recording on .csv files is straightforward. If the file exists, we can decide to overwrite data (default) or to append data.

When we use .xls files we should take care of some details. When the log file does not exists, the logger creates an empty workbook with one sheet, where columns are allocated according to the schema with first row allocated to field labels.

We can decide to use a pre-made .xls file. In this case we need to reserve a column for each field in the schema. The column can be placed anywhere in sheet, which sheet does not matter. The only constraint is that the cell at row 1 has to contain the field label. We can also decide to use a .xls file as template. A template is simply a pre-made file. In this case, the file is not overwritten as the destination is different (see xlslogge2 for an example).

For example we can decide to use the template shown in Figure 1.

Figure 1 - Template (knapsack.tpl.xls) used in this tutorial.

Data Collection

Once loggers are setup and schema defined, we can collect data. The best way to collect data is by means of listeners. For instance

143         GenerationEventListener<BooleanChromosome> logger1 =  new GenerationEventListener<BooleanChromosome>() {
145             public void onGeneration(GeneticAlgorithm ga, long time) {
146                 Population.Statistics stats = ga.getCurrentPopulation().getStatistics();
148                 prb.csvlogger.record(stats);
149                 prb.xlslogge1.record(stats);
150                 prb.xlslogge2.record(stats);
152             }
154         };

In this case StatisticsLogger takes care of logging data. We only need to provide a LoggableStatistics, and StatisticsLogger will do the job for us. The drawback to this solution is that we are not able to add data not considered by the statistics object. To gain a finer control of the process, we can make direct usage of a real logger. For instance

172         GenerationEventListener<BooleanChromosome> logger2 =  new GenerationEventListener<BooleanChromosome>() {
173             public void onGeneration(GeneticAlgorithm ga, long time) {
174                 Population.Statistics stats = ga.getCurrentPopulation().getStatistics();
176                 Group legals = stats.getGroup(Population.LEGALS);
178                 prb.xlslogge3.put("LegalHighestScore", legals.getMax());
179                 prb.xlslogge3.put("LegalScoreAvg", legals.getMin());
180                 prb.xlslogge3.put("Run", prb.exec);
182                 prb.xlslogge3.log();
183             }
185         };

In this case we can build a log record by ourselves.

Log closing

Finally we can make data persistent by closing the loggers.

165         prb.csvlogger.close();
166         prb.xlslogge1.close();
167         prb.xlslogge2.close();

195         prb.xlslogge3.close();


The output got at the end is depicted in the following figures. See also the attachments below.

Figure 2 - The output provided by csvlogger

Figure 3 - The output provided by xlslogge1

Figure 4 - The output provided by xlslogge2

Figure 5 - The output provided by xlslogge3

Pasquale Tatavitto,
Aug 3, 2011, 10:42 AM
Pasquale Tatavitto,
Aug 3, 2011, 10:42 AM
Pasquale Tatavitto,
Aug 3, 2011, 10:42 AM
Pasquale Tatavitto,
Aug 3, 2011, 10:42 AM
Pasquale Tatavitto,
Aug 3, 2011, 10:42 AM