diff options
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/evaluation/scores/PrecisionAtKEvaluation.java')
-rw-r--r-- | src/de/lmu/ifi/dbs/elki/evaluation/scores/PrecisionAtKEvaluation.java | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/evaluation/scores/PrecisionAtKEvaluation.java b/src/de/lmu/ifi/dbs/elki/evaluation/scores/PrecisionAtKEvaluation.java new file mode 100644 index 00000000..97ab0abd --- /dev/null +++ b/src/de/lmu/ifi/dbs/elki/evaluation/scores/PrecisionAtKEvaluation.java @@ -0,0 +1,127 @@ +package de.lmu.ifi.dbs.elki.evaluation.scores; +/* + This file is part of ELKI: + Environment for Developing KDD-Applications Supported by Index-Structures + + Copyright (C) 2014 + Ludwig-Maximilians-Universität München + Lehr- und Forschungseinheit für Datenbanksysteme + ELKI Development Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter; + +/** + * Evaluate using Precision@k, or R-precision (when {@code k=0}). + * + * When {@code k=0}, then it is set to the number of positive objects, and the + * returned value is the R-precision, or the precision-recall break-even-point + * (BEP). + * + * @author Erich Schubert + */ +public class PrecisionAtKEvaluation extends AbstractScoreEvaluation { + /** + * Static instance + */ + public static final PrecisionAtKEvaluation RPRECISION = new PrecisionAtKEvaluation(0); + + /** + * Parameter k. + */ + int k; + + /** + * Constructor. + * + * @param k k to evaluate at. May be 0. + */ + public PrecisionAtKEvaluation(int k) { + this.k = k; + } + + @Override + public <I extends ScoreIter> double evaluate(Predicate<? super I> predicate, I iter) { + final int k = (this.k > 0) ? this.k : predicate.numPositive(); + int total = 0; + double score = 0.; + while(iter.valid() && total < k) { + int posthis = 0, cntthis = 0; + // positive or negative match? + do { + if(predicate.test(iter)) { + ++posthis; + } + ++cntthis; + iter.advance(); + } // Loop while tied: + while(iter.valid() && iter.tiedToPrevious()); + // Special tie computations only when we reach k. + if(total + cntthis > k) { + // p = posthis / cntthis chance of being positive + // n = (k-total) draws. + // expected value = n * p + score += posthis / (double) cntthis * (k - total); + total = k; + break; + } + score += posthis; + total += cntthis; + } + return score / total; + } + + /** + * Parameterization class. + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractParameterizer { + /** + * Option ID for the k parameter. + */ + public static final OptionID K_ID = new OptionID("precision.k", // + "k value for precision@k. Can be set to 0, to get R-precision, or the precision-recall-break-even-point."); + + /** + * K parameter + */ + int k; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + IntParameter kP = new IntParameter(K_ID) // + .setDefaultValue(0) // + .addConstraint(CommonConstraints.GREATER_EQUAL_ZERO_INT); + if(config.grab(kP)) { + k = kP.intValue(); + } + } + + @Override + protected PrecisionAtKEvaluation makeInstance() { + return k > 0 ? new PrecisionAtKEvaluation(k) : RPRECISION; + } + } +} |