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, 代码示例, 仪表板测试, 假数据, 医疗保健, 医疗分析, 医疗数据生成器, 医院运营数据, 占用率追踪, 合成数据, 天气集成, 季节性模式, 患者人口统计学, 数据分析, 数据工程, 数据管道, 数据隐私, 无后门, 模拟数据, 测试数据, 软件工程, 逆向工具