/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.uci.jforests.eval.ranking;
import java.util.Arrays;
import edu.uci.jforests.sample.RankingSample;
import edu.uci.jforests.sample.Sample;
import edu.uci.jforests.util.ArraysUtil;
import edu.uci.jforests.util.ScoreBasedComparator;
import edu.uci.jforests.util.ScoreBasedComparator.TieBreaker;
import edu.uci.jforests.util.concurrency.BlockingThreadPoolExecutor;
import edu.uci.jforests.util.concurrency.TaskCollection;
import edu.uci.jforests.util.concurrency.TaskItem;
/**
* Precision at position k (P@k)
*/
/**
* @author Yasser Ganjisaffar
*/
public class PrecisionEval extends RankingEvaluationMetric {
private TaskCollection mapWorkers;
private int maxLevels;
double relevancyThreshold;
private int maxDocsPerQuery;
public PrecisionEval(int maxDocsPerQuery, int maxLevels, double relevancyThreshold) throws Exception {
super(true);
this.maxDocsPerQuery = maxDocsPerQuery;
this.maxLevels = maxLevels;
this.relevancyThreshold = relevancyThreshold;
int numWorkers = BlockingThreadPoolExecutor.getInstance().getMaximumPoolSize();
mapWorkers = new TaskCollection();
for (int i = 0; i < numWorkers; i++) {
mapWorkers.addTask(new PrecisionWorker());
}
}
private class PrecisionWorker extends TaskItem {
private int[] permutation;
private RankingSample sample;
private int beginIdx;
private int endIdx;
private double[] result;
private ScoreBasedComparator comparator;
public PrecisionWorker() {
permutation = new int[maxDocsPerQuery];
comparator = new ScoreBasedComparator();
result = new double[maxLevels];
}
public void init(RankingSample sample, double[] scores, int beginIdx, int endIdx, TieBreaker tieBreaker) {
this.sample = sample;
this.beginIdx = beginIdx;
this.endIdx = endIdx;
comparator.labels = sample.targets;
comparator.scores = scores;
comparator.tieBreaker = tieBreaker;
Arrays.fill(result, 0);
}
public double[] getResult() {
return result;
}
@Override
public void run() {
for (int q = beginIdx; q < endIdx; q++) {
int begin = sample.queryBoundaries[q];
int numDocs = sample.queryBoundaries[q + 1] - begin;
comparator.offset = begin;
for (int d = 0; d < numDocs; d++) {
permutation[d] = d;
}
ArraysUtil.sort(permutation, numDocs, comparator);
try {
int numRelevant = 0;
for (int pos = 0; pos < Math.min(numDocs, maxLevels); pos++) {
if (sample.targets[begin + permutation[pos]] >= relevancyThreshold) {
numRelevant++;
}
result[pos] += ((double) numRelevant / (pos + 1));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public double[] getPrecisions(double[] predictions, Sample sample, TieBreaker tieBreaker) throws Exception {
RankingSample rankingSample = (RankingSample) sample;
int chunkSize = 1 + (rankingSample.numQueries / mapWorkers.getSize());
int offset = 0;
int workerCount = 0;
for (int i = 0; i < mapWorkers.getSize() && offset < rankingSample.numQueries; i++) {
int endOffset = offset + Math.min(rankingSample.numQueries - offset, chunkSize);
PrecisionWorker worker = mapWorkers.getTask(i);
workerCount++;
worker.init(rankingSample, predictions, offset, endOffset, tieBreaker);
BlockingThreadPoolExecutor.getInstance().execute(worker);
offset += chunkSize;
}
BlockingThreadPoolExecutor.getInstance().await();
double[] result = new double[maxLevels];
for (int i = 0; i < workerCount; i++) {
double[] localResult = mapWorkers.getTask(i).getResult();
for (int p = 0; p < maxLevels; p++) {
result[p] += localResult[p];
}
}
for (int p = 0; p < maxLevels; p++) {
result[p] /= rankingSample.numQueries;
}
return result;
}
@Override
public double measure(double[] predictions, Sample sample) throws Exception {
return getPrecisions(predictions, sample, TieBreaker.ReverseLabels)[0];
}
@Override
public SwapScorer getSwapScorer(double[] targets, int[] boundaries,
int trunc, int[][] labelCounts) throws Exception {
throw new UnsupportedOperationException("Precision not supported for LambdaMART yet!");
}
@Override
public double[] measureByQuery(double[] predictions, Sample sample)
throws Exception {
throw new UnsupportedOperationException("Precision not supported yet!");
}
}
Ads help maintain this website.