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