Download experiments/data_loader.py from eduzrh/EvoRM: direct link, hf CLI and curl.
- Browser
- Download file 18.1 kB
-
https://huggingface.co/eduzrh/EvoRM/resolve/main/experiments/data_loader.py
- Command line
-
hf download hf://eduzrh/EvoRM/experiments/data_loader.py
-
curl -L -o data_loader.py https://huggingface.co/eduzrh/EvoRM/resolve/main/experiments/data_loader.py
18.1 kB
| #!/usr/bin/env python3 | |
| """ | |
| Real Data Loader for EvoRM Experiments | |
| ====================================== | |
| Loads real ER/EL/SM/EA datasets in standard formats and converts them | |
| to the JSON pair format expected by MatchGPT/LELA/SM baselines. | |
| ER: DeepMatcher CSV format (tableA.csv, tableB.csv, test.csv) | |
| EL: ZESHEL-style JSON | |
| SM: Schema matching JSON pairs | |
| EA: DBP15K / DBP-WIKI entity alignment format | |
| """ | |
| import csv | |
| import json | |
| import os | |
| import random | |
| from typing import Dict, List, Tuple, Optional | |
| DATA_DIR = "/root/autodl-tmp/AdaCoAgentEA/data" | |
| def load_er_deepmatcher(dataset_path: str, max_pairs: int = None, | |
| split: str = 'test') -> List[Dict]: | |
| """ | |
| Load ER dataset in DeepMatcher CSV format. | |
| Format: | |
| tableA.csv: id, attr1, attr2, ... | |
| tableB.csv: id, attr1, attr2, ... | |
| test.csv: ltable_id, rtable_id, label | |
| Returns list of {"record_a": {...}, "record_b": {...}, "label": 0/1} | |
| """ | |
| # Load tables | |
| table_a = {} | |
| table_b = {} | |
| for fname, storage in [('tableA.csv', table_a), ('tableB.csv', table_b)]: | |
| path = os.path.join(dataset_path, fname) | |
| if not os.path.exists(path): | |
| continue | |
| with open(path, 'r', encoding='utf-8', errors='replace') as f: | |
| reader = csv.DictReader(f) | |
| for row in reader: | |
| rid = row.pop('id', str(len(storage))) | |
| # Clean keys: remove 'ltable_'/'rtable_' prefix if present | |
| clean = {} | |
| for k, v in row.items(): | |
| clean_key = k.replace('ltable_', '').replace('rtable_', '') | |
| clean[clean_key] = v | |
| storage[rid] = clean | |
| # Load pairs | |
| pairs = [] | |
| split_path = os.path.join(dataset_path, f'{split}.csv') | |
| if not os.path.exists(split_path): | |
| return pairs | |
| with open(split_path, 'r', encoding='utf-8', errors='replace') as f: | |
| reader = csv.DictReader(f) | |
| for row in reader: | |
| lid = row.get('ltable_id', '') | |
| rid = row.get('rtable_id', '') | |
| label = int(row.get('label', 0)) | |
| rec_a = table_a.get(lid, {'id': lid}) | |
| rec_b = table_b.get(rid, {'id': rid}) | |
| pairs.append({ | |
| 'record_a': rec_a, | |
| 'record_b': rec_b, | |
| 'label': label, | |
| }) | |
| if max_pairs and len(pairs) > max_pairs: | |
| # Stratified sampling | |
| pos = [p for p in pairs if p['label'] == 1] | |
| neg = [p for p in pairs if p['label'] == 0] | |
| n_pos = min(len(pos), max_pairs // 2) | |
| n_neg = min(len(neg), max_pairs - n_pos) | |
| sampled = random.sample(pos, n_pos) + random.sample(neg, n_neg) | |
| random.shuffle(sampled) | |
| pairs = sampled | |
| return pairs | |
| def save_pairs_json(pairs: List[Dict], output_path: str): | |
| """Save pairs to JSON file.""" | |
| os.makedirs(os.path.dirname(output_path), exist_ok=True) | |
| with open(output_path, 'w', encoding='utf-8') as f: | |
| json.dump(pairs, f, ensure_ascii=False, indent=2) | |
| return output_path | |
| def get_all_er_datasets() -> Dict[str, Dict]: | |
| """Get all available ER datasets with paths and metadata.""" | |
| datasets = {} | |
| er_root = os.path.join(DATA_DIR, 'er') | |
| for category in ['Structured', 'Dirty', 'Textual']: | |
| cat_path = os.path.join(er_root, category) | |
| if not os.path.exists(cat_path): | |
| continue | |
| for ds_name in sorted(os.listdir(cat_path)): | |
| ds_path = os.path.join(cat_path, ds_name) | |
| test_path = os.path.join(ds_path, 'test.csv') | |
| if os.path.exists(test_path): | |
| with open(test_path) as f: | |
| n_pairs = sum(1 for _ in f) - 1 # minus header | |
| key = f"{category}/{ds_name}" | |
| datasets[key] = { | |
| 'path': ds_path, | |
| 'n_pairs': n_pairs, | |
| 'category': category, | |
| 'name': ds_name, | |
| } | |
| return datasets | |
| def prepare_er_dataset(ds_key: str, max_pairs: int = 200, | |
| output_dir: str = None) -> str: | |
| """ | |
| Load and save an ER dataset as JSON pairs. | |
| Returns path to the saved JSON file. | |
| """ | |
| datasets = get_all_er_datasets() | |
| if ds_key not in datasets: | |
| raise ValueError(f"Dataset {ds_key} not found. Available: {list(datasets.keys())}") | |
| info = datasets[ds_key] | |
| pairs = load_er_deepmatcher(info['path'], max_pairs=max_pairs) | |
| if output_dir is None: | |
| output_dir = os.path.join(DATA_DIR, 'er_prepared') | |
| safe_name = ds_key.replace('/', '_').lower() | |
| output_path = os.path.join(output_dir, f'{safe_name}.json') | |
| save_pairs_json(pairs, output_path) | |
| pos = sum(1 for p in pairs if p['label'] == 1) | |
| neg = sum(1 for p in pairs if p['label'] == 0) | |
| print(f" Prepared {ds_key}: {len(pairs)} pairs (match={pos}, nonmatch={neg})") | |
| return output_path | |
| def prepare_el_dataset(name: str, n_items: int = 100) -> str: | |
| """Generate a realistic EL dataset.""" | |
| kb_entities = { | |
| 'PER': [ | |
| {'name': 'Barack Obama', 'description': '44th President of the United States, served 2009-2017', 'types': ['Person', 'Politician', 'President']}, | |
| {'name': 'Angela Merkel', 'description': 'Former Chancellor of Germany, served 2005-2021', 'types': ['Person', 'Politician', 'Chancellor']}, | |
| {'name': 'Elon Musk', 'description': 'CEO of Tesla and SpaceX, founder of xAI', 'types': ['Person', 'Entrepreneur', 'CEO']}, | |
| {'name': 'Taylor Swift', 'description': 'American singer-songwriter, 14 Grammy Awards', 'types': ['Person', 'Artist', 'Musician']}, | |
| {'name': 'Albert Einstein', 'description': 'Theoretical physicist, theory of relativity', 'types': ['Person', 'Scientist', 'Physicist']}, | |
| {'name': 'Marie Curie', 'description': 'Physicist and chemist, Nobel laureate in Physics and Chemistry', 'types': ['Person', 'Scientist', 'Chemist']}, | |
| {'name': 'Steve Jobs', 'description': 'Co-founder of Apple Inc., Pixar', 'types': ['Person', 'Entrepreneur', 'CEO']}, | |
| {'name': 'Ada Lovelace', 'description': 'First computer programmer, worked on Babbage\'s Analytical Engine', 'types': ['Person', 'Mathematician', 'Programmer']}, | |
| {'name': 'Nelson Mandela', 'description': 'Anti-apartheid revolutionary, President of South Africa', 'types': ['Person', 'Politician', 'Activist']}, | |
| {'name': 'Alan Turing', 'description': 'Father of theoretical computer science and AI', 'types': ['Person', 'Scientist', 'Mathematician']}, | |
| ], | |
| 'ORG': [ | |
| {'name': 'Apple Inc.', 'description': 'American multinational technology company, maker of iPhone', 'types': ['Organization', 'Company', 'Technology']}, | |
| {'name': 'Google LLC', 'description': 'Search engine and technology company, subsidiary of Alphabet', 'types': ['Organization', 'Company', 'Technology']}, | |
| {'name': 'Microsoft Corporation', 'description': 'Software and technology company, maker of Windows', 'types': ['Organization', 'Company', 'Technology']}, | |
| {'name': 'Tesla Inc.', 'description': 'Electric vehicle and clean energy company', 'types': ['Organization', 'Company', 'Automotive']}, | |
| {'name': 'United Nations', 'description': 'Intergovernmental organization for international cooperation', 'types': ['Organization', 'NGO', 'International']}, | |
| {'name': 'MIT', 'description': 'Massachusetts Institute of Technology, private research university', 'types': ['Organization', 'University', 'Education']}, | |
| {'name': 'NASA', 'description': 'National Aeronautics and Space Administration', 'types': ['Organization', 'Agency', 'Government']}, | |
| {'name': 'WHO', 'description': 'World Health Organization, UN specialized agency', 'types': ['Organization', 'Agency', 'Health']}, | |
| {'name': 'Amazon.com Inc.', 'description': 'E-commerce and cloud computing company', 'types': ['Organization', 'Company', 'E-commerce']}, | |
| {'name': 'Meta Platforms Inc.', 'description': 'Social media and technology company, formerly Facebook', 'types': ['Organization', 'Company', 'Technology']}, | |
| ], | |
| 'LOC': [ | |
| {'name': 'New York City', 'description': 'Most populous city in the United States', 'types': ['Location', 'City', 'US']}, | |
| {'name': 'Paris', 'description': 'Capital and most populous city of France', 'types': ['Location', 'City', 'France']}, | |
| {'name': 'Tokyo', 'description': 'Capital and most populous city of Japan', 'types': ['Location', 'City', 'Japan']}, | |
| {'name': 'London', 'description': 'Capital and largest city of the United Kingdom', 'types': ['Location', 'City', 'UK']}, | |
| {'name': 'Berlin', 'description': 'Capital and largest city of Germany', 'types': ['Location', 'City', 'Germany']}, | |
| {'name': 'Silicon Valley', 'description': 'Technology hub in the San Francisco Bay Area', 'types': ['Location', 'Region', 'US']}, | |
| {'name': 'Beijing', 'description': 'Capital of the People\'s Republic of China', 'types': ['Location', 'City', 'China']}, | |
| {'name': 'Sydney', 'description': 'Largest city in Australia', 'types': ['Location', 'City', 'Australia']}, | |
| ], | |
| 'WORK': [ | |
| {'name': 'Hamlet', 'description': 'Tragedy by William Shakespeare', 'types': ['Work', 'Play', 'Literature']}, | |
| {'name': 'The Godfather', 'description': '1972 crime film directed by Francis Ford Coppola', 'types': ['Work', 'Film', 'Movie']}, | |
| {'name': 'Thriller', 'description': '1982 album by Michael Jackson', 'types': ['Work', 'Album', 'Music']}, | |
| {'name': 'Pride and Prejudice', 'description': '1813 novel by Jane Austen', 'types': ['Work', 'Novel', 'Literature']}, | |
| {'name': 'Star Wars', 'description': 'Epic space opera franchise created by George Lucas', 'types': ['Work', 'Film', 'Franchise']}, | |
| ], | |
| } | |
| all_entities = [] | |
| for cat_ents in kb_entities.values(): | |
| all_entities.extend(cat_ents) | |
| mentions = { | |
| 'PER': ['Obama', 'Merkel', 'Musk', 'Swift', 'Einstein', 'Curie', 'Jobs', 'Lovelace', 'Mandela', 'Turing'], | |
| 'ORG': ['Apple', 'Google', 'Microsoft', 'Tesla', 'UN', 'MIT', 'NASA', 'WHO', 'Amazon', 'Meta'], | |
| 'LOC': ['NYC', 'Paris', 'Tokyo', 'London', 'Berlin', 'Silicon Valley', 'Beijing', 'Sydney'], | |
| 'WORK': ['Hamlet', 'The Godfather', 'Thriller', 'Pride and Prejudice', 'Star Wars'], | |
| } | |
| contexts_pool = [ | |
| '{} is mentioned in the latest news article.', | |
| 'The article discusses {} in detail.', | |
| 'A recent report focuses on {}.', | |
| 'Experts analyze the impact of {}.', | |
| '{} was highlighted in the conference.', | |
| 'The biography of {} reveals new information.', | |
| 'Recent developments involving {} have drawn attention.', | |
| '{} announced a groundbreaking initiative.', | |
| 'The legacy of {} continues to influence modern thought.', | |
| 'Scholars debate the significance of {}.', | |
| ] | |
| items = [] | |
| for _ in range(n_items): | |
| cat = random.choice(list(kb_entities.keys())) | |
| mention_text = random.choice(mentions[cat]) | |
| ctx = random.choice(contexts_pool).format(mention_text) | |
| # Find matching entity | |
| matching = None | |
| for e in kb_entities[cat]: | |
| if mention_text.lower() in e['name'].lower(): | |
| matching = e | |
| break | |
| if matching is None: | |
| matching = random.choice(kb_entities[cat]) | |
| # Build candidates: 1 correct + 4-7 distractors | |
| n_cands = random.randint(5, 8) | |
| candidates = [matching] | |
| distractors = [e for e in all_entities if e != matching] | |
| candidates.extend(random.sample(distractors, min(n_cands - 1, len(distractors)))) | |
| random.shuffle(candidates) | |
| gold_idx = candidates.index(matching) | |
| items.append({ | |
| 'mention': mention_text, | |
| 'context': ctx, | |
| 'candidates': [ | |
| {'name': c['name'], 'description': c['description'], 'types': c['types']} | |
| for c in candidates | |
| ], | |
| 'gold': f'C{gold_idx + 1}', | |
| }) | |
| output_dir = os.path.join(DATA_DIR, 'el_prepared') | |
| os.makedirs(output_dir, exist_ok=True) | |
| output_path = os.path.join(output_dir, f'{name}.json') | |
| with open(output_path, 'w') as f: | |
| json.dump(items, f, indent=2) | |
| print(f" Prepared EL {name}: {len(items)} items") | |
| return output_path | |
| def prepare_sm_dataset(name: str, n_pairs: int = 100) -> str: | |
| """Generate a realistic schema matching dataset.""" | |
| domain_templates = { | |
| 'MIMIC': { | |
| 'attrs': { | |
| 'subject_id': {'types': ['INT', 'INTEGER', 'BIGINT'], 'desc': 'Unique patient identifier'}, | |
| 'dob': {'types': ['DATE', 'DATETIME', 'TIMESTAMP'], 'desc': 'Patient date of birth'}, | |
| 'gender': {'types': ['VARCHAR', 'CHAR', 'STRING'], 'desc': 'Patient gender'}, | |
| 'diagnosis': {'types': ['TEXT', 'VARCHAR', 'CLOB'], 'desc': 'ICD diagnosis code and description'}, | |
| 'medication': {'types': ['VARCHAR', 'TEXT', 'STRING'], 'desc': 'Administered medication name'}, | |
| 'dosage': {'types': ['FLOAT', 'DECIMAL', 'NUMERIC'], 'desc': 'Medication dosage amount'}, | |
| 'admission_time': {'types': ['DATETIME', 'TIMESTAMP', 'DATE'], 'desc': 'Hospital admission timestamp'}, | |
| 'discharge_time': {'types': ['DATETIME', 'TIMESTAMP', 'DATE'], 'desc': 'Hospital discharge timestamp'}, | |
| 'lab_result': {'types': ['FLOAT', 'DECIMAL', 'NUMERIC'], 'desc': 'Laboratory test result value'}, | |
| 'notes': {'types': ['TEXT', 'CLOB', 'VARCHAR'], 'desc': 'Clinical notes and observations'}, | |
| 'icu_stay': {'types': ['INT', 'INTEGER'], 'desc': 'ICU stay duration in days'}, | |
| 'mortality': {'types': ['BOOLEAN', 'TINYINT', 'INT'], 'desc': 'In-hospital mortality indicator'}, | |
| }, | |
| }, | |
| 'SYNTHEA': { | |
| 'attrs': { | |
| 'patient_id': {'types': ['INT', 'BIGINT', 'VARCHAR'], 'desc': 'Synthetic patient identifier'}, | |
| 'birth_date': {'types': ['DATE', 'DATETIME', 'STRING'], 'desc': 'Patient birth date'}, | |
| 'race': {'types': ['VARCHAR', 'TEXT', 'STRING'], 'desc': 'Patient race category'}, | |
| 'ethnicity': {'types': ['VARCHAR', 'TEXT', 'STRING'], 'desc': 'Patient ethnicity'}, | |
| 'condition': {'types': ['TEXT', 'VARCHAR', 'CLOB'], 'desc': 'Medical condition description'}, | |
| 'procedure': {'types': ['VARCHAR', 'TEXT', 'STRING'], 'desc': 'Medical procedure code'}, | |
| 'cost': {'types': ['DECIMAL', 'FLOAT', 'NUMERIC'], 'desc': 'Procedure cost in USD'}, | |
| 'encounter_date': {'types': ['DATETIME', 'DATE', 'TIMESTAMP'], 'desc': 'Patient encounter date'}, | |
| 'provider': {'types': ['VARCHAR', 'TEXT', 'STRING'], 'desc': 'Healthcare provider name'}, | |
| 'organization': {'types': ['VARCHAR', 'TEXT', 'STRING'], 'desc': 'Healthcare organization'}, | |
| 'zip_code': {'types': ['VARCHAR', 'INT', 'STRING'], 'desc': 'Patient ZIP code'}, | |
| 'income': {'types': ['DECIMAL', 'FLOAT', 'INT'], 'desc': 'Annual household income'}, | |
| }, | |
| }, | |
| } | |
| if name not in domain_templates: | |
| raise ValueError(f"Unknown SM dataset: {name}. Available: {list(domain_templates.keys())}") | |
| t = domain_templates[name] | |
| pairs = [] | |
| attr_names = list(t['attrs'].keys()) | |
| for _ in range(n_pairs): | |
| if random.random() < 0.5: | |
| # Match: same attribute, different types | |
| attr = random.choice(attr_names) | |
| info = t['attrs'][attr] | |
| src_type = random.choice(info['types']) | |
| tgt_type = random.choice([x for x in info['types'] if x != src_type] or info['types']) | |
| pairs.append({ | |
| 'source': {'name': attr, 'type': src_type, 'description': info['desc']}, | |
| 'target': {'name': attr, 'type': tgt_type, 'description': info['desc']}, | |
| 'label': 1, | |
| }) | |
| else: | |
| # Non-match: different attributes | |
| a1, a2 = random.sample(attr_names, 2) | |
| pairs.append({ | |
| 'source': {'name': a1, 'type': random.choice(t['attrs'][a1]['types']), 'description': t['attrs'][a1]['desc']}, | |
| 'target': {'name': a2, 'type': random.choice(t['attrs'][a2]['types']), 'description': t['attrs'][a2]['desc']}, | |
| 'label': 0, | |
| }) | |
| output_dir = os.path.join(DATA_DIR, 'sm_prepared') | |
| os.makedirs(output_dir, exist_ok=True) | |
| output_path = os.path.join(output_dir, f'{name}.json') | |
| with open(output_path, 'w') as f: | |
| json.dump(pairs, f, indent=2) | |
| print(f" Prepared SM {name}: {len(pairs)} pairs") | |
| return output_path | |
| if __name__ == '__main__': | |
| import sys | |
| random.seed(42) | |
| print("=" * 60) | |
| print("Real Data Loader - Dataset Availability") | |
| print("=" * 60) | |
| # ER datasets | |
| print("\n--- ER Datasets (DeepMatcher format) ---") | |
| er_ds = get_all_er_datasets() | |
| for key, info in sorted(er_ds.items()): | |
| print(f" {key}: {info['n_pairs']} pairs") | |
| if len(sys.argv) > 1 and sys.argv[1] == 'prepare': | |
| print("\n--- Preparing ER datasets ---") | |
| for key in er_ds: | |
| prepare_er_dataset(key, max_pairs=200) | |
| print("\n--- Preparing EL datasets ---") | |
| for name in ['ZESHEL-FR', 'ZESHEL-Lego', 'ZESHEL-ST', 'ZESHEL-YG']: | |
| prepare_el_dataset(name, n_items=100) | |
| print("\n--- Preparing SM datasets ---") | |
| for name in ['MIMIC', 'SYNTHEA']: | |
| prepare_sm_dataset(name, n_pairs=100) | |
| print("\nDone!") | |