@ Override public void compute ( ) { if ( ! Double . isNaN ( getValue ( ) ) ) { // since the data cannot change, avoid re-doing the calculations return ; } iniCompute ( ) ; Map < U , List < Pair < I , Double > > > data = processDataAsRankedTestRelevance ( ) ; userDcgAtCutoff = new HashMap < Integer , Map < U , Double > > ( ) ; userIdcgAtCutoff = new HashMap < Integer , Map < U , Double > > ( ) ; int nUsers = 0 ; for ( Map . Entry < U , List < Pair < I , Double > > > e : data . entrySet ( ) ) { U user = e . getKey ( ) ; List < Pair < I , Double > > sortedList = e . getValue ( ) ; double dcg = 0.0 ; int rank = 0 ; for ( Pair < I , Double > pair : sortedList ) { double rel = pair . getSecond ( ) ; rank ++ ; dcg += computeDCG ( rel , rank ) ; // compute at a particular cutoff for ( int at : getCutoffs ( ) ) { if ( rank == at ) { Map < U , Double > m = userDcgAtCutoff . get ( at ) ; if ( m == null ) { m = new HashMap < U , Double > ( ) ; userDcgAtCutoff . put ( at , m ) ; } m . put ( user , dcg ) ; } } } // assign the ndcg of the whole list to those cutoffs larger than the list's size for ( int at : getCutoffs ( ) ) { if ( rank <= at ) { Map < U , Double > m = userDcgAtCutoff . get ( at ) ; if ( m == null ) { m = new HashMap < U , Double > ( ) ; userDcgAtCutoff . put ( at , m ) ; } m . put ( user , dcg ) ; } } Map < I , Double > userTest = new HashMap <> ( ) ; for ( I i : getTest ( ) . getUserItems ( user ) ) { userTest . put ( i , getTest ( ) . getUserItemPreference ( user , i ) ) ; } double idcg = computeIDCG ( user , userTest ) ; double undcg = dcg / idcg ; if ( ! Double . isNaN ( undcg ) ) { setValue ( getValue ( ) + undcg ) ; getMetricPerUser ( ) . put ( user , undcg ) ; nUsers ++ ; } } setValue ( getValue ( ) / nUsers ) ; }
Computes the global NDCG by first summing the NDCG for each user and then averaging by the number of users .