shawnnesser/Healthcare-Data-Generator

GitHub: shawnnesser/Healthcare-Data-Generator

一款专为 Microsoft Fabric 设计的合成医疗数据生成器,通过引入天气、季节性模式和专科差异,生成逼真的无隐私风险医院运营数据,用于测试分析管道和仪表板。

Stars: 0 | Forks: 1

# 医疗保健数据生成器 一个复杂的合成医疗保健数据生成系统,用于创建逼真的医院就诊、住院和运营数据,具备高级季节性模式、天气集成和占用率跟踪功能。该工具旨在用于测试分析管道、医疗保健仪表板和数据工程工作流,而无需真实的患者数据。 ## 快速入门(适用于 LLM 和自动化代理) ``` # 克隆 git clone https://github.com/shawnnesser/Healthcare-Data-Generator.git cd Healthcare-Data-Generator # 创建虚拟环境并安装 python -m venv .venv # Windows: .venv\Scripts\activate | macOS/Linux: source .venv/bin/activate pip install -r requirements.txt # 配置连接(选择一种方法) # 选项 A — .env 文件(推荐): cp .env.example .env # 编辑 .env 并将 CONNECTION_STRING 设置为 URL 编码的 ODBC 字符串。 # 选项 B — 环境变量: # export CONNECTION_STRING="Driver%3D%7BODBC+Driver+18+for+SQL+Server%7D%3B..." # 选项 C — 无数据库(仅 Parquet 导出,无需连接): python src/main.py --export-parquet # 运行 python src/main.py # incremental: generate today's data python src/main.py --rebuild-start 2025-01-01 # full rebuild: 2025-01-01 → today python src/main.py --export-parquet # export to data/*.parquet (no DB) ``` **代理需要了解的关键文件:** | 文件 | 用途 | |------|---------| | `src/main.py` | 入口点 —— 所有 CLI 标志均在此定义 | | `src/config.py` | 从环境变量 / `.env` / `src/config_local.py` 读取 `CONNECTION_STRING` | | `.env.example` | 连接字符串模板(复制到 `.env`) | | `src/config_local.py` | 替代本地配置覆盖(gitignored) | | `requirements.txt` | Python 依赖项 | ## 概述 医疗保健数据生成器生成涵盖以下内容的多表医疗保健数据集: - **患者人口统计与病史**:包含合成个人身份标识和保险信息的患者记录 - **医院运营**:医院床位库存、科室级床位分配(包括基于医院规模的 ER 激增容量) - **临床就诊**:具有逼真时间模式的 ED 就诊、访问和住院 - **住院与占用率**:完整的住院/出院跟踪,用于精确计算床位占用率 - **临床数据**:手术、诊断、药物、化验和账单记录 - **时间维度**:具有完整公历和财年日历的日期维度表 - **环境背景**:来自历史数据(2025-01-01 起)的天气集成,影响疾病模式(流感、跌倒) - **医院专科化**:多专科医院系统,具有逼真的住院率、诊断路由以及按医院类型的季节性差异 ### 关键特性 #### 🏥 **医院专科化系统** ⭐ 新功能 具有特定专科行为的逼真医院类型: - **综合医院**(5 家医院):全方位服务 ED,20% 住院率,混合季节性模式 - 专科:创伤、内科、普通外科、精神科、妇产科 - 季节性差异:1 月/12 月高峰(+12% 至 +18%),7 月低谷(-10%) - **心脏专科研究所**(1 家医院):专注于心脏病学,72% 住院率 - 主要诊断:急性冠脉综合征 (28%),心力衰竭 (22%),心律失常 (18%) - **关键模式**:冬季 ACS 激增(1 月比 7 月 +38%) - 住院时间:清晨高峰(35% 在 6–10am) - **无急诊科** —— 急诊通过综合医院路由然后转院 - 付款人组合:Medicare 45%,商保 40%(老年心脏病患者群体) - **儿科儿童医院**(1 家医院):儿科专科,12% 住院率 - 主要诊断:上呼吸道感染 (22%),中耳炎 (18%),哮喘 (12%),骨折 (15%) - 季节性模式:冬季呼吸道高峰(1 月比 7 月 +35%) - 住院时间:全天分布(8–10am,2–4pm,6–9pm 高峰) - 急诊护理机构(24/7 但夜间量较低) - 付款人组合:Medicaid 52%,商保 35%(儿科群体) - **癌症中心**(1 家医院):肿瘤科/血液科,96% 住院率(最高) - 主要诊断:发热性中性粒细胞减少症 (22%),感染/脓毒症 (20%),急性白血病 (18%) - 季节性模式:稳定 ±6%(以计划治疗为主) - 住院时间:集中在工作时间(70% 在 8am–5pm 计划,30% 夜间急诊) - 平均住院天数 (LOS):7.4 天(最长) - **无急诊科** —— 来自肿瘤科诊所的直接住院 - **康复中心**(1 家医院):急性后期护理,85% 住院率 - 患者组合:骨科术后 (35%),中风康复 (25%),心脏康复 (15%) - 季节性模式:春季/秋季高峰(3 月/4 月/10 月 +10%,7 月 -8%) - 住院时间:清晨出院转院(60% 在 7–9am) - 平均住院天数 (LOS):21 天(由于康复重点而最长) - **非 ED** —— 仅限医生转诊,住院时间 7am–5pm - **专科诊断中心**(1 家医院):仅影像/化验 - 放射科、病理科、实验室服务 - 仅限工作时间(8am–5pm) - 无 ED,无住院 **特定医院的月度季节性:** | 月份 | 儿科 | 心脏 | 癌症 | 综合 | 康复 | |-------|-----------|---------|--------|---------|-------| | **1 月** | **+35%** | **+38%** | 5% | +12% | 4% | | **2 月** | **+28%** | **+32%** | 3% | +8% | 2% | | **7 月** | **-25%** | **-27%** | -6% | -10% | **-8%** | | **10 月** | -1% | -2% | 2% | 0% | **+12%** ⬆ 高峰 | | **12 月** | **+26%** | **+28%** | 6% | **+18%** | 0% | **对领导层分析的影响:** - 1 月:儿科 ED 激增 +35%(流感/RSV),心脏 ICU 占用率达 92–96% - 7 月:儿科医院 -25%(夏季回落),全系统手术计划减少 - 10 月:康复中心 +12%(术后恢复季节) - 周五 2–6pm:综合医院的 ER 占用率为 93–95%(分流风险) #### 📊 **ER 床位占用压力建模** ⭐ 新功能 具有周几差异的逼真每小时 ER 占用模式: - **小时基线**:4am 占用率 38%(最低) → 2pm 占用率 89%(高峰) = 2.3 倍范围 - **周几乘数**: - **周五 2–6pm:93–95% 占用率**(周末择期激增,创伤峰值) 🔴 危急 - 周一至周四上午:75–88% 占用率 - 周日 4am:36–40% 占用率(择期住院的行政机会) - **运营洞察**: - 周五 2–6pm 显示占用率接近分流阈值 - 清晨(午夜–6am)显示 50% 空床(是患者转院/住院的理想时机) - 周一激增(92% 占用率)来自周末积压 #### 📋 **医院就诊量变化** ⭐ 新功能 医院间就诊量的逼真差异: - **基于床位数的分布**:大医院按比例生成更多就诊 - 750 张床位医院:约 45-65 次就诊/天 - 350 张床位医院:约 20-35 次就诊/天 - 120 张床位医院:约 7-15 次就诊/天 - **随机变异 (15-30%)**:每家医院的日就诊量逼真波动 - 反映了现实世界中患者到达的波动 - 防止所有医院出现不真实的均匀分布 - **科室加权分配**:根据逼真的需求将就诊分配给科室 - 急诊科:患者量高 2.5 倍 - 内科:1.8 倍 - 专科服务:乘数较低 #### 💳 **付款人组合逼真度** ⭐ 新功能 根据医院专科和患者人口统计为每次就诊分配付款人类型: - **整体市场份额**: - Medicare:36% - 商保:35% - Medicaid:20% - 无保险:5% - 其他:4% - **专科调整**: - 儿科医院:Medicaid 52%,商保 35% - 心脏病医院:Medicare 45%,商保 40% - 康复中心:Medicare 50%(急性后期人群) - 综合医院:标准组合 #### 📚 **完整的 ICD-10 文档** ⭐ 新功能 所有 39 个 ICD-10 代码均包含完整的临床描述和逼真的主诉: - **示例诊断**: - `I10`: "原发性高血压" - 头痛,头晕 - `J18.9`: "肺炎,病原体未特指" - 发烧,咳嗽,呼吸急促 - `I63.9`: "脑梗死,未特指(缺血性卒中)" - 突然无力,言语不清 - `A41.9`: "脓毒症,病原体未特指" - 发烧,低血压,精神状态改变 - 支持逼真的就诊记录和主诉生成 - 支持准确的诊断到治疗映射 #### 📋 **面向医院领导的数据驱动建议** ⭐ 新功能 生成的数据揭示了需要采取行动的逼真运营挑战: **问题 1:冬季儿科 ED 过度拥挤** - 模式:1 月就诊量比 7 月基线高 +35% - 根本原因:流感/RSV 季节(CDC NHAMCS 数据) - 行动:10 月至 2 月招聘 3–4 名临时注册护士;实施流感疫苗宣传活动;扩展快速通道 - 预期 ROI:ED 等候时间 ↓ 50%(4 小时 → 2 小时) **问题 2:心脏研究所清晨容量危机** - 模式:1 月 +38% 就诊;工作日 8–10am 占用率 94–96% - 根本原因:ACS(急性冠脉综合征)昼夜高峰 + 冬季激增 - 行动:开放 6am ICU 溢出病房;导管室延长时间 7am–7pm(而非 9am–5pm);减少 6am–12pm 的择期手术 - 预期 ROI:ACS 从进门到导管时间持续 <120 分钟 **问题 3:综合医院周五 ER 分流风险** - 模式:周五 2–6pm 占用率 93–95%(对比周日–周四的 75–80%) - 根本原因:周五下午择期手术出院;创伤峰值;周末人员配置准备 - 行动:周五上午 10 点前让所有稳定的住院患者出院;下午 1 点–6 点阻断择期住院;激活周末人员 - 预期 ROI:分流激活 <2 次/月(对比当前的 4–6 次/月) **问题 4:康复中心 4 月瓶颈** - 模式:4 月住院 +10%(春季手术季节);清晨出院转院激增 - 根本原因:术后康复转诊季节 - 行动:招聘临时 PT/OT 人员;预先计划出院转诊;安排早期医院出院(6am 而非中午) - 预期 ROI:医院到康复中心转院时间 ↓ 25%(72 小时 → 48 小时);减少床位阻塞 **问题 5:癌症中心过夜化疗毒性** - 模式:5% 的住院发生在午夜–8am;20%+ 发热性中性粒细胞减少症 - 根本原因:化疗副作用在输注后 12–36 小时达到高峰 - 行动:下午 6 点–上午 6 点待命肿瘤分诊护士;体温 >100.4°F 的快速住院方案;晚上 8 点–早上 8 点预留 3–5 张床位 - 预期 ROI:发热性中性粒细胞减少症住院 <2 小时(对比 4–6 小时);降低脓毒症死亡率 **综合报告:** 请参阅 [HOSPITAL_SEASONALITY_AND_OCCUPANCY_ANALYSIS.md](HOSPITAL_SEASONALITY_AND_OCCUPANCY_ANALYSIS.md) 了解: - 按专科划分的完整月度差异表 - 住院率、LOS 分布、住院时间模式 - ER 占用率热力图(按小时 × 周几) - 7 项附带引用的运营建议(CDC, AHA, NIH, NCI, APTA, ACEP) #### 🌡️ 真实天气集成 - 从 **Open-Meteo API** 获取历史天气数据(免费,无需 API 密钥) - 天气状况映射到医疗保健影响(雨/雪 → 跌倒增加,寒冷 → 流感激增) - 批量生成期间应用按日期天气(不仅仅是今天的天气) - 内存缓存 + JSON 文件持久化,以避免重复的 API 调用 - 可通过 CLI 标志按需清除缓存 #### 📅 全面的日期维度 - 完整的时间覆盖范围(398 天:2025-01-01 → 2026-02-02) - 所有标准日历列:公历和财年日历 - 周几、季度ISO 周、年周数、年日数、财月跟踪 - 支持复杂的时间查询和汇总 #### 🏥 逼真的医院结构 - 可配置的医院数量(默认:跨大/中/小层级的 10 家医院) - **逼真的科室床位分配**:基于证据的科室类型百分比: - **急诊:6%**(750 张床位医院中有 45 张 ER 床位,而非 300+ 张) - 内科:35%(最大的住院服务) - 外科:25%(外科病房) - 专科科室:10-20%(心脏病学、骨科等) - 门诊服务:3-5%(放射科、病理科) - 科室级床位计数,精确汇总到医院总数(无重复计算或浪费) - **科室需求乘数**:逼真的患者量分布 - 急诊:2.5 倍(量最大) - 内科:1.8 倍 - 放射科:1.9 倍(高影像需求) - 姑息治疗:0.6 倍(专科,量较低) - 具有适当 6% 床位分配的综合医院急诊科 - 用于实时 ER 和患者占用率跟踪的视图 #### 📊 季节性乘数(基于证据) 跨三个维度应用,以实现逼真的时间变化: - **小时乘数**(24 个值:0.43–1.52) - ED 在下午/晚上达到高峰(16:00–20:00 时为 1.4–1.52) - 在 03:00–05:00 达到低谷(0.43–0.51) - 基于 NHS A&E 和 NHAMCS (CDC) 数据 - *来源:NHS A&E 就诊数据,NHAMCS 国家医院门诊医疗护理调查* - **周几乘数**(7 个值:0.96–1.06) - 周一激增 (1.06) 来自基层医疗积压 - 周中回落 (0.96–0.98),积压清除 - 周末升高 (1.01–1.03),因基层医疗关闭 - *来源:NHS 运营数据,NHAMCS 季节性模式* - **月度乘数**(12 个值:0.85–1.12) - 冬季高峰(1 月/2 月/12 月:1.08–1.12)- 流感、呼吸道、心脏事件 - 夏季回落(7 月:0.85)- 急性表现较少 - 春季/秋季过渡期(0.95–1.02) - *来源:CDC FluVax 流感季节跟踪,NHS A&E 季节性变化* - **手术季节性**(11 项手术,PMC 来源) - **心脏导管术**:1.15(冬季心脏事件)→ 0.92(夏季) - **阑尾切除术**:1.10(夏季手术激增)→ 0.95(冬季) - **结肠镜检查**:0.95(冬季回落)→ 1.05(夏季筛查) - **搭桥手术**:1.18(冬季 ACS)→ 0.88(夏季) - **血管成形术**:1.12(冬季 ACS)→ 0.90(夏季) - **子宫切除术**:1.02(夏季择期)→ 0.98(冬季) - **膝关节置换术**:1.08(夏季,运动季后)→ 0.94(冬季) - **髋关节置换术**:1.05(夏季预防跌倒热潮)→ 0.98(冬季) - **阑尾切除**:1.10(夏季)→ 0.92(冬季) - **胆囊切除**:1.03(夏季)→ 0.99(冬季) - **疝修补术**:1.04(夏季)→ 0.97(冬季) - *来源:PMC 手术季节性研究,NHS 择期手术安排模式* #### 👥 住院与占用率跟踪 - 具有 admit_datetime 和 discharge_datetime 的完整住院/出院工作流 - 特定医院的住院率:儿科 12%,心脏 72%,癌症 96%,综合 20%,康复 85% - **适合专科的住院时间**: - 心脏:35% 的住院在 6–10am(清晨 ACS 高峰) - 儿科:分布(上午、下午、晚上高峰) - 癌症:70% 在 8am–5pm(计划化疗管理),30% 夜间急诊 - 康复:60% 在 7–9am(从急性护理转出的出院) - 综合:40% 在 2–6pm(ED 下午高峰) - **特定专科的住院天数**(带有 ±30% 差异): - 儿科:平均 1.2 天 - 心脏:平均 3.5 天 - 癌症:平均 7.4 天 - 康复:平均 21 天(最长) - 综合:平均 3.8 天 - 50% 在 0–7 天内出院;50% 正在住院(discharge_datetime = NULL) - 可通过 SQL 视图精确计算床位占用率 - 支持容量规划和住院天数分析 #### 🗄️ 数据库 Schema 所有表都包含具有无冲突偏移逻辑的显式 ID: | 表 | 用途 | 关键列 | |-------|---------|-------------| | `date_dim` | 时间参考 | date, yyyy, mm, dd, day_of_week, is_weekend, fiscal_month, iso_week | | `hospitals` | 医院主数据 | hospital_id, hospital_name, bed_count, city, state | | `departments` | 运营单元 | department_id, department_name, hospital_id, specialty_type | | `hospital_department_beds` | 床位分配 | hospital_id, department_id, bed_count | | `patients` | 患者人口统计 | patient_id, first_name, last_name, dob, gender, address, insurance_id | | `doctors` | 临床人员 | doctor_id, first_name, last_name, specialty | | `encounters` | ED 就诊/住院 | encounter_id, patient_id, hospital_id, department_id, doctor_id, encounter_date, payer_type, chief_complaint | | `admissions` | 住院记录 | admission_id, encounter_id, hospital_id, patient_id, admit_datetime, discharge_datetime | | `procedures` | 外科/临床手术 | procedure_id, hospital_id, encounter_id, procedure_name, procedure_date | | `diagnoses` | 关联到就诊的 ICD 代码 | diagnosis_id, encounter_id, diagnosis_code, diagnosis_name | | `medications` | 处方 | medication_id, encounter_id, medication_name, dosage | | `labs` | 化验结果 | lab_id, encounter_id, lab_name, result, normal_range | | `insurance` | 保险主数据 | insurance_id, company_name, plan_name, copay | | `billing` | 费用与账单记录 | billing_id, encounter_id, amount, service_type | | `run_logs` | 审计跟踪 | run_id, run_date, records_inserted, duration_seconds | #### 📊 SQL 视图 - **`vw_current_er_beds`**:按医院划分的实时 ER 床位可用性 - 显示每个 ED 的可用、占用和总床位数 - 范围限定为 department_type='Emergency' - **`vw_current_patient_beds`**:所有床位的实时患者占用率 - 从 `admissions` 表计算占用率(admit_datetime ≤ 今天 AND discharge_datetime IS NULL OR > 今天) - 支持容量规划和溢出检测 #### ✅ 补缺机制 - 检测应用是否已超过 24 小时未运行 - 自动从上次 run_log 到今天回填缺失的日期 - 对所有补缺日期应用季节性和天气 ## 安装 ### 前置条件 - Python 3.8+ - ODBC Driver 18 for SQL Server(数据库模式需要;`--export-parquet` 不需要) - SQL Server、Azure SQL 或 Microsoft Fabric SQL 数据库(可选 —— 没有 Parquet 导出也可以工作) ### 设置 1. **克隆并导航到项目**: git clone https://github.com/shawnnesser/Healthcare-Data-Generator.git cd Healthcare-Data-Generator 2. **创建虚拟环境**: python -m venv .venv # Windows .venv\Scripts\activate # macOS / Linux source .venv/bin/activate 3. **安装依赖项**: pip install -r requirements.txt 4. **配置数据库连接**(选择一种): **选项 A —— `.env` 文件(推荐)**: cp .env.example .env 编辑 `.env` 并将 `CONNECTION_STRING` 设置为 **URL 编码的** ODBC 连接字符串。 有关格式示例,请参阅 `.env.example`。 **选项 B —— `src/config_local.py`**: # src/config_local.py (此文件已被 gitignored) import urllib.parse CONN_ODBC = ( "Driver={ODBC Driver 18 for SQL Server};" "Server=your-server.database.fabric.microsoft.com,1433;" "Database=your-database;" "Encrypt=yes;TrustServerCertificate=no;Authentication=ActiveDirectoryInteractive" ) CONNECTION_STRING = urllib.parse.quote_plus(CONN_ODBC) **选项 C —— 环境变量**: export CONNECTION_STRING="Driver%3D%7BODBC+Driver+18+for+SQL+Server%7D%3BServer%3D..." **选项 D —— 无数据库(仅 Parquet)**: 完全跳过此步骤并使用 `--export-parquet`。 5. **运行生成器**: python src/main.py # 每日增量 python src/main.py --rebuild-start 2025-01-01 # 完整历史重建 python src/main.py --export-parquet # 导出到 data/*.parquet ## 使用方法 ### 命令行界面 #### 默认行为(每日增量) ``` python src/main.py ``` - 运行一次,插入今天的数据 - 应用今天的天气和季节性 - 如果上次运行超过 24 小时,自动回填所有缺失的日期 - 缓存在启动时加载,在退出时保存 #### 重建数据库(完整历史) ``` python src/main.py --rebuild-start 2025-01-01 ``` - 截断所有表 - 从指定的 start_date 到今天重新生成所有数据 - 应用按日期的天气和季节性 - 填充所有 13 个核心表 - 创建/重新创建 SQL 视图 - 生成 399 天的数据(2025-01-01 → 今天) - 通过逼真的时间变化演示完整的数据集功能 #### 持续生成(每小时) ``` python src/main.py --frequency hourly ``` - 每小时运行(适用于 `cron` 或任务计划程序) - 维护连续的数据流 - 对于实时分析仪表板很有用 #### 无缓存生成一次 ``` python src/main.py --clear-weather-cache ``` - 在运行前清除天气缓存 - 强制对所有日期进行新的 API 调用 - 对于缓存验证或调试很有用 #### 导出到 Parquet ``` python src/main.py --export-parquet ``` - 将生成的数据导出到 `output/` 目录(parquet 格式) - 每个表单独一个文件 - 对于 ETL 集成或填充数据湖很有用 #### 组合标志 ``` python src/main.py --rebuild-start 2025-01-01 --export-parquet --frequency daily ``` ### 示例工作流 #### 场景 1:用历史数据填充仪表板 ``` python src/main.py --rebuild-start 2025-01-01 # 等待约 2–5 分钟 # 仪表板查询 `vw_current_patient_beds`、`vw_current_er_beds`、按月统计的程序等。 # 所有历史数据现已在数据库中,并带有真实的季节性 ``` #### 场景 2:持续测试管道 ``` # 初始设置(完整历史) python src/main.py --rebuild-start 2025-01-01 # 然后每日刷新(07:00 的 cron job) 0 7 * * * cd /path/to/project && /usr/bin/python3 src/main.py --frequency daily ``` #### 场景 3:验证缓存持久性 ``` # 首次运行:构建缓存 python src/main.py --rebuild-start 2025-01-01 # 成功完成后缓存保存到 weather_cache.json # 第二次运行:使用缓存(即时,无 API 调用) python src/main.py # 清除缓存以进行新的 API 调用 python src/main.py --clear-weather-cache --rebuild-start 2025-01-01 ``` ## 数据流与架构 ### 生成管道(重建模式) ``` Input: start_date (2025-01-01), end_date (today) ↓ [Loop: day-by-day from start_date → end_date] ↓ For each day: 0. Get month for specialty multiplier lookup 1. Fetch weather for that date (cached if available) 2. [NEW] For each hospital (10 total): a. Get specialty-adjusted encounter count via get_hospital_monthly_encounters() - Pediatric: ±35% monthly variance - Cardiac: ±38% monthly variance - Cancer: ±6% monthly variance - General: ±18% monthly variance - Rehab: ±12% monthly variance b. Generate encounters scaled by specialty + month multiplier c. Route diagnoses via get_specialty_diagnoses() - Children's: URI, otitis, asthma, fractures - Heart Institute: ACS, heart failure, arrhythmia - Cancer Center: febrile neutropenia, acute leukemia, lymphoma - General: trauma, infection, surgery, psychiatry d. Apply specialty-appropriate admission rate (12% to 96%) e. Generate admission times via get_admission_times_by_specialty() - Cardiac: 35% early-morning peak - Rehab: 60% 7–9am transfer window - Cancer: 70% business hours f. Apply specialty-specific LOS (1.2 to 21 days) 3. Generate patients (if new) 4. Generate doctors (if new) 5. Generate procedures (procedure name weighted by PROCEDURE_SEASONALITY + monthly multiplier) 6. Generate medications, labs, insurance, billing records 7. Offset all IDs to match DB state 8. Insert data (replace on day 1, append thereafter) 9. Advance ID counters ↓ [After all days] ↓ Create/recreate SQL views (ER beds, patient beds) ↓ Save weather cache to JSON ↓ Output: All tables populated with realistic hospital specialization, views ready, cache persisted ``` ### 季节性应用 ``` For each encounter/procedure on date D: 1. Get hourly multiplier (if applicable): HOURLY_MULTIPLIERS[hour_of_day] 2. Get day-of-week multiplier: DAY_OF_WEEK_MULTIPLIERS[dow] 3. Get monthly multiplier: MONTHLY_MULTIPLIERS[month] 4. For procedures: apply PROCEDURE_SEASONALITY[procedure_name] 5. Combine: combined_weight = base_weight * monthly * (day_of_week * hourly if hourly else day_of_week) 6. Normalize weights across all procedures: sum = 1.0 7. Select procedure via random.choices(procedures, weights=normalized) ``` ### 天气集成 ``` For date D: 1. Check weather_cache (in-memory dict or JSON file) 2. If miss: call Open-Meteo archive API - Endpoint: https://archive-api.open-meteo.com/v1/archive?latitude=XX&longitude=YY&date=YYYY-MM-DD - Parse response: get weather_code (WMO) - Map code to condition: (0–1: clear, 2–3: cloudy, 45–48: fog, 51–67: drizzle/rain, 71–86: snow, 80–82: showers, 85–86: heavy snow showers) 3. Store in cache (in-memory + JSON) 4. Apply WEATHER_IMPACT multipliers: - flu_multiplier = 1.2 if (rain/snow/fog) else 1.0 - fall_multiplier = 1.4 if (rain/snow) else 1.0 5. Scale diagnosis generation: increase flu/fall diagnoses on bad weather ``` ### 增量更新(非重建) ``` Input: (no date range specified) ↓ Check last run in run_logs: - If run_date is today: skip (already run) - If run_date < today - 1 day: detect catch-up needed ↓ [For each missing day: loop back to day-by-day generation] ↓ Generate today's data: - Fetch weather for today - Apply today's seasonality - Generate encounter/patient/procedure/admission records - Offset IDs - Insert (append) ↓ Save weather cache ↓ Output: Today's data added, views updated ``` ## 配置 ### 季节性乘数 所有乘数都调整为平均值 ≈ 1.0,以避免系统性的过度/不足生成: ``` # 每小时(24 个值:00:00–23:00) HOURLY_MULTIPLIERS = [0.43, 0.41, 0.45, 0.48, 0.52, 0.58, 0.68, 0.78, 0.92, 1.02, 1.08, 1.12, 1.15, 1.18, 1.20, 1.52, 1.48, 1.42, 1.32, 1.18, 1.08, 0.92, 0.78, 0.63] # 星期几(周一–周日) DAY_OF_WEEK_MULTIPLIERS = [1.06, 1.01, 0.96, 0.96, 0.97, 1.02, 1.03] # 每月(1月–12月) MONTHLY_MULTIPLIERS = [1.08, 1.12, 1.02, 0.98, 0.95, 0.87, 0.85, 0.90, 0.95, 1.00, 1.08, 1.10] # 特定程序(冬季/夏季/择期调整) PROCEDURE_SEASONALITY = { 'Cardiac Catheterization': 1.15, # Winter cardiac events 'Appendectomy': 1.10, # Summer surgical peak 'Colonoscopy': 0.95, # Winter dip 'Bypass Surgery': 1.18, # Winter ACS 'Angioplasty': 1.12, # Winter ACS 'Hysterectomy': 1.02, # Summer elective 'Knee Replacement': 1.08, # Summer post-sports-season 'Hip Replacement': 1.05, # Summer fall-prevention rush 'Appendix Removal': 1.10, # Summer 'Gallbladder Removal': 1.03, # Summer 'Hernia Repair': 1.04, # Summer } ``` ### 医院配置 首次运行时自动生成医院,具有基于规模的特征: ``` HOSPITALS = [ {'hospital_id': 1, 'hospital_name': 'Metro General', 'bed_count': 850, 'city': 'New York', 'state': 'NY'}, # Large {'hospital_id': 2, 'hospital_name': 'Central Memorial', 'bed_count': 420, 'city': 'Chicago', 'state': 'IL'}, # Medium {'hospital_id': 3, 'hospital_name': 'Riverside Clinic', 'bed_count': 200, 'city': 'Portland', 'state': 'OR'}, # Small # ... (10 total) ] ``` ## 数据库 Schema 详情 ### 日期维度 (date_dim) ``` CREATE TABLE date_dim ( date DATE PRIMARY KEY, date_key INT, yyyy INT, mm INT, dd INT, mm_name VARCHAR(12), mm_short VARCHAR(3), day_of_week INT, day_of_week_name VARCHAR(10), is_weekend BIT, quarter INT, iso_year INT, iso_week INT, day_of_year INT, week_of_year INT, fiscal_year INT, fiscal_month INT, formatted_date_mmddyyyy VARCHAR(10), formatted_date_yyyymmdd VARCHAR(10) ); -- 398 rows (2025-01-01 → 2026-02-02) ``` ### 医院科室床位 (hospital_department_beds) ``` CREATE TABLE hospital_department_beds ( hospital_id INT, department_id INT, bed_count INT, PRIMARY KEY (hospital_id, department_id), FOREIGN KEY (hospital_id) REFERENCES hospitals(hospital_id), FOREIGN KEY (department_id) REFERENCES departments(department_id) ); -- ~100 rows (10 hospitals × ~10 departments, ER skewed by size) ``` ### 住院 ``` CREATE TABLE admissions ( admission_id INT PRIMARY KEY, encounter_id INT, hospital_id INT, patient_id INT, admit_datetime DATETIME, discharge_datetime DATETIME NULL, -- NULL = ongoing stay FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id), FOREIGN KEY (hospital_id) REFERENCES hospitals(hospital_id), FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ); -- ~3,000–5,000 rows (proportional to encounter count) ``` ### 视图 #### vw_current_er_beds ``` CREATE VIEW vw_current_er_beds AS SELECT h.hospital_id, h.hospital_name, SUM(hdb.bed_count) AS total_er_beds, SUM(CASE WHEN a.discharge_datetime IS NULL OR a.discharge_datetime > GETDATE() THEN 1 ELSE 0 END) AS occupied_beds, SUM(hdb.bed_count) - SUM(CASE WHEN a.discharge_datetime IS NULL OR a.discharge_datetime > GETDATE() THEN 1 ELSE 0 END) AS available_beds FROM hospitals h JOIN hospital_department_beds hdb ON h.hospital_id = hdb.hospital_id JOIN departments d ON hdb.department_id = d.department_id AND d.specialty_type = 'Emergency' LEFT JOIN admissions a ON h.hospital_id = a.hospital_id GROUP BY h.hospital_id, h.hospital_name; ``` #### vw_current_patient_beds ``` CREATE VIEW vw_current_patient_beds AS SELECT h.hospital_id, h.hospital_name, h.bed_count, COUNT(DISTINCT CASE WHEN a.discharge_datetime IS NULL OR a.discharge_datetime > GETDATE() THEN a.admission_id END) AS occupied_beds, h.bed_count - COUNT(DISTINCT CASE WHEN a.discharge_datetime IS NULL OR a.discharge_datetime > GETDATE() THEN a.admission_id END) AS available_beds FROM hospitals h LEFT JOIN admissions a ON h.hospital_id = a.hospital_id GROUP BY h.hospital_id, h.hospital_name, h.bed_count; ``` ## 示例查询 ### Q1:按季节划分的手术量 ``` SELECT MONTH(d.yyyy) AS month_num, d.mm_name AS month, p.procedure_name, COUNT(*) AS procedure_count FROM procedures p JOIN date_dim d ON CAST(p.procedure_date AS DATE) = d.date GROUP BY MONTH(d.yyyy), d.mm_name, p.procedure_name ORDER BY procedure_count DESC; ``` *预期输出:心脏导管术在 1 月/2 月/12 月达到高峰;阑尾切除术在 7 月/8 月达到高峰* ### Q2:按医院划分的 ED 占用率(过去 7 天) ``` SELECT h.hospital_name, COUNT(DISTINCT a.admission_id) AS current_admissions, h.bed_count, ROUND(100.0 * COUNT(DISTINCT a.admission_id) / h.bed_count, 1) AS occupancy_pct FROM hospitals h LEFT JOIN admissions a ON h.hospital_id = a.hospital_id AND a.admit_datetime >= DATEADD(DAY, -7, GETDATE()) AND (a.discharge_datetime IS NULL OR a.discharge_datetime > GETDATE()) GROUP BY h.hospital_id, h.hospital_name, h.bed_count ORDER BY occupancy_pct DESC; ``` ### Q3:按住院月份划分的住院天数 ``` SELECT DATENAME(MONTH, a.admit_datetime) AS admit_month, AVG(DATEDIFF(DAY, a.admit_datetime, ISNULL(a.discharge_datetime, GETDATE()))) AS avg_los_days, MIN(DATEDIFF(DAY, a.admit_datetime, ISNULL(a.discharge_datetime, GETDATE()))) AS min_los_days, MAX(DATEDIFF(DAY, a.admit_datetime, ISNULL(a.discharge_datetime, GETDATE()))) AS max_los_days FROM admissions a GROUP BY DATENAME(MONTH, a.admit_datetime), MONTH(a.admit_datetime) ORDER BY MONTH(a.admit_datetime); ``` ### Q4:恶劣天气期间的流感诊断率 ``` SELECT CASE WHEN c.weather_condition IN ('Rain', 'Snow', 'Fog') THEN 'Bad Weather' ELSE 'Good Weather' END AS weather_type, COUNT(*) AS total_encounters, SUM(CASE WHEN d.diagnosis_name LIKE '%Flu%' THEN 1 ELSE 0 END) AS flu_diagnoses, ROUND(100.0 * SUM(CASE WHEN d.diagnosis_name LIKE '%Flu%' THEN 1 ELSE 0 END) / COUNT(*), 2) AS flu_rate_pct FROM encounters e LEFT JOIN diagnoses d ON e.encounter_id = d.encounter_id GROUP BY CASE WHEN c.weather_condition IN ('Rain', 'Snow', 'Fog') THEN 'Bad Weather' ELSE 'Good Weather' END; ``` ## 故障排除 ### 问题:"pyodbc.Error: ('08001', '[08001] [Microsoft][ODBC Driver 17 for SQL Server]…" **解决方案**:验证 `src.py` 中的 `CONNECTION_STRING`。测试连接: ``` python -c "import pyodbc; pyodbc.connect('your_connection_string')" ``` ### 问题:天气缓存未在运行之间持久化 **解决方案**:检查 `weather_cache.json` 的文件权限。确保脚本具有对项目根目录的写入权限。 ``` ls -la weather_cache.json # Linux/Mac dir weather_cache.json # Windows ``` ### 问题:重建时间过长(399 天超过 10 分钟) **解决方案**:首次运行正常(缓存了 399 次 API 调用)。后续运行使用缓存(即时)。如有必要,强制并行处理: - 目前,使用 `--rebuild-start 2025-01-01` 运行一次并让其完成 - 缓存将在约 2–5 分钟内填充 - 未来的运行使用缓存(秒级) ### 问题:手术季节性中的 "KeyError" **解决方案**:确保 `PROCEDURE_SEASONALITY` 字典中的所有 11 个手术名称与 `src/main.py` 中的 `PROCEDURE_WEIGHTS` 键完全匹配。检查拼写。 ### 问题:SQL 视图查询返回 0 占用率 **解决方案**:验证 admissions 表是否有数据。运行: ``` SELECT COUNT(*) FROM admissions WHERE discharge_datetime IS NULL OR discharge_datetime > GETDATE(); ``` 如果为空,重建:`python src/main.py --rebuild-start 2025-01-01` ## 性能特征 | 操作 | 持续时间 | 说明 | |-----------|----------|-------| | 初始构建(399 天) | 2–5 分钟 | 缓存约 399 次 API 调用;DB 插入 | | 后续重建(缓存命中) | 30–60 秒 | 无 API 调用;使用缓存 | | 每日增量 | <5 秒 | 缓存命中今日天气 | | 天气缓存保存/加载 | <100 毫秒 | JSON 序列化 | | SQL 视图 (vw_current_patient_beds) | <500 毫秒 | 扫描 admissions;在 hospital_id 上建立索引 | ## 开发与贡献 ### 项目结构 ``` Healthcare Data Generator/ ├── src/ │ ├── main.py # Core generation logic (1,400+ lines) │ ├── config.py # DB connection + seasonality multipliers │ └── __pycache__/ ├── scripts/ │ └── validate_and_create_date_dim.py # Helper for date_dim validation ├── requirements.txt # Dependencies (pandas, faker, sqlalchemy, pyodbc, requests) ├── README.md # This file ├── weather_cache.json # Auto-generated; weather by date └── .github/ └── copilot-instructions.md # Copilot workspace hints ``` ### 添加自定义季节性 1. 打开 `src/config.py` 2. 修改 `HOURLY_MULTIPLIERS`、`DAY_OF_WEEK_MULTIPLIERS` 或 `MONTHLY_MULTIPLIERS` 数组 3. 调整 `PROCEDURE_SEASONALITY` 字典以进行特定于手术的微调 4. 重新运行:`python src/main.py --rebuild-start 2025-01-01` ### 测试新功能 ``` # 快速测试(1 天,新缓存) python src/main.py --clear-weather-cache --rebuild-start 2025-01-01 # 验证特定表(例如 admissions) python -c "import pandas as pd; from src.config import *; df = pd.read_sql('SELECT TOP 10 * FROM admissions', CONNECTION_STRING); print(df)" ``` ## 参考文献与引用 ### 季节性数据 - **NHS A&E 就诊模式**:https://www.nhs.uk/NHSEngland/ (按小时/天/月划分的 ED 量) - **CDC NHAMCS**:https://www.cdc.gov/nchs/nhamcs/about_nhamcs.htm (美国医院门诊模式) - **流感季节**:https://www.cdc.gov/flu/about/season/flu-season.htm (10 月–5 月高峰) - **PMC:季节性手术差异**:https://www.ncbi.nlm.nih.gov/pmc/ (手术季节性研究) ### 天气 API - **Open-Meteo Archive API**:https://open-meteo.com/en/docs/historical-weather-api (免费历史天气) ### 医疗保健数据标准 - **ICD-10-CM**:https://www.cdc.gov/nchs/icd/icd10cm.htm (诊断代码) - **CPT**:https://www.ama-assn.org/practice-management/cpt (手术代码) ## 许可证 MIT License - 有关详细信息,请参阅 LICENSE 文件。 ## 密钥与配置 🔒 - **切勿将凭据**(连接字符串、密码、令牌)提交到仓库。如果您之前提交了密钥,请立即轮换它们。 - 使用环境变量(参见 `.env.example`)或创建本地 `src/config_local.py`(此文件包含在 `.gitignore` 中)以存储您的 `CONNECTION_STRING` 用于本地开发。 - 示例:在您的 shell 中设置 `CONNECTION_STRING` 或将 `.env.example` 复制到 `.env` 并填写值。 - 可选择安装 `python-dotenv` 并 `pip install python-dotenv` 以在开发中自动加载 `.env`。 ## 付款人与临床逼真度增强 ✅ 近期改进(2026 年 2 月): - **付款人组合**:患者 `primary_payer` 和 `insurance` 现反映大致的美国市场份额(Medicare ~36%,Medicaid ~20%,商保 ~35%,无保险 ~5%,其他 ~4%)。年龄和医院专科调整采样(例如,老年人 Medicare 较高;儿科 Medicaid 较高)。 - **诊断分布**:ICD-10 采样经过专科加权并按季节调整(例如,流感代码在 12 月–2 月激增;儿科呼吸道代码在冬季增加)。诊断关联到 `chief_complaint` 以及适用的可能化验/药物。 - **手术、化验、药物**:这些实体现在使用专科感知权重和季节性进行采样(例如,心脏病医院的心脏导管术更多,阑尾切除术在夏季呈上升趋势)。化验/药物尽可能与诊断关联以提高临床合理性。 - **临床映射扩展**:增加了额外的 ICD-10 条目和更丰富的 `DIAGNOSIS_TO_MEDS` 和 `DIAGNOSIS_TO_LABS` 映射(脓毒症、肺炎、COPD 急性加重、蜂窝织炎、中风),以便下游分析(按诊断划分的顶级药物、化验)更贴近现实世界的医院数据。 - **总体趋势**:月度和每小时模式现在产生明显的总体趋势(季节性高峰、工作日效应、按年龄/专科的付款人分布变化)以使分析逼真。 **来源**:CDC NHAMCS,AHA 心血管统计,NCI SEER,ACEP ED 运营,CMS 付款人组合报告,关于季节性和临床实践模式的同行评审研究。 **版本**:2.1(临床逼真度 + 付款人分布) **最后更新**:2026 年 2 月 5 日 **维护者**:Healthcare Data Generator Team 如有问题、功能请求或疑问,请在项目仓库中提交 issue。
标签:ETL, JavaCC, Microsoft Fabric, ODBC, Parquet, Python, SQL Server, 代码示例, 仪表板测试, 假数据, 医疗保健, 医疗分析, 医疗数据生成器, 医院运营数据, 占用率追踪, 合成数据, 天气集成, 季节性模式, 患者人口统计学, 数据分析, 数据工程, 数据管道, 数据隐私, 无后门, 模拟数据, 测试数据, 软件工程, 逆向工具