001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix;
031
032import gov.sandia.cognition.learning.performance.categorization.ConfusionMatrix;
033
034import java.util.ArrayList;
035import java.util.List;
036
037import net.sf.jasperreports.engine.JasperPrint;
038
039import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
040import org.openimaj.experiment.evaluation.AnalysisResult;
041
042import com.bethecoder.ascii_table.ASCIITable;
043
044/**
045 * Aggregated confusion matrix results
046 * 
047 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
048 *
049 * @param <CLASS> The type of the classes represented by the {@link CMResult}s
050 */
051public class AggregatedCMResult<CLASS> implements AnalysisResult {
052        /**
053         * Aggregated accuracy and error rate.
054         * 
055         * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
056         */
057        public static class AggregateStatistics {
058                private double meanAccuracy;
059                private double stddevAccuracy;
060                
061                private double meanErrorRate;
062                private double stddevErrorRate;
063        }
064        
065        protected List<CMResult<CLASS>> matrices;
066
067        /**
068         * Default constructor
069         */
070        public AggregatedCMResult() {
071                this.matrices = new ArrayList<CMResult<CLASS>>();
072        }
073        
074        /**
075         * Construct with a list of results
076         * @param results the results
077         */
078        public AggregatedCMResult(List<CMResult<CLASS>> results) {
079                this.matrices = results;
080        }
081
082        /**
083         * Compute the current aggregate statistics of the
084         * accumulated results. 
085         * 
086         * @return the current aggregate statistics
087         */
088        public AggregateStatistics computeStatistics() {
089                DescriptiveStatistics accuracy = new DescriptiveStatistics();
090                DescriptiveStatistics errorRate = new DescriptiveStatistics();
091                
092                for (CMResult<CLASS> result : matrices) {
093                        ConfusionMatrix<CLASS> m = result.getMatrix();
094                        accuracy.addValue(m.getAccuracy());
095                        errorRate.addValue(m.getErrorRate());
096                }
097                
098                AggregateStatistics s = new AggregateStatistics();
099                s.meanAccuracy = accuracy.getMean();
100                s.stddevAccuracy = accuracy.getStandardDeviation();
101                
102                s.meanErrorRate = errorRate.getMean();
103                s.stddevErrorRate = errorRate.getStandardDeviation();
104                
105                return s;
106        }
107        
108        @Override
109        public String toString() {
110                return getSummaryReport();
111        }
112
113        @Override
114        public JasperPrint getSummaryReport(String title, String info) {
115                //FIXME:
116                throw new UnsupportedOperationException();
117        }
118
119        @Override
120        public JasperPrint getDetailReport(String title, String info) {
121                //FIXME:
122                throw new UnsupportedOperationException();
123        }
124
125        @Override
126        public String getSummaryReport() {
127                AggregateStatistics summary = computeStatistics();
128                
129                String [] header = {"Value", "Mean", "Standard Deviation"};
130                String [][] data = {
131                                { "Accuracy", String.format("%2.3f", summary.meanAccuracy), String.format("%2.3f", summary.stddevAccuracy) },
132                                { "Error Rate", String.format("%2.3f", summary.meanErrorRate), String.format("%2.3f", summary.stddevErrorRate) }
133                };
134                
135                return ASCIITable.getInstance().getTable(header, data);
136        }
137
138        @Override
139        public String getDetailReport() {
140                StringBuilder sb = new StringBuilder();
141                
142                sb.append("** Summary Report **\n");
143                sb.append(getSummaryReport());
144                sb.append("\n");
145                sb.append("** Per Run Reports **\n");
146                for (int i=0; i<this.matrices.size(); i++) {
147                        CMResult<CLASS> result = this.matrices.get(i);
148                        
149                        
150                        sb.append("***************************************************************\n");
151                        sb.append("* Run #"+i+"\n");
152                        sb.append("***************************************************************\n");
153                        sb.append(result.getDetailReport());
154                        sb.append("\n");
155                }
156                
157                return sb.toString();
158        }
159}