feat: RRF and cross-segment max-score dedupe
This commit is contained in:
+54
-1
@@ -1 +1,54 @@
|
||||
// implemented in a later task
|
||||
use crate::model::Candidate;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Reciprocal Rank Fusion of two ranked lists of entry indices.
|
||||
/// Returns deduped entry indices ordered by fused score desc.
|
||||
pub fn rrf_merge(a: &[usize], b: &[usize], k: usize) -> Vec<usize> {
|
||||
let mut score: HashMap<usize, f64> = HashMap::new();
|
||||
for (rank, &id) in a.iter().enumerate() {
|
||||
*score.entry(id).or_default() += 1.0 / (k as f64 + rank as f64 + 1.0);
|
||||
}
|
||||
for (rank, &id) in b.iter().enumerate() {
|
||||
*score.entry(id).or_default() += 1.0 / (k as f64 + rank as f64 + 1.0);
|
||||
}
|
||||
let mut v: Vec<(usize, f64)> = score.into_iter().collect();
|
||||
v.sort_by(|x, y| y.1.partial_cmp(&x.1).unwrap());
|
||||
v.into_iter().map(|(id, _)| id).collect()
|
||||
}
|
||||
|
||||
/// Group candidates by normalized ICD code across all segments.
|
||||
/// Score = max over occurrences; retain all source segments and
|
||||
/// the matched phrase of the best-scoring occurrence.
|
||||
pub fn cross_segment_dedupe(cands: Vec<Candidate>) -> Vec<(DedupCandidate, f32)> {
|
||||
let mut by_code: HashMap<String, DedupCandidate> = HashMap::new();
|
||||
for c in cands {
|
||||
let s = c.rerank.or(c.semantic).or(c.lexical).unwrap_or(0.0);
|
||||
let e = by_code.entry(c.icd_code.clone()).or_insert_with(|| DedupCandidate {
|
||||
icd_code: c.icd_code.clone(),
|
||||
best_phrase: c.alpha_text.clone(),
|
||||
best_score: f32::MIN,
|
||||
source_segments: Vec::new(),
|
||||
});
|
||||
if !e.source_segments.contains(&c.segment_idx) {
|
||||
e.source_segments.push(c.segment_idx);
|
||||
}
|
||||
if s > e.best_score {
|
||||
e.best_score = s;
|
||||
e.best_phrase = c.alpha_text.clone();
|
||||
}
|
||||
}
|
||||
let mut out: Vec<(DedupCandidate, f32)> = by_code
|
||||
.into_values()
|
||||
.map(|mut d| { d.source_segments.sort(); let s = d.best_score; (d, s) })
|
||||
.collect();
|
||||
out.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
|
||||
out
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DedupCandidate {
|
||||
pub icd_code: String,
|
||||
pub best_phrase: String,
|
||||
pub best_score: f32,
|
||||
pub source_segments: Vec<usize>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user