feat: seeded transcription-error injection + Recall@k
This commit is contained in:
+39
-1
@@ -1 +1,39 @@
|
|||||||
// implemented in a later task
|
use rand::rngs::StdRng;
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
|
|
||||||
|
/// Inject realistic transcription errors deterministically (seeded):
|
||||||
|
/// char drop, adjacent swap, umlaut flattening, digit transposition.
|
||||||
|
pub fn inject_errors(text: &str, rate: f64, seed: u64) -> String {
|
||||||
|
let mut rng = StdRng::seed_from_u64(seed);
|
||||||
|
let mut chars: Vec<char> = text.chars().collect();
|
||||||
|
let n = chars.len();
|
||||||
|
let mut i = 0;
|
||||||
|
while i < chars.len() {
|
||||||
|
if rng.gen::<f64>() < rate {
|
||||||
|
match rng.gen_range(0..4) {
|
||||||
|
0 => { chars.remove(i); continue; } // drop
|
||||||
|
1 => { if i + 1 < chars.len() { chars.swap(i, i + 1); } } // swap
|
||||||
|
2 => { // flatten umlaut
|
||||||
|
chars[i] = match chars[i] {
|
||||||
|
'ä' => 'a', 'ö' => 'o', 'ü' => 'u', 'ß' => 's',
|
||||||
|
other => other,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => { // digit transpose
|
||||||
|
if chars[i].is_ascii_digit() && i + 1 < chars.len()
|
||||||
|
&& chars[i + 1].is_ascii_digit() {
|
||||||
|
chars.swap(i, i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
let _ = n;
|
||||||
|
chars.into_iter().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 1.0 if `expected` appears in the first k predictions, else 0.0.
|
||||||
|
pub fn recall_at_k(predicted: &[String], expected: &str, k: usize) -> f64 {
|
||||||
|
if predicted.iter().take(k).any(|p| p == expected) { 1.0 } else { 0.0 }
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
use alpha_id::eval::{inject_errors, recall_at_k};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn injection_is_deterministic_for_seed() {
|
||||||
|
let a = inject_errors("Diabetes mellitus Typ 2", 0.3, 42);
|
||||||
|
let b = inject_errors("Diabetes mellitus Typ 2", 0.3, 42);
|
||||||
|
assert_eq!(a, b);
|
||||||
|
assert_ne!(a, "Diabetes mellitus Typ 2"); // some corruption at rate 0.3
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn recall_counts_hit_within_k() {
|
||||||
|
let predicted = vec!["E11.9".to_string(), "I10.90".to_string(), "J45.0".to_string()];
|
||||||
|
assert_eq!(recall_at_k(&predicted, "I10.90", 5), 1.0);
|
||||||
|
assert_eq!(recall_at_k(&predicted, "I10.90", 1), 0.0);
|
||||||
|
assert_eq!(recall_at_k(&predicted, "Z99.9", 5), 0.0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user