Spaces:
Sleeping
Sleeping
| """ | |
| MEXAR - Retrieval Quality Metrics Module | |
| Provides Precision@k, Recall@k, Mean Reciprocal Rank (MRR), and nDCG@k algorithms. | |
| Evaluates retrieved document chunk sources against expected ground-truth document IDs. | |
| """ | |
| import math | |
| from typing import List, Any | |
| def precision_at_k(retrieved_doc_ids: List[str], relevant_doc_ids: List[str], k: int = 5) -> float: | |
| """Calculate Precision at position K.""" | |
| top_k = retrieved_doc_ids[:k] | |
| if not top_k: | |
| return 0.0 | |
| relevant_set = set(relevant_doc_ids or []) | |
| if not relevant_set: | |
| return 0.0 | |
| hits = sum(1 for d in top_k if any(rel in str(d) or str(d) in rel for rel in relevant_set)) | |
| return round(hits / len(top_k), 4) | |
| def recall_at_k(retrieved_doc_ids: List[str], relevant_doc_ids: List[str], k: int = 10) -> float: | |
| """Calculate Recall at position K.""" | |
| relevant_set = set(relevant_doc_ids or []) | |
| if not relevant_set: | |
| return 0.0 | |
| top_k = retrieved_doc_ids[:k] | |
| hits = sum(1 for rel in relevant_set if any(rel in str(d) or str(d) in rel for d in top_k)) | |
| return round(hits / len(relevant_set), 4) | |
| def mrr(retrieved_doc_ids: List[str], relevant_doc_ids: List[str]) -> float: | |
| """Calculate Mean Reciprocal Rank (MRR).""" | |
| relevant_set = set(relevant_doc_ids or []) | |
| if not relevant_set: | |
| return 0.0 | |
| for i, d in enumerate(retrieved_doc_ids, start=1): | |
| if any(rel in str(d) or str(d) in rel for rel in relevant_set): | |
| return round(1.0 / i, 4) | |
| return 0.0 | |
| def ndcg_at_k(retrieved_doc_ids: List[str], relevant_doc_ids: List[str], k: int = 10) -> float: | |
| """Calculate Normalized Discounted Cumulative Gain at position K (nDCG@k).""" | |
| relevant_set = set(relevant_doc_ids or []) | |
| if not relevant_set: | |
| return 0.0 | |
| def dcg(doc_ids: List[str]) -> float: | |
| score = 0.0 | |
| for i, d in enumerate(doc_ids[:k], start=1): | |
| is_rel = 1.0 if any(rel in str(d) or str(d) in rel for rel in relevant_set) else 0.0 | |
| score += is_rel / math.log2(i + 1) | |
| return score | |
| actual_dcg = dcg(retrieved_doc_ids) | |
| ideal_docs = list(relevant_set)[:k] | |
| ideal_dcg = dcg(ideal_docs) | |
| if ideal_dcg <= 0.0: | |
| return 0.0 | |
| return round(actual_dcg / ideal_dcg, 4) | |