glam/scripts/review_batch11_matches.py
kempersc e5a532a8bc Add comprehensive tests for NLP institution extraction and RDF partnership integration
- Introduced `test_nlp_extractor.py` with unit tests for the InstitutionExtractor, covering various extraction patterns (ISIL, Wikidata, VIAF, city names) and ensuring proper classification of institutions (museum, library, archive).
- Added tests for extracted entities and result handling to validate the extraction process.
- Created `test_partnership_rdf_integration.py` to validate the end-to-end process of extracting partnerships from a conversation and exporting them to RDF format.
- Implemented tests for temporal properties in partnerships and ensured compliance with W3C Organization Ontology patterns.
- Verified that extracted partnerships are correctly linked with PROV-O provenance metadata.
2025-11-19 23:20:47 +01:00

135 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""
Manual Review of Batch 11 Query Results
========================================
Review and filter the automated matches to identify:
1. Valid matches (high confidence)
2. Questionable matches (needs verification)
3. False positives (clearly wrong)
"""
import json
def review_matches():
"""Review and categorize Batch 11 matches"""
with open('scripts/batch11_query_results.json', 'r', encoding='utf-8') as f:
data = json.load(f)
print("="*80)
print("BATCH 11 MATCH REVIEW")
print("="*80)
valid_matches = []
questionable_matches = []
false_positives = []
# Known false positive: Museo Di (Q112135646) - Virtual LGBT museum
MUSEO_DI = "Q112135646"
for match in data['matches']:
museum_name = match['museum']['name']
q_number = match['match']['q_number']
wd_name = match['match']['wikidata_name']
location = match['match']['location']
description = match['match']['description']
score = match['match']['match_score']
print(f"\n{'='*80}")
print(f"Target: {museum_name}")
print(f"Match: {wd_name} ({q_number})")
print(f"Location: {location}")
print(f"Description: {description}")
print(f"Score: {score:.2f}")
# Filter obvious false positives
if q_number == MUSEO_DI:
print("❌ FALSE POSITIVE: Virtual LGBT museum (incorrect match)")
false_positives.append(match)
elif "Zoológico" in wd_name or "zoo" in description.lower():
print("❌ FALSE POSITIVE: Zoo, not a museum")
false_positives.append(match)
# High confidence matches (score > 0.95 and location matches)
elif score > 0.95 and location and location.lower() in museum_name.lower():
print("✅ VALID MATCH: High confidence")
valid_matches.append(match)
# Exact name matches
elif museum_name.lower() in wd_name.lower() or wd_name.lower() in museum_name.lower():
if location and (match['museum']['city'].lower() in location.lower() or
match['museum']['region'].lower() in location.lower()):
print("✅ VALID MATCH: Name and location align")
valid_matches.append(match)
else:
print("⚠️ QUESTIONABLE: Name matches but location unclear")
questionable_matches.append(match)
# Location mismatch
elif location and location != match['museum']['city']:
print("⚠️ QUESTIONABLE: Location mismatch")
questionable_matches.append(match)
else:
print("⚠️ QUESTIONABLE: Needs manual verification")
questionable_matches.append(match)
# Summary
print("\n" + "="*80)
print("REVIEW SUMMARY")
print("="*80)
print(f"✅ Valid matches: {len(valid_matches)}")
print(f"⚠️ Questionable matches: {len(questionable_matches)}")
print(f"❌ False positives: {len(false_positives)}")
if valid_matches:
print("\n" + "-"*80)
print("VALID MATCHES (High Confidence):")
print("-"*80)
for match in valid_matches:
print(f"{match['museum']['name']}")
print(f"{match['match']['wikidata_name']} ({match['match']['q_number']})")
if questionable_matches:
print("\n" + "-"*80)
print("QUESTIONABLE MATCHES (Need Verification):")
print("-"*80)
for match in questionable_matches:
print(f"{match['museum']['name']}")
print(f"{match['match']['wikidata_name']} ({match['match']['q_number']})")
print(f" Location: {match['match']['location']} vs {match['museum']['city']}")
if false_positives:
print("\n" + "-"*80)
print("FALSE POSITIVES (Rejected):")
print("-"*80)
for match in false_positives:
print(f"{match['museum']['name']}")
print(f"{match['match']['wikidata_name']} ({match['match']['q_number']})")
# Save filtered results
filtered = {
'batch': 11,
'review_date': '2025-11-09',
'valid_matches': valid_matches,
'questionable_matches': questionable_matches,
'false_positives': false_positives,
'summary': {
'valid': len(valid_matches),
'questionable': len(questionable_matches),
'false_positives': len(false_positives),
'expected_coverage': f"{55 + len(valid_matches)}/90",
'expected_coverage_percent': f"{((55 + len(valid_matches))/90*100):.1f}%"
}
}
with open('scripts/batch11_reviewed_matches.json', 'w', encoding='utf-8') as f:
json.dump(filtered, f, indent=2, ensure_ascii=False)
print(f"\n💾 Filtered results saved to: scripts/batch11_reviewed_matches.json")
print(f"\n📊 Conservative coverage estimate: {55 + len(valid_matches)}/90 = {((55 + len(valid_matches))/90*100):.1f}%")
if __name__ == "__main__":
review_matches()