use crate::eval::Evaluator;
use crate::ranklist::RankList;
#[derive(Debug, Clone)]
pub struct Precision {
limit: usize,
}
impl Precision {
pub fn new(limit: usize) -> Precision {
Precision { limit }
}
pub fn limit(&self) -> usize {
self.limit
}
pub fn set_limit(&mut self, limit: usize) {
self.limit = limit;
}
}
impl Evaluator for Precision {
fn evaluate_ranklist(&self, ranklist: &RankList) -> f32 {
let mut precision_score = 0.0f32;
for i in 0..self.limit {
match ranklist.get(i) {
Ok(dp) => {
if dp.get_label() == 1 {
precision_score += 1.0;
}
}
Err(_) => {
break;
}
}
}
match self.limit {
0 => 0.0,
_ => precision_score / self.limit as f32,
}
}
}
impl ToString for Precision {
fn to_string(&self) -> String {
format!("P@{}", self.limit)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::datapoint::DataPoint;
use crate::ranklist::RankList;
use crate::rl;
use crate::utils::random;
use approx::relative_eq;
#[test]
fn test_precision() {
let ranklist = rl!(
(0, 9, random::randomize_uniform(0f32, 100f32, 20), "doc1"),
(1, 9, random::randomize_uniform(0f32, 100f32, 20), "doc2"),
(1, 9, random::randomize_uniform(0f32, 100f32, 20), "doc3"),
(0, 9, random::randomize_uniform(0f32, 100f32, 20), "doc4"),
(1, 9, random::randomize_uniform(0f32, 100f32, 20), "doc5"),
(0, 9, random::randomize_uniform(0f32, 100f32, 20), "doc6")
);
let p1 = Precision::new(1);
let mut p3 = Precision::new(3);
let p5 = Precision::new(5);
let p1_score = p1.evaluate_ranklist(&ranklist);
let p3_score = p3.evaluate_ranklist(&ranklist);
let p5_score = p5.evaluate_ranklist(&ranklist);
assert!(relative_eq!(p1_score, 0.0, max_relative = 0.01f32));
assert!(relative_eq!(p3_score, 0.66, max_relative = 0.01f32));
assert!(relative_eq!(p5_score, 0.6, max_relative = 0.01f32));
assert_eq!(p1.limit(), 1);
assert_eq!(p3.limit(), 3);
assert_eq!(p5.limit(), 5);
p3.set_limit(2);
assert_eq!(p3.limit(), 2);
assert!(relative_eq!(
p3.evaluate_ranklist(&ranklist),
0.5,
max_relative = 0.01f32
));
}
}