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.analyser; 031 032import gnu.trove.map.hash.TIntLongHashMap; 033import gnu.trove.procedure.TIntLongProcedure; 034import gov.sandia.cognition.math.MathUtil; 035 036import java.util.HashSet; 037import java.util.Map; 038import java.util.Set; 039 040import org.apache.log4j.Logger; 041 042/** 043 * Create an {@link AdjustedRandomIndexAnalysis} instance 044 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 045 */ 046public class AdjustedRandomIndexClusterAnalyser implements ClusterAnalyser<AdjustedRandomIndexAnalysis>{ 047 final static Logger logger = Logger.getLogger(AdjustedRandomIndexAnalysis.class); 048 @Override 049 public AdjustedRandomIndexAnalysis analyse(int[][] correct, int[][] estimated) { 050 TIntLongHashMap nij = new TIntLongHashMap(); 051 TIntLongHashMap ni = new TIntLongHashMap(); 052 TIntLongHashMap nj = new TIntLongHashMap(); 053 054 Map<Integer,Integer> invCor = ClusterAnalyserUtils.invert(correct); 055 logger.debug("Correct keys: " + invCor.size()); 056 Map<Integer,Integer> invEst = ClusterAnalyserUtils.invert(estimated); 057 logger.debug("Estimated keys: " + invCor.size()); 058 Set<Integer> sharedKeys = new HashSet<Integer>(); 059 sharedKeys.addAll(invCor.keySet()); 060 sharedKeys.retainAll(invEst.keySet()); 061 logger.debug("Shared keys: " + sharedKeys.size()); 062 for (Integer index : sharedKeys) { 063 int i = invCor.get(index); 064 int j = invEst.get(index); 065 nij.adjustOrPutValue(i * correct.length + j, 1, 1); 066 ni.adjustOrPutValue(i, 1, 1); 067 nj.adjustOrPutValue(j, 1, 1); 068 } 069 070 final long[] sumnij = new long[1]; 071 final long[] sumni = new long[1]; 072 final long[] sumnj = new long[1]; 073 final long[] sumn = new long[1]; 074 075 nj.forEachEntry(new TIntLongProcedure() { 076 077 @Override 078 public boolean execute(int a, long b) { 079 if(b > 1){ 080 sumnj[0] += MathUtil.binomialCoefficient((int)b, 2); 081 } 082 return true; 083 } 084 }); 085 086 ni.forEachEntry(new TIntLongProcedure() { 087 088 @Override 089 public boolean execute(int a, long b) { 090 if(b > 1){ 091 sumni[0] += MathUtil.binomialCoefficient((int)b, 2); 092 } 093 sumn[0] += b; 094 return true; 095 } 096 }); 097 nij.forEachEntry(new TIntLongProcedure() { 098 099 @Override 100 public boolean execute(int a, long b) { 101 if(b > 1){ 102 sumnij[0] += MathUtil.binomialCoefficient((int)b, 2); 103 } 104 return true; 105 } 106 }); 107 double bisumn = MathUtil.binomialCoefficient((int) sumn[0], 2); 108 double div = (sumni[0] * sumnj[0]) / bisumn; 109 AdjustedRandomIndexAnalysis ret = new AdjustedRandomIndexAnalysis(); 110 ret.adjRandInd = (sumnij[0] - div) / (0.5 * (sumni[0] + sumnj[0]) - div); 111 112 return ret; 113 } 114 115}