/// <summary> /// Self-evident. /// </summary> /// <param name="vals"></param> /// <param name="labels"></param> /// <returns></returns> public static AnnotatedScore[] Populate(double[] vals, float[] labels) { AnnotatedScore[] annScores = new AnnotatedScore[vals.Length]; for (int i=0; i<vals.Length; ++i) { annScores[i] = new AnnotatedScore(vals[i], labels[i], i); } return annScores; }
public static void DeepCopy(AnnotatedScore[] asIn, AnnotatedScore[] asOut) { if(asIn.Length != asOut.Length) throw new Exception("AnnotatedScore: DeepCopy: size mismatch"); for(int i=0; i<asIn.Length; ++i) { asOut[i].score = asIn[i].score; asOut[i].label = asIn[i].label; asOut[i].srcIdx = asIn[i].srcIdx; } }
/// <summary> /// WARNING: For speed, it is assumed that we can sort the scores and labels in place. Creating scratch space for this in the static /// constructor won't work with threading, and creating scratch space in the other constructor is very expensive, since may be called /// often. It is left to the user to make copies beforehand if necessary. /// </Summary> /// <param name="scores"></param> /// <param name="labels"></param> /// <param name="truncNDCG"></param> /// <param name="nonTruncNDCG"></param> public void ComputeDCGs(bool pessimistic, double[] scores, float[] labels, out double truncDCG, out double nonTruncDCG) { Debug.Assert(scores.Length == labels.Length, "scores, labels length mismatch"); AnnotatedScore[] annScores = new AnnotatedScore[scores.Length]; for(int i = 0; i < annScores.Length; ++i) { annScores[i] = new AnnotatedScore(scores[i], labels[i]); } ComputeDCGs(pessimistic, annScores, out truncDCG, out nonTruncDCG); }
/// <summary> /// If a bunch of urls have the same score, the mean NDCG for that bunch is the mean gain, times the total markup. /// Best to call this after ComputeOptimisticDCGs, since then the sorted order will be the same. Note that handling /// the truncated NDCG is tricky: if a block of urls with equal score, overlaps the truncation level, then you still /// have to compute the mean gain over the full block, and split the result to get the contribution to the truncated NDCG. /// </summary> /// <param name="annScores"></param> /// <param name="meanTruncDCG"></param> /// <param name="meanNonTruncDCG"></param> public void ComputeMeanDCGs(AnnotatedScore[] annScores, out double meanTruncDCG, out double meanNonTruncDCG) { Array.Sort(annScores, new OptimisticAnnotatedScoreComparer()); meanTruncDCG = 0.0; meanNonTruncDCG = 0.0; double score; double lastScore = annScores[0].score; double samePatchCtr = 0.0; double gain = 0.0; double markupTrunc = 0.0; double markupNonTrunc = 0.0; double deltaDCG; int truncLevel = DCGScorer.truncLevel < annScores.Length ? DCGScorer.truncLevel : annScores.Length; for (int rank = 0; rank < truncLevel; ++rank) { score = annScores[rank].score; if (score != lastScore) { deltaDCG = ( gain / samePatchCtr ) * markupTrunc; meanTruncDCG += deltaDCG; meanNonTruncDCG += deltaDCG; samePatchCtr = 1.0; gain = 0.0; markupTrunc = 0.0; lastScore = score; } else { ++samePatchCtr; } markupTrunc += DCGScorer.discounts[rank]; gain += DCGScorer.scoresMap[(int)annScores[rank].label]; } bool doneTruncComp = false; markupNonTrunc = markupTrunc; for (int rank = truncLevel; rank < annScores.Length; ++rank) { score = annScores[rank].score; if (score != lastScore) { if(!doneTruncComp) { meanTruncDCG += ( gain / samePatchCtr ) * markupTrunc; doneTruncComp = true; } meanNonTruncDCG += ( gain / samePatchCtr ) * markupNonTrunc; samePatchCtr = 1.0; gain = 0.0; markupNonTrunc = 0.0; lastScore = score; } else { ++samePatchCtr; } markupNonTrunc += DCGScorer.discounts[rank]; gain += DCGScorer.scoresMap[(int)annScores[rank].label]; } if(!doneTruncComp) { meanTruncDCG += ( gain / samePatchCtr ) * markupTrunc; } meanNonTruncDCG += ( gain / samePatchCtr ) * markupNonTrunc; }
public void ComputeDCGs(bool pessimistic, AnnotatedScore[] annScores, out double truncDCG, out double nonTruncDCG) { if (pessimistic) Array.Sort(annScores, new PessimisticAnnotatedScoreComparer()); else Array.Sort(annScores, new OptimisticAnnotatedScoreComparer()); truncDCG = 0.0; nonTruncDCG = 0.0; for (int rank = 0; rank < annScores.Length; ++rank) { double markup = DCGScorer.discounts[rank]; double gain = DCGScorer.scoresMap[(int)annScores[rank].label]; if (rank < DCGScorer.truncLevel) { truncDCG += markup * gain; } nonTruncDCG += markup * gain; } }