Spaces:
Runtime error
Runtime error
github-actions[bot]
Sync backend to Hugging Face Space (commit: 39b5c807918249fa80049d49f4b6a74d6a0ed1fc)
6d86412 | """Generate realistic synthetic HCP seed data for Orsync Scenarist. | |
| Produces: | |
| - data/gold/doctors_unified.json (gold-layer records for GMM + Neo4j) | |
| Run: | |
| python -m scripts.generate_seed_data | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import math | |
| import os | |
| import random | |
| SEED = 42 | |
| NUM_DOCTORS = 200 | |
| INSTITUTIONS = [ | |
| {"name": "Massachusetts General Hospital", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "Johns Hopkins Hospital", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "Mayo Clinic", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "Cleveland Clinic", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "MD Anderson Cancer Center", "type": "cancer_center", "country": "US"}, | |
| {"name": "Memorial Sloan Kettering", "type": "cancer_center", "country": "US"}, | |
| {"name": "Dana-Farber Cancer Institute", "type": "cancer_center", "country": "US"}, | |
| {"name": "Stanford Medical Center", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "UCSF Medical Center", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "Cedars-Sinai Medical Center", "type": "medical_center", "country": "US"}, | |
| {"name": "Mount Sinai Hospital", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "University of Chicago Medicine", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "Duke University Hospital", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "NYU Langone Health", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "Brigham and Women's Hospital", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "University of Pennsylvania Health", "type": "academic_medical_center", "country": "US"}, | |
| {"name": "Charite - Universitaetsmedizin Berlin", "type": "academic_medical_center", "country": "DE"}, | |
| {"name": "Karolinska University Hospital", "type": "academic_medical_center", "country": "SE"}, | |
| {"name": "Royal Marsden Hospital", "type": "cancer_center", "country": "GB"}, | |
| {"name": "Institut Gustave Roussy", "type": "cancer_center", "country": "FR"}, | |
| ] | |
| TOPICS = [ | |
| "Immuno-Oncology", "Targeted Therapy", "CAR-T Cell Therapy", | |
| "Precision Medicine", "Biomarker Discovery", "Clinical Pharmacology", | |
| "Tumor Microenvironment", "Liquid Biopsy", "Checkpoint Inhibitors", | |
| "FGFR Signaling", "Kinase Inhibitors", "Combination Therapy", | |
| "Real-World Evidence", "Patient-Reported Outcomes", "Health Economics", | |
| "Drug Resistance Mechanisms", "Genomic Profiling", "Minimal Residual Disease", | |
| "Neoadjuvant Therapy", "Adjuvant Therapy", "Phase I/II Trial Design", | |
| "Adaptive Trial Design", "Rare Cancers", "Hematologic Malignancies", | |
| "Solid Tumors", "Gastrointestinal Oncology", "Thoracic Oncology", | |
| "Breast Cancer", "Prostate Cancer", "Renal Cell Carcinoma", | |
| "Hepatocellular Carcinoma", "Melanoma", "Head and Neck Cancer", | |
| "Pancreatic Cancer", "Ovarian Cancer", "Bladder Cancer", | |
| "Pharmacovigilance", "Regulatory Science", "Translational Research", | |
| "Artificial Intelligence in Oncology", | |
| ] | |
| # Archetype distributions (mean, std) for numeric fields per cluster | |
| ARCHETYPES = [ | |
| { | |
| "name": "Academic Skeptic", | |
| "h_index": (42, 12), "works_count": (180, 60), "cited_by_count": (5500, 2000), | |
| "i10_index": (110, 35), "years_active": (18, 5), | |
| "topic_count": (5, 2), "topic_bias": ["Precision Medicine", "Biomarker Discovery", "Clinical Pharmacology", "Genomic Profiling", "Translational Research"], | |
| }, | |
| { | |
| "name": "Commercial Adopter", | |
| "h_index": (28, 10), "works_count": (250, 90), "cited_by_count": (2000, 800), | |
| "i10_index": (65, 20), "years_active": (10, 4), | |
| "topic_count": (4, 2), "topic_bias": ["Targeted Therapy", "Kinase Inhibitors", "Combination Therapy", "Checkpoint Inhibitors", "Artificial Intelligence in Oncology"], | |
| }, | |
| { | |
| "name": "Guideline Loyalist", | |
| "h_index": (22, 8), "works_count": (90, 40), "cited_by_count": (1200, 500), | |
| "i10_index": (35, 15), "years_active": (14, 6), | |
| "topic_count": (3, 1), "topic_bias": ["Real-World Evidence", "Patient-Reported Outcomes", "Health Economics", "Pharmacovigilance", "Regulatory Science"], | |
| }, | |
| { | |
| "name": "Price-Sensitive Pragmatist", | |
| "h_index": (15, 7), "works_count": (60, 30), "cited_by_count": (500, 250), | |
| "i10_index": (20, 10), "years_active": (8, 4), | |
| "topic_count": (3, 1), "topic_bias": ["Health Economics", "Real-World Evidence", "Patient-Reported Outcomes", "Drug Resistance Mechanisms"], | |
| }, | |
| ] | |
| def _clamp(val: float, lo: float, hi: float) -> float: | |
| return max(lo, min(hi, val)) | |
| def generate_doctors(n: int, rng: random.Random) -> list[dict]: | |
| doctors = [] | |
| per_cluster = n // len(ARCHETYPES) | |
| for cluster_id, arch in enumerate(ARCHETYPES): | |
| for i in range(per_cluster): | |
| h_mean, h_std = arch["h_index"] | |
| wc_mean, wc_std = arch["works_count"] | |
| cb_mean, cb_std = arch["cited_by_count"] | |
| i10_mean, i10_std = arch["i10_index"] | |
| ya_mean, ya_std = arch["years_active"] | |
| tc_mean, tc_std = arch["topic_count"] | |
| h_index = int(_clamp(rng.gauss(h_mean, h_std), 1, 100)) | |
| works_count = int(_clamp(rng.gauss(wc_mean, wc_std), 5, 800)) | |
| cited_by_count = int(_clamp(rng.gauss(cb_mean, cb_std), 10, 20000)) | |
| i10_index = int(_clamp(rng.gauss(i10_mean, i10_std), 0, 300)) | |
| years_active = int(_clamp(rng.gauss(ya_mean, ya_std), 1, 40)) | |
| topic_count = int(_clamp(rng.gauss(tc_mean, tc_std), 1, 8)) | |
| institution = rng.choice(INSTITUTIONS) | |
| biased = rng.sample(arch["topic_bias"], min(topic_count, len(arch["topic_bias"]))) | |
| remaining = topic_count - len(biased) | |
| if remaining > 0: | |
| extras = [t for t in TOPICS if t not in biased] | |
| biased += rng.sample(extras, min(remaining, len(extras))) | |
| code_name = f"HCP-{cluster_id:02d}-{i:03d}" | |
| doctors.append({ | |
| "code_name": code_name, | |
| "source": "seed_synthetic", | |
| "cluster_id": cluster_id, | |
| "h_index": h_index, | |
| "works_count": works_count, | |
| "cited_by_count": cited_by_count, | |
| "i10_index": i10_index, | |
| "years_active": years_active, | |
| "institution": institution["name"], | |
| "institution_type": institution["type"], | |
| "institution_country": institution["country"], | |
| "topics": biased, | |
| }) | |
| remaining = n - len(doctors) | |
| for i in range(remaining): | |
| cluster_id = rng.randint(0, len(ARCHETYPES) - 1) | |
| arch = ARCHETYPES[cluster_id] | |
| h_mean, h_std = arch["h_index"] | |
| doctors.append({ | |
| "code_name": f"HCP-XX-{i:03d}", | |
| "source": "seed_synthetic", | |
| "cluster_id": cluster_id, | |
| "h_index": int(_clamp(rng.gauss(h_mean, h_std), 1, 100)), | |
| "works_count": int(_clamp(rng.gauss(arch["works_count"][0], arch["works_count"][1]), 5, 800)), | |
| "cited_by_count": int(_clamp(rng.gauss(arch["cited_by_count"][0], arch["cited_by_count"][1]), 10, 20000)), | |
| "i10_index": int(_clamp(rng.gauss(arch["i10_index"][0], arch["i10_index"][1]), 0, 300)), | |
| "years_active": int(_clamp(rng.gauss(arch["years_active"][0], arch["years_active"][1]), 1, 40)), | |
| "institution": rng.choice(INSTITUTIONS)["name"], | |
| "institution_type": rng.choice(INSTITUTIONS)["type"], | |
| "institution_country": rng.choice(INSTITUTIONS)["country"], | |
| "topics": rng.sample(TOPICS, rng.randint(1, 5)), | |
| }) | |
| return doctors | |
| def main(): | |
| rng = random.Random(SEED) | |
| doctors = generate_doctors(NUM_DOCTORS, rng) | |
| out_path = os.path.join(os.path.dirname(__file__), "..", "data", "gold", "doctors_unified.json") | |
| out_path = os.path.normpath(out_path) | |
| os.makedirs(os.path.dirname(out_path), exist_ok=True) | |
| with open(out_path, "w", encoding="utf-8") as f: | |
| json.dump(doctors, f, indent=2, ensure_ascii=False) | |
| print(f"Generated {len(doctors)} doctor records -> {out_path}") | |
| cluster_counts = {} | |
| for d in doctors: | |
| cid = d["cluster_id"] | |
| cluster_counts[cid] = cluster_counts.get(cid, 0) + 1 | |
| for cid, count in sorted(cluster_counts.items()): | |
| print(f" Cluster {cid} ({ARCHETYPES[cid]['name']}): {count} doctors") | |
| if __name__ == "__main__": | |
| main() | |