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.cluster; 031 032import java.util.ArrayList; 033import java.util.List; 034import java.util.Map; 035import java.util.Map.Entry; 036 037import org.openimaj.experiment.evaluation.AnalysisResult; 038import org.openimaj.experiment.evaluation.Evaluator; 039import org.openimaj.experiment.evaluation.cluster.analyser.ClusterAnalyser; 040import org.openimaj.experiment.evaluation.cluster.processor.Clusterer; 041import org.openimaj.util.function.Function; 042 043/** 044 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 045 * 046 * @param <D> The type of data which the internal clusterer can cluster lists of 047 * @param <T> The type of results the 048 */ 049public class ClusterEvaluator<D, T extends AnalysisResult> implements Evaluator<int[][],T>{ 050 051 private int[][] correct; 052 private ClusterAnalyser<T> analyser; 053 private Clusterer<D> gen; 054 private D data; 055 056 /** 057 * @param gen 058 * @param data 059 * @param clusters 060 * @param analyser 061 */ 062 public ClusterEvaluator(Clusterer<D> gen, D data, int[][] clusters, ClusterAnalyser<T> analyser) { 063 this.gen = gen; 064 this.correct = clusters; 065 this.analyser = analyser; 066 this.data = data; 067 } 068 069 /** 070 * @param gen 071 * @param data 072 * @param dataset extract the elements of this map "in order" and build a ground truth. very dangerous. 073 * @param analyser 074 */ 075 public <A,B> ClusterEvaluator(Clusterer<D> gen, D data, Map<A,? extends List<B>> dataset, ClusterAnalyser<T> analyser) { 076 this.gen = gen; 077 this.correct = new int[dataset.size()][]; 078 int j = 0; 079 int k = 0; 080 for (Entry<A, ? extends List<B>> es : dataset.entrySet()) { 081 this.correct[j] = new int[es.getValue().size()]; 082 int i = 0; 083 List<B> value = es.getValue(); 084 for (int l = 0; l < value.size(); l++) { 085 this.correct[j][i++] = k; 086 k++; 087 } 088 j++; 089 } 090 this.analyser = analyser; 091 this.data = data; 092 } 093 094 /** 095 * @param gen 096 * @param data 097 * @param indexFunc given a data instance, return its index 098 * @param dataset 099 * @param analyser 100 */ 101 public <A,B> ClusterEvaluator( 102 Clusterer<D> gen, 103 D data, 104 Function<B,Integer> indexFunc, 105 Map<A,? extends List<B>> dataset, 106 ClusterAnalyser<T> analyser) { 107 this.gen = gen; 108 this.correct = new int[dataset.size()][]; 109 int j = 0; 110 for (Entry<A, ? extends List<B>> es : dataset.entrySet()) { 111 this.correct[j] = new int[es.getValue().size()]; 112 int i = 0; 113 List<B> value = es.getValue(); 114 for (B b : value) { 115 this.correct[j][i++] = indexFunc.apply(b); 116 } 117 j++; 118 } 119 this.analyser = analyser; 120 this.data = data; 121 } 122 123 /** 124 * @param gen 125 * @param dataset 126 * @param transform turn a list of dataset items into the required type for clustering 127 * @param analyser 128 */ 129 public <A,B> ClusterEvaluator( 130 Clusterer<D> gen, 131 Map<A,? extends List<B>> dataset, 132 Function<List<B>,D> transform, 133 ClusterAnalyser<T> analyser 134 ) { 135 this.gen = gen; 136 this.analyser = analyser; 137 this.correct = new int[dataset.size()][]; 138 int j = 0; 139 List<B> flattened = new ArrayList<B>(); 140 for (Entry<A, ? extends List<B>> es : dataset.entrySet()) { 141 this.correct[j] = new int[es.getValue().size()]; 142 int i = 0; 143 for (B b : es.getValue()) { 144 this.correct[j][i++] = flattened.size(); 145 flattened.add(b); 146 } 147 j++; 148 } 149 this.data = transform.apply(flattened); 150 } 151 152 153 154 155 156 @Override 157 public int[][] evaluate() { 158 return this.gen.performClustering(this.data); 159 } 160 161 @Override 162 public T analyse(int[][] estimated) { 163 return this.analyser.analyse(correct, estimated); 164 } 165 166}