摘要
随着医疗信息化的深入发展,医疗大数据的价值日益凸显。本文将深入探讨如何构建一个专业的智慧医疗大数据可视化系统,涵盖医疗数据采集、患者分析、趋势预测、慢病管理等核心功能。通过实际案例分析和完整的代码实现,帮助开发者掌握医疗领域数据可视化的关键技术和最佳实践,为医疗机构的数字化转型提供技术支撑。
关键词: 智慧医疗、医疗大数据、数据可视化、患者分析、慢病管理
目录
- 引言
- 智慧医疗可视化系统概述
- 系统架构设计
- 医疗数据采集与处理
- 患者数据可视化分析
- 医疗指标监控系统
- 慢病管理可视化模块
- 地理信息系统集成
- 实时数据处理与预警
- 用户界面设计与交互
- 数据安全与隐私保护
- 性能优化与扩展性
- 部署与运维
- 总结与展望
1. 引言
在数字化医疗时代,医疗机构每天产生海量的数据,包括患者信息、诊疗记录、检验结果、影像数据等。如何有效地分析和利用这些数据,为医疗决策提供支持,成为现代医疗管理的重要课题。
1.1 医疗大数据的挑战
现代医疗机构在数据管理和分析中面临以下主要挑战:
1.2 可视化解决方案的价值
医疗大数据可视化在现代医疗管理中的核心价值:
- 直观展示:将复杂的医疗数据转化为易理解的图表
- 趋势分析:识别疾病流行趋势和患者健康变化
- 资源优化:优化医疗资源配置和床位管理
- 质量监控:实时监控医疗服务质量指标
- 决策支持:为临床决策和管理决策提供数据支撑
2. 智慧医疗可视化系统概述
2.1 系统功能架构
# 智慧医疗大数据可视化系统
class MedicalDataVisualizationSystem:
"""智慧医疗大数据可视化系统"""
def __init__(self):
self.modules = self.define_system_modules()
self.data_sources = self.define_data_sources()
self.indicators = self.define_medical_indicators()
self.patient_categories = self.define_patient_categories()
def define_system_modules(self):
"""定义系统功能模块"""
return {
"数据采集概况": {
"描述": "医疗数据采集和统计概览",
"功能": [
"数据采集量统计",
"门诊住院人数统计",
"各医院数据对比",
"实时数据监控"
],
"技术要点": [
"多源数据整合",
"实时数据更新",
"统计图表展示",
"地理信息展示"
]
},
"指标分析": {
"描述": "医疗质量指标分析和监控",
"功能": [
"医疗质量指标监控",
"服务效率分析",
"成本效益分析",
"同行对比分析"
],
"技术要点": [
"指标体系设计",
"多维度分析",
"趋势预测算法",
"异常检测机制"
]
},
"趋势分析": {
"描述": "医疗数据趋势分析和预测",
"功能": [
"疾病流行趋势分析",
"患者流量预测",
"季节性变化分析",
"长期趋势预测"
],
"技术要点": [
"时间序列分析",
"机器学习预测",
"统计学方法",
"可视化展示"
]
},
"慢病管理": {
"描述": "慢性病患者管理和监控",
"功能": [
"慢病患者列表管理",
"病情进展跟踪",
"用药依从性监控",
"健康指标预警"
],
"技术要点": [
"患者档案管理",
"健康数据追踪",
"预警机制设计",
"个性化分析"
]
}
}
def define_data_sources(self):
"""定义数据源"""
return {
"HIS系统": {
"描述": "医院信息系统",
"数据类型": [
"患者基本信息",
"门诊记录",
"住院记录",
"医嘱信息"
],
"更新频率": "实时",
"数据格式": "结构化数据"
},
"LIS系统": {
"描述": "实验室信息系统",
"数据类型": [
"检验结果",
"检验项目",
"标本信息",
"质控数据"
],
"更新频率": "实时",
"数据格式": "结构化数据"
},
"PACS系统": {
"描述": "影像归档和通信系统",
"数据类型": [
"医学影像",
"影像报告",
"检查记录",
"设备信息"
],
"更新频率": "实时",
"数据格式": "非结构化数据"
},
"EMR系统": {
"描述": "电子病历系统",
"数据类型": [
"病历记录",
"诊断信息",
"治疗方案",
"护理记录"
],
"更新频率": "实时",
"数据格式": "半结构化数据"
},
"外部数据": {
"描述": "外部医疗数据源",
"数据类型": [
"公共卫生数据",
"疾控中心数据",
"医保数据",
"药品信息"
],
"更新频率": "定期",
"数据格式": "多种格式"
}
}
def define_medical_indicators(self):
"""定义医疗指标体系"""
return {
"医疗质量指标": {
"患者安全指标": {
"院内感染率": {
"计算公式": "院内感染人数 / 住院总人数 × 100%",
"目标值": "< 3%",
"监控频率": "日",
"权重": 0.3
},
"药物不良反应率": {
"计算公式": "药物不良反应人数 / 用药总人数 × 100%",
"目标值": "< 1%",
"监控频率": "日",
"权重": 0.2
},
"手术并发症率": {
"计算公式": "手术并发症人数 / 手术总人数 × 100%",
"目标值": "< 2%",
"监控频率": "日",
"权重": 0.25
}
},
"医疗效率指标": {
"平均住院日": {
"计算公式": "总住院天数 / 出院人数",
"目标值": "< 10天",
"监控频率": "日",
"权重": 0.2
},
"床位使用率": {
"计算公式": "实际占用床日数 / 开放床日数 × 100%",
"目标值": "85%-95%",
"监控频率": "日",
"权重": 0.15
},
"门诊预约率": {
"计算公式": "预约门诊人数 / 门诊总人数 × 100%",
"目标值": "> 80%",
"监控频率": "日",
"权重": 0.1
}
}
},
"服务质量指标": {
"患者满意度": {
"门诊满意度": {
"计算公式": "满意患者数 / 调查患者数 × 100%",
"目标值": "> 90%",
"监控频率": "月",
"权重": 0.3
},
"住院满意度": {
"计算公式": "满意患者数 / 调查患者数 × 100%",
"目标值": "> 95%",
"监控频率": "月",
"权重": 0.3
}
},
"服务效率": {
"平均候诊时间": {
"计算公式": "总候诊时间 / 门诊人数",
"目标值": "< 30分钟",
"监控频率": "日",
"权重": 0.2
},
"检查报告及时率": {
"计算公式": "及时出具报告数 / 检查总数 × 100%",
"目标值": "> 95%",
"监控频率": "日",
"权重": 0.2
}
}
},
"经济效益指标": {
"成本控制": {
"人均医疗费用": {
"计算公式": "总医疗费用 / 患者总数",
"目标值": "合理区间",
"监控频率": "月",
"权重": 0.25
},
"药占比": {
"计算公式": "药品费用 / 医疗总费用 × 100%",
"目标值": "< 30%",
"监控频率": "月",
"权重": 0.25
}
},
"收益指标": {
"医疗收入增长率": {
"计算公式": "(本期收入-上期收入) / 上期收入 × 100%",
"目标值": "> 5%",
"监控频率": "月",
"权重": 0.25
},
"医疗服务收入占比": {
"计算公式": "医疗服务收入 / 总收入 × 100%",
"目标值": "> 60%",
"监控频率": "月",
"权重": 0.25
}
}
}
}
def define_patient_categories(self):
"""定义患者分类"""
return {
"年龄分组": {
"儿童": "0-14岁",
"青少年": "15-24岁",
"青年": "25-44岁",
"中年": "45-64岁",
"老年": "65岁以上"
},
"疾病分类": {
"慢性病": [
"高血压",
"糖尿病",
"冠心病",
"慢性肾病",
"慢性阻塞性肺病"
],
"急性病": [
"急性心梗",
"急性脑卒中",
"急性胰腺炎",
"急性阑尾炎"
],
"肿瘤": [
"肺癌",
"胃癌",
"肝癌",
"乳腺癌",
"结直肠癌"
]
},
"就诊类型": {
"门诊": "门诊患者",
"急诊": "急诊患者",
"住院": "住院患者",
"体检": "健康体检"
},
"风险等级": {
"低风险": "健康状况良好",
"中风险": "存在健康隐患",
"高风险": "需要重点关注",
"极高风险": "需要紧急处理"
}
}
def calculate_medical_quality_score(self, hospital_data):
"""计算医疗质量评分"""
total_score = 0
total_weight = 0
for category, indicators in self.indicators.items():
for subcategory, sub_indicators in indicators.items():
for indicator_name, indicator_info in sub_indicators.items():
if indicator_name in hospital_data:
value = hospital_data[indicator_name]
score = self.evaluate_medical_indicator(value, indicator_info)
weight = indicator_info['权重']
total_score += score * weight
total_weight += weight
if total_weight > 0:
final_score = total_score / total_weight * 100
return min(100, max(0, final_score))
return 0
def evaluate_medical_indicator(self, value, indicator_info):
"""评估医疗指标"""
target_value = indicator_info['目标值']
# 简化的评估逻辑,实际应用中需要更复杂的算法
if self.meets_target(value, target_value):
return 95
else:
# 根据偏离程度计算得分
return max(60, 95 - abs(self.calculate_deviation(value, target_value)) * 10)
def meets_target(self, value, target_str):
"""检查是否达到目标值"""
# 简化的目标检查逻辑
if '<' in target_str:
threshold = float(target_str.replace('<', '').replace('%', '').strip())
return value < threshold
elif '>' in target_str:
threshold = float(target_str.replace('>', '').replace('%', '').strip())
return value > threshold
elif '-' in target_str:
parts = target_str.replace('%', '').split('-')
min_val = float(parts[0].strip())
max_val = float(parts[1].strip())
return min_val <= value <= max_val
return True
def calculate_deviation(self, value, target_str):
"""计算偏离程度"""
# 简化的偏离计算逻辑
if '<' in target_str:
threshold = float(target_str.replace('<', '').replace('%', '').strip())
return max(0, value - threshold) / threshold
elif '>' in target_str:
threshold = float(target_str.replace('>', '').replace('%', '').strip())
return max(0, threshold - value) / threshold
return 0
def generate_medical_report(self, hospital_data):
"""生成医疗质量报告"""
quality_score = self.calculate_medical_quality_score(hospital_data)
return {
"医院名称": hospital_data.get("name", "未知医院"),
"评估时间": "2024-07-20",
"综合评分": quality_score,
"质量等级": self.get_quality_level(quality_score),
"关键指标": self.analyze_key_indicators(hospital_data),
"改进建议": self.generate_improvement_suggestions(hospital_data),
"风险预警": self.identify_risk_alerts(hospital_data)
}
def get_quality_level(self, score):
"""获取质量等级"""
if score >= 90:
return "优秀"
elif score >= 80:
return "良好"
elif score >= 70:
return "合格"
else:
return "需要改进"
def analyze_key_indicators(self, hospital_data):
"""分析关键指标"""
key_indicators = {}
# 分析关键医疗指标
if "院内感染率" in hospital_data:
key_indicators["患者安全"] = {
"院内感染率": f"{hospital_data['院内感染率']:.2f}%",
"状态": "正常" if hospital_data['院内感染率'] < 3 else "需关注"
}
if "平均住院日" in hospital_data:
key_indicators["医疗效率"] = {
"平均住院日": f"{hospital_data['平均住院日']:.1f}天",
"状态": "正常" if hospital_data['平均住院日'] < 10 else "需优化"
}
return key_indicators
def generate_improvement_suggestions(self, hospital_data):
"""生成改进建议"""
suggestions = []
if hospital_data.get("院内感染率", 0) > 3:
suggestions.append("加强院内感染控制措施,提高手卫生依从性")
if hospital_data.get("平均住院日", 0) > 10:
suggestions.append("优化诊疗流程,缩短平均住院日")
if hospital_data.get("药占比", 0) > 30:
suggestions.append("合理用药,控制药占比在合理范围内")
if not suggestions:
suggestions.append("继续保持良好的医疗质量管理水平")
return suggestions
def identify_risk_alerts(self, hospital_data):
"""识别风险预警"""
alerts = []
if hospital_data.get("药物不良反应率", 0) > 1:
alerts.append({
"级别": "高风险",
"内容": "药物不良反应率超标",
"建议": "立即审查用药安全管理制度"
})
if hospital_data.get("手术并发症率", 0) > 2:
alerts.append({
"级别": "中风险",
"内容": "手术并发症率偏高",
"建议": "加强手术质量管理和术前评估"
})
return alerts
def print_system_overview(self):
"""打印系统概述"""
print("=== 智慧医疗大数据可视化系统概述 ===\n")
print("🏥 系统功能模块:")
for module_name, module_info in self.modules.items():
print(f"\n🔹 {module_name}")
print(f" 描述: {module_info['描述']}")
print(f" 主要功能:")
for func in module_info['功能']:
print(f" • {func}")
print(f" 技术要点:")
for tech in module_info['技术要点']:
print(f" ◦ {tech}")
print(f"\n📊 数据源:")
for source_name, source_info in self.data_sources.items():
print(f"\n🔸 {source_name}")
print(f" 描述: {source_info['描述']}")
print(f" 数据类型: {', '.join(source_info['数据类型'])}")
print(f" 更新频率: {source_info['更新频率']}")
print(f"\n📈 医疗指标体系:")
for category, indicators in self.indicators.items():
print(f"\n🔸 {category}:")
for subcategory, sub_indicators in indicators.items():
print(f" • {subcategory}:")
for indicator in sub_indicators.keys():
print(f" - {indicator}")
# 创建系统实例并展示概述
medical_system = MedicalDataVisualizationSystem()
medical_system.print_system_overview()
# 示例:医疗质量评估
sample_hospital = {
"name": "第一人民医院",
"院内感染率": 2.5,
"药物不良反应率": 0.8,
"手术并发症率": 1.5,
"平均住院日": 8.5,
"床位使用率": 88.0,
"药占比": 28.5
}
report = medical_system.generate_medical_report(sample_hospital)
print(f"\n📋 医疗质量评估报告:")
print(f" 医院名称: {report['医院名称']}")
print(f" 综合评分: {report['综合评分']:.2f}")
print(f" 质量等级: {report['质量等级']}")
print(f" 改进建议: {', '.join(report['改进建议'])}")
2.2 系统特点与优势
特点 | 描述 | 业务价值 |
---|---|---|
多源数据整合 | 整合HIS、LIS、PACS等多个系统数据 | 提供全面的医疗数据视图 |
实时监控 | 7×24小时实时监控医疗指标 | 及时发现异常,提高响应速度 |
智能分析 | 基于AI的数据分析和预测 | 提供智能决策支持 |
个性化展示 | 根据用户角色定制化展示 | 提高信息利用效率 |
移动端支持 | 支持移动设备访问 | 随时随地查看医疗数据 |
3. 系统架构设计
3.1 技术架构
3.2 数据流架构
4. 医疗数据采集与处理
4.1 数据采集模块
# 医疗数据采集与处理系统
import json
import datetime
from typing import Dict, List, Any
import pandas as pd
import numpy as np
class MedicalDataCollector:
"""医疗数据采集器"""
def __init__(self):
self.data_sources = self.initialize_data_sources()
self.collection_rules = self.define_collection_rules()
self.data_quality_rules = self.define_quality_rules()
def initialize_data_sources(self):
"""初始化数据源配置"""
return {
"HIS": {
"connection_type": "database",
"host": "his.hospital.com",
"port": 1521,
"database": "HIS_DB",
"tables": [
"patients", # 患者信息表
"admissions", # 入院记录表
"discharges", # 出院记录表
"outpatient_visits", # 门诊记录表
"medical_orders", # 医嘱表
"medications", # 用药记录表
"procedures", # 手术记录表
"diagnoses" # 诊断记录表
],
"update_frequency": "real-time",
"data_retention": "7_years"
},
"LIS": {
"connection_type": "api",
"endpoint": "https://lis.hospital.com/api/v1",
"authentication": "oauth2",
"data_types": [
"lab_results", # 检验结果
"lab_orders", # 检验申请
"specimens", # 标本信息
"reference_ranges", # 参考范围
"quality_control" # 质控数据
],
"update_frequency": "real-time",
"data_retention": "5_years"
},
"PACS": {
"connection_type": "dicom",
"server": "pacs.hospital.com",
"port": 11112,
"data_types": [
"medical_images", # 医学影像
"image_reports", # 影像报告
"study_metadata", # 检查元数据
"series_metadata" # 序列元数据
],
"update_frequency": "real-time",
"data_retention": "10_years"
},
"EMR": {
"connection_type": "hl7",
"endpoint": "emr.hospital.com:8080",
"message_types": [
"ADT", # 患者管理消息
"ORM", # 医嘱消息
"ORU", # 结果消息
"MDM" # 文档消息
],
"update_frequency": "real-time",
"data_retention": "永久"
}
}
def define_collection_rules(self):
"""定义数据采集规则"""
return {
"实时采集规则": {
"触发条件": [
"新患者入院",
"检验结果更新",
"医嘱下达",
"诊断确认"
],
"采集频率": "事件驱动",
"数据验证": "实时验证",
"错误处理": "重试机制"
},
"批量采集规则": {
"采集时间": [
"每日凌晨2:00",
"每周日凌晨1:00",
"每月1日凌晨0:00"
],
"采集范围": "全量数据",
"数据验证": "批量验证",
"错误处理": "日志记录"
},
"增量采集规则": {
"采集频率": "每小时",
"时间窗口": "上次采集时间至当前时间",
"数据验证": "增量验证",
"冲突处理": "最新数据优先"
}
}
def define_quality_rules(self):
"""定义数据质量规则"""
return {
"完整性检查": {
"必填字段检查": [
"患者ID",
"就诊时间",
"诊断代码",
"医生ID"
],
"关联性检查": [
"患者-就诊记录关联",
"医嘱-执行记录关联",
"检验申请-结果关联"
]
},
"准确性检查": {
"数据格式验证": [
"日期格式检查",
"数值范围检查",
"编码规范检查"
],
"逻辑一致性检查": [
"入院时间早于出院时间",
"检验时间在合理范围内",
"药物剂量在安全范围内"
]
},
"及时性检查": {
"数据延迟监控": [
"实时数据延迟 < 5分钟",
"批量数据延迟 < 1小时",
"历史数据完整性"
]
},
"一致性检查": {
"跨系统数据一致性": [
"患者基本信息一致性",
"诊断编码一致性",
"时间戳一致性"
]
}
}
def collect_patient_data(self, patient_id: str, date_range: tuple = None):
"""采集患者数据"""
try:
patient_data = {
"basic_info": self.collect_basic_info(patient_id),
"medical_history": self.collect_medical_history(patient_id, date_range),
"lab_results": self.collect_lab_results(patient_id, date_range),
"medications": self.collect_medications(patient_id, date_range),
"procedures": self.collect_procedures(patient_id, date_range),
"images": self.collect_medical_images(patient_id, date_range)
}
# 数据质量检查
quality_report = self.validate_data_quality(patient_data)
return {
"patient_id": patient_id,
"data": patient_data,
"quality_report": quality_report,
"collection_time": datetime.datetime.now().isoformat()
}
except Exception as e:
return {
"patient_id": patient_id,
"error": str(e),
"collection_time": datetime.datetime.now().isoformat()
}
def collect_basic_info(self, patient_id: str):
"""采集患者基本信息"""
# 模拟从HIS系统采集患者基本信息
return {
"patient_id": patient_id,
"name": "张三",
"gender": "男",
"age": 45,
"birth_date": "1979-03-15",
"id_number": "110101197903150001",
"phone": "13800138000",
"address": "北京市朝阳区",
"emergency_contact": "李四",
"emergency_phone": "13900139000",
"insurance_type": "职工医保",
"insurance_number": "110101197903150001"
}
def collect_medical_history(self, patient_id: str, date_range: tuple = None):
"""采集病史信息"""
# 模拟从EMR系统采集病史信息
return {
"chronic_diseases": [
{
"disease_code": "I10",
"disease_name": "高血压",
"diagnosis_date": "2020-05-15",
"severity": "轻度",
"status": "稳定"
},
{
"disease_code": "E11",
"disease_name": "2型糖尿病",
"diagnosis_date": "2021-08-20",
"severity": "中度",
"status": "控制中"
}
],
"allergies": [
{
"allergen": "青霉素",
"reaction": "皮疹",
"severity": "中度"
}
],
"family_history": [
{
"relation": "父亲",
"disease": "高血压",
"age_of_onset": 50
},
{
"relation": "母亲",
"disease": "糖尿病",
"age_of_onset": 55
}
],
"surgical_history": [
{
"procedure": "阑尾切除术",
"date": "2015-06-10",
"hospital": "第一人民医院"
}
]
}
def collect_lab_results(self, patient_id: str, date_range: tuple = None):
"""采集检验结果"""
# 模拟从LIS系统采集检验结果
return {
"blood_routine": {
"test_date": "2024-07-20",
"results": {
"WBC": {"value": 6.5, "unit": "10^9/L", "reference": "3.5-9.5", "status": "正常"},
"RBC": {"value": 4.2, "unit": "10^12/L", "reference": "4.3-5.8", "status": "偏低"},
"HGB": {"value": 125, "unit": "g/L", "reference": "130-175", "status": "偏低"},
"PLT": {"value": 280, "unit": "10^9/L", "reference": "125-350", "status": "正常"}
}
},
"blood_chemistry": {
"test_date": "2024-07-20",
"results": {
"GLU": {"value": 8.5, "unit": "mmol/L", "reference": "3.9-6.1", "status": "偏高"},
"TC": {"value": 5.8, "unit": "mmol/L", "reference": "<5.2", "status": "偏高"},
"TG": {"value": 2.1, "unit": "mmol/L", "reference": "<1.7", "status": "偏高"},
"HDL": {"value": 1.0, "unit": "mmol/L", "reference": ">1.0", "status": "正常"},
"LDL": {"value": 3.8, "unit": "mmol/L", "reference": "<3.4", "status": "偏高"}
}
},
"liver_function": {
"test_date": "2024-07-20",
"results": {
"ALT": {"value": 35, "unit": "U/L", "reference": "9-50", "status": "正常"},
"AST": {"value": 28, "unit": "U/L", "reference": "15-40", "status": "正常"},
"TBIL": {"value": 18, "unit": "μmol/L", "reference": "5-21", "status": "正常"}
}
}
}
def collect_medications(self, patient_id: str, date_range: tuple = None):
"""采集用药信息"""
# 模拟从HIS系统采集用药信息
return {
"current_medications": [
{
"medication_name": "氨氯地平片",
"dosage": "5mg",
"frequency": "每日一次",
"route": "口服",
"start_date": "2024-01-15",
"end_date": None,
"prescriber": "李医生",
"indication": "高血压"
},
{
"medication_name": "二甲双胍片",
"dosage": "500mg",
"frequency": "每日两次",
"route": "口服",
"start_date": "2024-02-01",
"end_date": None,
"prescriber": "王医生",
"indication": "2型糖尿病"
}
],
"medication_history": [
{
"medication_name": "阿司匹林肠溶片",
"dosage": "100mg",
"frequency": "每日一次",
"route": "口服",
"start_date": "2023-06-01",
"end_date": "2024-01-01",
"prescriber": "张医生",
"indication": "心血管保护",
"discontinue_reason": "胃肠道不适"
}
]
}
def collect_procedures(self, patient_id: str, date_range: tuple = None):
"""采集手术/操作信息"""
# 模拟从HIS系统采集手术信息
return {
"procedures": [
{
"procedure_code": "36.10",
"procedure_name": "冠状动脉造影",
"date": "2024-06-15",
"surgeon": "心内科-刘医生",
"anesthesia_type": "局部麻醉",
"duration": 45,
"complications": "无",
"outcome": "成功"
}
],
"planned_procedures": [
{
"procedure_name": "冠状动脉支架植入术",
"planned_date": "2024-08-01",
"surgeon": "心内科-刘医生",
"preparation_required": [
"术前检查",
"停用抗凝药物",
"禁食12小时"
]
}
]
}
def collect_medical_images(self, patient_id: str, date_range: tuple = None):
"""采集医学影像信息"""
# 模拟从PACS系统采集影像信息
return {
"studies": [
{
"study_id": "ST001",
"modality": "CT",
"body_part": "胸部",
"study_date": "2024-07-18",
"description": "胸部CT平扫+增强",
"radiologist": "影像科-陈医生",
"report": "双肺纹理清晰,未见明显异常",
"images_count": 120,
"file_size": "256MB"
},
{
"study_id": "ST002",
"modality": "ECG",
"body_part": "心脏",
"study_date": "2024-07-20",
"description": "12导联心电图",
"cardiologist": "心内科-李医生",
"report": "窦性心律,心率78次/分,ST段轻度压低",
"images_count": 1,
"file_size": "2MB"
}
]
}
def validate_data_quality(self, patient_data: Dict[str, Any]):
"""验证数据质量"""
quality_report = {
"overall_score": 0,
"completeness": self.check_completeness(patient_data),
"accuracy": self.check_accuracy(patient_data),
"consistency": self.check_consistency(patient_data),
"timeliness": self.check_timeliness(patient_data),
"issues": []
}
# 计算总体质量评分
scores = [
quality_report["completeness"]["score"],
quality_report["accuracy"]["score"],
quality_report["consistency"]["score"],
quality_report["timeliness"]["score"]
]
quality_report["overall_score"] = sum(scores) / len(scores)
return quality_report
def check_completeness(self, patient_data: Dict[str, Any]):
"""检查数据完整性"""
required_fields = [
"basic_info.patient_id",
"basic_info.name",
"basic_info.gender",
"basic_info.age"
]
missing_fields = []
for field in required_fields:
if not self.get_nested_value(patient_data, field):
missing_fields.append(field)
completeness_score = (len(required_fields) - len(missing_fields)) / len(required_fields) * 100
return {
"score": completeness_score,
"missing_fields": missing_fields,
"total_fields": len(required_fields),
"complete_fields": len(required_fields) - len(missing_fields)
}
def check_accuracy(self, patient_data: Dict[str, Any]):
"""检查数据准确性"""
accuracy_issues = []
# 检查年龄与出生日期的一致性
if patient_data.get("basic_info"):
birth_date = patient_data["basic_info"].get("birth_date")
age = patient_data["basic_info"].get("age")
if birth_date and age:
calculated_age = self.calculate_age(birth_date)
if abs(calculated_age - age) > 1:
accuracy_issues.append("年龄与出生日期不一致")
# 检查检验结果的合理性
if patient_data.get("lab_results"):
lab_results = patient_data["lab_results"]
for test_type, test_data in lab_results.items():
if "results" in test_data:
for item, result in test_data["results"].items():
if result["status"] in ["异常", "危急"]:
accuracy_issues.append(f"{item}检验结果异常")
accuracy_score = max(0, 100 - len(accuracy_issues) * 10)
return {
"score": accuracy_score,
"issues": accuracy_issues,
"total_checks": 10,
"passed_checks": 10 - len(accuracy_issues)
}
def check_consistency(self, patient_data: Dict[str, Any]):
"""检查数据一致性"""
consistency_issues = []
# 检查用药与诊断的一致性
if patient_data.get("medical_history") and patient_data.get("medications"):
diagnoses = [d["disease_name"] for d in patient_data["medical_history"].get("chronic_diseases", [])]
medications = patient_data["medications"].get("current_medications", [])
for med in medications:
indication = med.get("indication", "")
if indication and indication not in diagnoses:
consistency_issues.append(f"用药适应症{indication}与诊断不一致")
consistency_score = max(0, 100 - len(consistency_issues) * 15)
return {
"score": consistency_score,
"issues": consistency_issues,
"total_checks": 5,
"passed_checks": 5 - len(consistency_issues)
}
def check_timeliness(self, patient_data: Dict[str, Any]):
"""检查数据及时性"""
timeliness_issues = []
current_date = datetime.datetime.now().date()
# 检查检验结果的时效性
if patient_data.get("lab_results"):
for test_type, test_data in patient_data["lab_results"].items():
test_date_str = test_data.get("test_date")
if test_date_str:
test_date = datetime.datetime.strptime(test_date_str, "%Y-%m-%d").date()
days_diff = (current_date - test_date).days
if days_diff > 30:
timeliness_issues.append(f"{test_type}检验结果过期({days_diff}天)")
timeliness_score = max(0, 100 - len(timeliness_issues) * 20)
return {
"score": timeliness_score,
"issues": timeliness_issues,
"total_checks": 3,
"passed_checks": 3 - len(timeliness_issues)
}
def get_nested_value(self, data: Dict, path: str):
"""获取嵌套字典的值"""
keys = path.split('.')
current = data
for key in keys:
if isinstance(current, dict) and key in current:
current = current[key]
else:
return None
return current
def calculate_age(self, birth_date_str: str):
"""计算年龄"""
birth_date = datetime.datetime.strptime(birth_date_str, "%Y-%m-%d").date()
today = datetime.date.today()
age = today.year - birth_date.year - ((today.month, today.day) < (birth_date.month, birth_date.day))
return age
def generate_collection_report(self, collection_results: List[Dict]):
"""生成采集报告"""
total_patients = len(collection_results)
successful_collections = len([r for r in collection_results if "data" in r])
failed_collections = total_patients - successful_collections
quality_scores = []
for result in collection_results:
if "data" in result and "quality_report" in result:
quality_scores.append(result["quality_report"]["overall_score"])
avg_quality_score = sum(quality_scores) / len(quality_scores) if quality_scores else 0
return {
"collection_summary": {
"total_patients": total_patients,
"successful_collections": successful_collections,
"failed_collections": failed_collections,
"success_rate": successful_collections / total_patients * 100 if total_patients > 0 else 0
},
"quality_summary": {
"average_quality_score": avg_quality_score,
"high_quality_count": len([s for s in quality_scores if s >= 90]),
"medium_quality_count": len([s for s in quality_scores if 70 <= s < 90]),
"low_quality_count": len([s for s in quality_scores if s < 70])
},
"recommendations": self.generate_collection_recommendations(collection_results)
}
def generate_collection_recommendations(self, collection_results: List[Dict]):
"""生成采集建议"""
recommendations = []
# 分析失败原因
failed_results = [r for r in collection_results if "error" in r]
if failed_results:
recommendations.append("检查数据源连接状态,解决采集失败问题")
# 分析质量问题
quality_issues = []
for result in collection_results:
if "quality_report" in result:
quality_report = result["quality_report"]
if quality_report["overall_score"] < 80:
quality_issues.extend(quality_report["issues"])
if quality_issues:
recommendations.append("改进数据质量控制流程,解决数据质量问题")
if not recommendations:
recommendations.append("数据采集状态良好,继续保持")
return recommendations
# 创建数据采集器实例
data_collector = MedicalDataCollector()
# 示例:采集患者数据
patient_ids = ["P001", "P002", "P003"]
collection_results = []
print("=== 医疗数据采集示例 ===\n")
for patient_id in patient_ids:
print(f"📊 采集患者 {patient_id} 的数据...")
result = data_collector.collect_patient_data(patient_id)
collection_results.append(result)
if "data" in result:
quality_score = result["quality_report"]["overall_score"]
print(f" ✅ 采集成功,数据质量评分: {quality_score:.1f}")
else:
print(f" ❌ 采集失败: {result.get('error', '未知错误')}")
# 生成采集报告
print(f"\n📋 数据采集报告:")
report = data_collector.generate_collection_report(collection_results)
print(f" 总患者数: {report['collection_summary']['total_patients']}")
print(f" 成功采集: {report['collection_summary']['successful_collections']}")
print(f" 成功率: {report['collection_summary']['success_rate']:.1f}%")
print(f" 平均质量评分: {report['quality_summary']['average_quality_score']:.1f}")
print(f" 建议: {', '.join(report['recommendations'])}")
5. 患者数据可视化分析
5.1 患者画像分析
/**
* 患者数据可视化分析模块
*/
class PatientDataAnalyzer {
constructor() {
this.charts = new Map();
this.patientData = [];
this.analysisConfig = this.initAnalysisConfig();
this.colorScheme = this.initColorScheme();
}
/**
* 初始化分析配置
*/
initAnalysisConfig() {
return {
ageGroups: [
{ name: '儿童', min: 0, max: 14, color: '#74b9ff' },
{ name: '青少年', min: 15, max: 24, color: '#0984e3' },
{ name: '青年', min: 25, max: 44, color: '#00b894' },
{ name: '中年', min: 45, max: 64, color: '#fdcb6e' },
{ name: '老年', min: 65, max: 120, color: '#e17055' }
],
diseaseCategories: [
{ name: '心血管疾病', code: 'CVD', color: '#e74c3c' },
{ name: '糖尿病', code: 'DM', color: '#f39c12' },
{ name: '呼吸系统疾病', code: 'RD', color: '#3498db' },
{ name: '消化系统疾病', code: 'GD', color: '#2ecc71' },
{ name: '神经系统疾病', code: 'ND', color: '#9b59b6' },
{ name: '肿瘤', code: 'TUMOR', color: '#34495e' }
],
riskLevels: [
{ name: '低风险', threshold: 30, color: '#00ff88' },
{ name: '中风险', threshold: 60, color: '#ffd93d' },
{ name: '高风险', threshold: 80, color: '#ff6b6b' },
{ name: '极高风险', threshold: 100, color: '#c44569' }
]
};
}
/**
* 初始化颜色方案
*/
initColorScheme() {
return {
primary: '#1e3c72',
secondary: '#2a5298',
accent: '#00d4ff',
success: '#00ff88',
warning: '#ffd93d',
danger: '#ff6b6b',
info: '#74b9ff',
light: '#f8f9fa',
dark: '#343a40'
};
}
/**
* 创建患者年龄分布图
*/
createAgeDistributionChart(containerId, patientData) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
// 统计年龄分布
const ageDistribution = this.calculateAgeDistribution(patientData);
const option = {
backgroundColor: 'transparent',
title: {
text: '患者年龄分布',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 16,
fontWeight: 'bold'
}
},
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
textStyle: {
color: '#ffffff'
},
formatter: function(params) {
return `${params.name}<br/>
患者数量: ${params.value}人<br/>
占比: ${params.percent}%`;
}
},
legend: {
orient: 'vertical',
left: 'left',
top: 'middle',
textStyle: {
color: '#ffffff',
fontSize: 12
}
},
series: [{
name: '年龄分布',
type: 'pie',
radius: ['40%', '70%'],
center: ['60%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 8,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false
},
emphasis: {
label: {
show: true,
fontSize: '14',
fontWeight: 'bold',
color: '#ffffff'
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
data: ageDistribution.map(item => ({
name: item.name,
value: item.count,
itemStyle: {
color: item.color
}
}))
}]
};
chart.setOption(option);
this.charts.set(containerId, chart);
return chart;
}
/**
* 创建疾病分布图
*/
createDiseaseDistributionChart(containerId, patientData) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
// 统计疾病分布
const diseaseDistribution = this.calculateDiseaseDistribution(patientData);
const option = {
backgroundColor: 'transparent',
title: {
text: '疾病分布统计',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 16
}
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
textStyle: {
color: '#ffffff'
},
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: diseaseDistribution.map(item => item.name),
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
axisLabel: {
color: '#ffffff',
rotate: 45
}
},
yAxis: {
type: 'value',
name: '患者数量',
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
axisLabel: {
color: '#ffffff'
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
series: [{
name: '患者数量',
type: 'bar',
barWidth: '60%',
data: diseaseDistribution.map((item, index) => ({
value: item.count,
itemStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: item.color },
{ offset: 1, color: this.adjustColorOpacity(item.color, 0.6) }
]
},
borderRadius: [4, 4, 0, 0]
}
}))
}]
};
chart.setOption(option);
this.charts.set(containerId, chart);
return chart;
}
/**
* 创建患者风险评估雷达图
*/
createRiskAssessmentChart(containerId, patientData) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
// 计算风险评估数据
const riskAssessment = this.calculateRiskAssessment(patientData);
const indicators = [
{ name: '年龄风险', max: 100 },
{ name: '疾病风险', max: 100 },
{ name: '用药风险', max: 100 },
{ name: '生活方式风险', max: 100 },
{ name: '遗传风险', max: 100 },
{ name: '环境风险', max: 100 }
];
const option = {
backgroundColor: 'transparent',
title: {
text: '患者风险评估',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 16
}
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
textStyle: {
color: '#ffffff'
}
},
radar: {
indicator: indicators,
center: ['50%', '55%'],
radius: '70%',
axisName: {
color: '#ffffff',
fontSize: 12
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.2)'
}
},
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
splitArea: {
show: true,
areaStyle: {
color: [
'rgba(0, 255, 136, 0.1)',
'rgba(255, 217, 61, 0.1)',
'rgba(255, 107, 107, 0.1)',
'rgba(196, 69, 105, 0.1)'
]
}
}
},
series: [{
name: '风险评估',
type: 'radar',
data: riskAssessment.map(patient => ({
value: [
patient.ageRisk,
patient.diseaseRisk,
patient.medicationRisk,
patient.lifestyleRisk,
patient.geneticRisk,
patient.environmentRisk
],
name: patient.name,
areaStyle: {
color: this.getRiskColor(patient.overallRisk),
opacity: 0.3
},
lineStyle: {
color: this.getRiskColor(patient.overallRisk),
width: 2
},
symbol: 'circle',
symbolSize: 5
}))
}]
};
chart.setOption(option);
this.charts.set(containerId, chart);
return chart;
}
/**
* 创建医疗费用分析图
*/
createMedicalCostChart(containerId, patientData) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
// 计算医疗费用数据
const costData = this.calculateMedicalCosts(patientData);
const option = {
backgroundColor: 'transparent',
title: {
text: '医疗费用构成分析',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 16
}
},
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
textStyle: {
color: '#ffffff'
},
formatter: function(params) {
return `${params.name}<br/>
费用: ¥${params.value.toLocaleString()}<br/>
占比: ${params.percent}%`;
}
},
legend: {
orient: 'vertical',
left: 'left',
top: 'middle',
textStyle: {
color: '#ffffff',
fontSize: 12
}
},
series: [{
name: '医疗费用',
type: 'pie',
radius: ['30%', '60%'],
center: ['60%', '50%'],
roseType: 'area',
itemStyle: {
borderRadius: 5,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
color: '#ffffff',
formatter: '{b}: {c}'
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
data: costData
}]
};
chart.setOption(option);
this.charts.set(containerId, chart);
return chart;
}
/**
* 创建就诊趋势图
*/
createVisitTrendChart(containerId, visitData) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
const option = {
backgroundColor: 'transparent',
title: {
text: '就诊趋势分析',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 16
}
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
textStyle: {
color: '#ffffff'
},
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['门诊', '急诊', '住院'],
top: '10%',
textStyle: {
color: '#ffffff'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: visitData.dates,
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
axisLabel: {
color: '#ffffff'
}
},
yAxis: {
type: 'value',
name: '就诊人数',
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
axisLabel: {
color: '#ffffff'
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
series: [
{
name: '门诊',
type: 'line',
smooth: true,
lineStyle: {
color: this.colorScheme.success,
width: 3
},
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: this.adjustColorOpacity(this.colorScheme.success, 0.8) },
{ offset: 1, color: this.adjustColorOpacity(this.colorScheme.success, 0.1) }
]
}
},
data: visitData.outpatient
},
{
name: '急诊',
type: 'line',
smooth: true,
lineStyle: {
color: this.colorScheme.warning,
width: 3
},
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: this.adjustColorOpacity(this.colorScheme.warning, 0.8) },
{ offset: 1, color: this.adjustColorOpacity(this.colorScheme.warning, 0.1) }
]
}
},
data: visitData.emergency
},
{
name: '住院',
type: 'line',
smooth: true,
lineStyle: {
color: this.colorScheme.danger,
width: 3
},
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: this.adjustColorOpacity(this.colorScheme.danger, 0.8) },
{ offset: 1, color: this.adjustColorOpacity(this.colorScheme.danger, 0.1) }
]
}
},
data: visitData.inpatient
}
]
};
chart.setOption(option);
this.charts.set(containerId, chart);
return chart;
}
/**
* 计算年龄分布
*/
calculateAgeDistribution(patientData) {
const distribution = this.analysisConfig.ageGroups.map(group => ({
name: group.name,
count: 0,
color: group.color
}));
patientData.forEach(patient => {
const age = patient.age || 0;
const group = this.analysisConfig.ageGroups.find(g => age >= g.min && age <= g.max);
if (group) {
const index = distribution.findIndex(d => d.name === group.name);
if (index !== -1) {
distribution[index].count++;
}
}
});
return distribution;
}
/**
* 计算疾病分布
*/
calculateDiseaseDistribution(patientData) {
const distribution = this.analysisConfig.diseaseCategories.map(category => ({
name: category.name,
count: 0,
color: category.color
}));
patientData.forEach(patient => {
if (patient.diagnoses) {
patient.diagnoses.forEach(diagnosis => {
const category = this.categorizeDisease(diagnosis);
const index = distribution.findIndex(d => d.name === category);
if (index !== -1) {
distribution[index].count++;
}
});
}
});
return distribution.filter(d => d.count > 0);
}
/**
* 计算风险评估
*/
calculateRiskAssessment(patientData) {
return patientData.slice(0, 5).map(patient => ({
name: patient.name || '患者',
ageRisk: this.calculateAgeRisk(patient.age),
diseaseRisk: this.calculateDiseaseRisk(patient.diagnoses),
medicationRisk: this.calculateMedicationRisk(patient.medications),
lifestyleRisk: this.calculateLifestyleRisk(patient.lifestyle),
geneticRisk: this.calculateGeneticRisk(patient.familyHistory),
environmentRisk: this.calculateEnvironmentRisk(patient.environment),
overallRisk: this.calculateOverallRisk(patient)
}));
}
/**
* 计算医疗费用
*/
calculateMedicalCosts(patientData) {
const costCategories = [
{ name: '药品费用', value: 0, color: '#e74c3c' },
{ name: '检查费用', value: 0, color: '#3498db' },
{ name: '治疗费用', value: 0, color: '#2ecc71' },
{ name: '手术费用', value: 0, color: '#f39c12' },
{ name: '床位费用', value: 0, color: '#9b59b6' },
{ name: '其他费用', value: 0, color: '#34495e' }
];
// 模拟费用计算
costCategories[0].value = 125000; // 药品费用
costCategories[1].value = 85000; // 检查费用
costCategories[2].value = 95000; // 治疗费用
costCategories[3].value = 180000; // 手术费用
costCategories[4].value = 45000; // 床位费用
costCategories[5].value = 25000; // 其他费用
return costCategories.map(category => ({
name: category.name,
value: category.value,
itemStyle: {
color: category.color
}
}));
}
/**
* 疾病分类
*/
categorizeDisease(diagnosis) {
const diseaseMap = {
'高血压': '心血管疾病',
'冠心病': '心血管疾病',
'心律失常': '心血管疾病',
'糖尿病': '糖尿病',
'肺炎': '呼吸系统疾病',
'哮喘': '呼吸系统疾病',
'胃炎': '消化系统疾病',
'肝炎': '消化系统疾病',
'脑梗': '神经系统疾病',
'癫痫': '神经系统疾病',
'肺癌': '肿瘤',
'胃癌': '肿瘤'
};
return diseaseMap[diagnosis] || '其他疾病';
}
/**
* 计算各种风险评分
*/
calculateAgeRisk(age) {
if (age < 18) return 10;
if (age < 40) return 20;
if (age < 60) return 40;
if (age < 80) return 70;
return 90;
}
calculateDiseaseRisk(diagnoses) {
if (!diagnoses || diagnoses.length === 0) return 10;
return Math.min(90, diagnoses.length * 20 + 30);
}
calculateMedicationRisk(medications) {
if (!medications || medications.length === 0) return 10;
return Math.min(80, medications.length * 15 + 20);
}
calculateLifestyleRisk(lifestyle) {
// 模拟生活方式风险计算
return Math.random() * 60 + 20;
}
calculateGeneticRisk(familyHistory) {
if (!familyHistory || familyHistory.length === 0) return 20;
return Math.min(70, familyHistory.length * 25 + 25);
}
calculateEnvironmentRisk(environment) {
// 模拟环境风险计算
return Math.random() * 50 + 25;
}
calculateOverallRisk(patient) {
const risks = [
this.calculateAgeRisk(patient.age),
this.calculateDiseaseRisk(patient.diagnoses),
this.calculateMedicationRisk(patient.medications),
this.calculateLifestyleRisk(patient.lifestyle),
this.calculateGeneticRisk(patient.familyHistory),
this.calculateEnvironmentRisk(patient.environment)
];
return risks.reduce((sum, risk) => sum + risk, 0) / risks.length;
}
/**
* 获取风险颜色
*/
getRiskColor(riskScore) {
if (riskScore < 30) return this.colorScheme.success;
if (riskScore < 60) return this.colorScheme.warning;
if (riskScore < 80) return this.colorScheme.danger;
return '#c44569';
}
/**
* 调整颜色透明度
*/
adjustColorOpacity(color, opacity) {
// 简化的颜色透明度调整
if (color.startsWith('#')) {
const r = parseInt(color.slice(1, 3), 16);
const g = parseInt(color.slice(3, 5), 16);
const b = parseInt(color.slice(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
}
return color;
}
/**
* 调整图表大小
*/
resize() {
this.charts.forEach(chart => {
chart.resize();
});
}
/**
* 销毁所有图表
*/
dispose() {
this.charts.forEach(chart => {
chart.dispose();
});
this.charts.clear();
}
}
// 创建患者数据分析器实例
const patientAnalyzer = new PatientDataAnalyzer();
// 模拟患者数据
const mockPatientData = [
{
id: 'P001',
name: '张三',
age: 45,
gender: '男',
diagnoses: ['高血压', '糖尿病'],
medications: ['氨氯地平', '二甲双胍'],
familyHistory: ['高血压', '糖尿病']
},
{
id: 'P002',
name: '李四',
age: 32,
gender: '女',
diagnoses: ['哮喘'],
medications: ['沙丁胺醇'],
familyHistory: []
},
{
id: 'P003',
name: '王五',
age: 68,
gender: '男',
diagnoses: ['冠心病', '高血压'],
medications: ['阿司匹林', '氨氯地平', '阿托伐他汀'],
familyHistory: ['冠心病']
}
];
// 模拟就诊趋势数据
const mockVisitData = {
dates: ['1月', '2月', '3月', '4月', '5月', '6月'],
outpatient: [1200, 1350, 1180, 1420, 1380, 1500],
emergency: [180, 220, 160, 240, 200, 190],
inpatient: [320, 380, 290, 410, 360, 420]
};
// 页面加载完成后创建图表
document.addEventListener('DOMContentLoaded', () => {
// 创建年龄分布图
if (document.getElementById('ageDistributionChart')) {
patientAnalyzer.createAgeDistributionChart('ageDistributionChart', mockPatientData);
}
// 创建疾病分布图
if (document.getElementById('diseaseDistributionChart')) {
patientAnalyzer.createDiseaseDistributionChart('diseaseDistributionChart', mockPatientData);
}
// 创建风险评估图
if (document.getElementById('riskAssessmentChart')) {
patientAnalyzer.createRiskAssessmentChart('riskAssessmentChart', mockPatientData);
}
// 创建医疗费用图
if (document.getElementById('medicalCostChart')) {
patientAnalyzer.createMedicalCostChart('medicalCostChart', mockPatientData);
}
// 创建就诊趋势图
if (document.getElementById('visitTrendChart')) {
patientAnalyzer.createVisitTrendChart('visitTrendChart', mockVisitData);
}
});
// 窗口大小变化时调整图表
window.addEventListener('resize', () => {
patientAnalyzer.resize();
});
6. 医疗指标监控系统
6.1 关键指标监控
# 医疗指标监控系统
import datetime
import json
from typing import Dict, List, Any, Optional
import numpy as np
import pandas as pd
class MedicalIndicatorMonitor:
"""医疗指标监控系统"""
def __init__(self):
self.indicators = self.define_medical_indicators()
self.alert_rules = self.define_alert_rules()
self.monitoring_config = self.define_monitoring_config()
self.historical_data = {}
self.current_alerts = []
def define_medical_indicators(self):
"""定义医疗指标"""
return {
"患者安全指标": {
"院内感染率": {
"计算公式": "院内感染人数 / 住院总人数 × 100%",
"目标值": "< 3%",
"预警阈值": "> 2.5%",
"危险阈值": "> 4%",
"监控频率": "日",
"数据源": "HIS",
"责任科室": "感控科",
"权重": 0.25
},
"药物不良反应率": {
"计算公式": "药物不良反应人数 / 用药总人数 × 100%",
"目标值": "< 1%",
"预警阈值": "> 0.8%",
"危险阈值": "> 1.5%",
"监控频率": "日",
"数据源": "HIS+药房系统",
"责任科室": "药剂科",
"权重": 0.2
},
"手术并发症率": {
"计算公式": "手术并发症人数 / 手术总人数 × 100%",
"目标值": "< 2%",
"预警阈值": "> 1.5%",
"危险阈值": "> 3%",
"监控频率": "日",
"数据源": "手术系统",
"责任科室": "外科",
"权重": 0.25
},
"跌倒发生率": {
"计算公式": "跌倒事件数 / 住院总人数 × 1000‰",
"目标值": "< 3‰",
"预警阈值": "> 2.5‰",
"危险阈值": "> 4‰",
"监控频率": "日",
"数据源": "护理系统",
"责任科室": "护理部",
"权重": 0.15
},
"压疮发生率": {
"计算公式": "压疮发生人数 / 住院总人数 × 100%",
"目标值": "< 1%",
"预警阈值": "> 0.8%",
"危险阈值": "> 1.5%",
"监控频率": "日",
"数据源": "护理系统",
"责任科室": "护理部",
"权重": 0.15
}
},
"医疗质量指标": {
"平均住院日": {
"计算公式": "总住院天数 / 出院人数",
"目标值": "< 10天",
"预警阈值": "> 12天",
"危险阈值": "> 15天",
"监控频率": "日",
"数据源": "HIS",
"责任科室": "医务科",
"权重": 0.2
},
"床位使用率": {
"计算公式": "实际占用床日数 / 开放床日数 × 100%",
"目标值": "85%-95%",
"预警阈值": "< 80% 或 > 98%",
"危险阈值": "< 70% 或 > 100%",
"监控频率": "日",
"数据源": "HIS",
"责任科室": "医务科",
"权重": 0.15
},
"床位周转次数": {
"计算公式": "出院人数 / 平均开放床位数",
"目标值": "> 30次/年",
"预警阈值": "< 25次/年",
"危险阈值": "< 20次/年",
"监控频率": "月",
"数据源": "HIS",
"责任科室": "医务科",
"权重": 0.1
},
"门诊预约率": {
"计算公式": "预约门诊人数 / 门诊总人数 × 100%",
"目标值": "> 80%",
"预警阈值": "< 70%",
"危险阈值": "< 60%",
"监控频率": "日",
"数据源": "门诊系统",
"责任科室": "门诊部",
"权重": 0.1
},
"检查报告及时率": {
"计算公式": "及时出具报告数 / 检查总数 × 100%",
"目标值": "> 95%",
"预警阈值": "< 90%",
"危险阈值": "< 85%",
"监控频率": "日",
"数据源": "LIS+PACS",
"责任科室": "检验科+影像科",
"权重": 0.15
},
"手术按时开台率": {
"计算公式": "按时开台手术数 / 计划手术总数 × 100%",
"目标值": "> 90%",
"预警阈值": "< 85%",
"危险阈值": "< 80%",
"监控频率": "日",
"数据源": "手术系统",
"责任科室": "手术室",
"权重": 0.15
},
"急诊抢救成功率": {
"计算公式": "抢救成功人数 / 抢救总人数 × 100%",
"目标值": "> 85%",
"预警阈值": "< 80%",
"危险阈值": "< 75%",
"监控频率": "日",
"数据源": "急诊系统",
"责任科室": "急诊科",
"权重": 0.15
}
},
"服务质量指标": {
"患者满意度": {
"计算公式": "满意患者数 / 调查患者数 × 100%",
"目标值": "> 90%",
"预警阈值": "< 85%",
"危险阈值": "< 80%",
"监控频率": "月",
"数据源": "满意度调查系统",
"责任科室": "客服部",
"权重": 0.3
},
"投诉处理及时率": {
"计算公式": "及时处理投诉数 / 投诉总数 × 100%",
"目标值": "> 95%",
"预警阈值": "< 90%",
"危险阈值": "< 85%",
"监控频率": "日",
"数据源": "投诉管理系统",
"责任科室": "客服部",
"权重": 0.2
},
"平均候诊时间": {
"计算公式": "总候诊时间 / 门诊人数",
"目标值": "< 30分钟",
"预警阈值": "> 45分钟",
"危险阈值": "> 60分钟",
"监控频率": "日",
"数据源": "门诊系统",
"责任科室": "门诊部",
"权重": 0.25
},
"医生平均接诊时间": {
"计算公式": "总接诊时间 / 接诊人数",
"目标值": "> 8分钟",
"预警阈值": "< 6分钟",
"危险阈值": "< 5分钟",
"监控频率": "日",
"数据源": "门诊系统",
"责任科室": "门诊部",
"权重": 0.15
},
"护理满意度": {
"计算公式": "护理满意患者数 / 调查患者数 × 100%",
"目标值": "> 95%",
"预警阈值": "< 90%",
"危险阈值": "< 85%",
"监控频率": "月",
"数据源": "满意度调查系统",
"责任科室": "护理部",
"权重": 0.1
}
},
"经济效益指标": {
"人均医疗费用": {
"计算公式": "总医疗费用 / 患者总数",
"目标值": "合理区间",
"预警阈值": "偏离合理区间20%",
"危险阈值": "偏离合理区间40%",
"监控频率": "月",
"数据源": "财务系统",
"责任科室": "财务科",
"权重": 0.2
},
"药占比": {
"计算公式": "药品费用 / 医疗总费用 × 100%",
"目标值": "< 30%",
"预警阈值": "> 32%",
"危险阈值": "> 35%",
"监控频率": "月",
"数据源": "财务系统+药房系统",
"责任科室": "药剂科",
"权重": 0.25
},
"耗材占比": {
"计算公式": "耗材费用 / 医疗总费用 × 100%",
"目标值": "< 20%",
"预警阈值": "> 22%",
"危险阈值": "> 25%",
"监控频率": "月",
"数据源": "财务系统+物资系统",
"责任科室": "设备科",
"权重": 0.15
},
"医疗收入增长率": {
"计算公式": "(本期收入-上期收入) / 上期收入 × 100%",
"目标值": "> 5%",
"预警阈值": "< 3%",
"危险阈值": "< 0%",
"监控频率": "月",
"数据源": "财务系统",
"责任科室": "财务科",
"权重": 0.2
},
"成本控制率": {
"计算公式": "实际成本 / 预算成本 × 100%",
"目标值": "95%-105%",
"预警阈值": "< 90% 或 > 110%",
"危险阈值": "< 85% 或 > 115%",
"监控频率": "月",
"数据源": "财务系统",
"责任科室": "财务科",
"权重": 0.2
}
}
}
def define_alert_rules(self):
"""定义预警规则"""
return {
"预警级别": {
"绿色": {
"描述": "指标正常",
"触发条件": "所有指标在目标范围内",
"处理措施": "常规监控",
"通知方式": "无需通知",
"响应时间": "无",
"颜色代码": "#00ff88"
},
"黄色": {
"描述": "需要关注",
"触发条件": "单项指标达到预警阈值",
"处理措施": "加强监控,分析原因",
"通知方式": "系统提醒",
"响应时间": "4小时内",
"颜色代码": "#ffd93d"
},
"橙色": {
"描述": "风险较高",
"触发条件": "多项指标达到预警阈值或单项达到危险阈值",
"处理措施": "立即分析,制定改进方案",
"通知方式": "邮件+短信",
"响应时间": "2小时内",
"颜色代码": "#ff9f43"
},
"红色": {
"描述": "高风险",
"触发条件": "多项指标达到危险阈值",
"处理措施": "紧急处理,启动应急预案",
"通知方式": "电话+邮件+短信",
"响应时间": "30分钟内",
"颜色代码": "#ff6b6b"
}
},
"自动化处理": {
"数据收集": {
"频率": "实时/小时/日/月",
"来源": "多系统自动采集",
"验证": "数据质量检查",
"存储": "时序数据库"
},
"指标计算": {
"引擎": "实时计算引擎",
"规则": "可配置计算规则",
"缓存": "计算结果缓存",
"更新": "增量更新机制"
},
"阈值监控": {
"检查": "持续阈值检查",
"比较": "多维度比较分析",
"趋势": "趋势变化监控",
"预测": "异常预测算法"
},
"预警触发": {
"规则": "多级预警规则",
"去重": "重复预警过滤",
"升级": "预警级别升级",
"记录": "预警历史记录"
}
}
}
def define_monitoring_config(self):
"""定义监控配置"""
return {
"监控策略": {
"实时监控": {
"指标": [
"院内感染率",
"药物不良反应率",
"手术并发症率",
"床位使用率"
],
"频率": "每5分钟",
"数据延迟": "< 1分钟",
"存储周期": "7天"
},
"小时监控": {
"指标": [
"门诊预约率",
"检查报告及时率",
"平均候诊时间",
"急诊抢救成功率"
],
"频率": "每小时",
"数据延迟": "< 5分钟",
"存储周期": "30天"
},
"日度监控": {
"指标": [
"平均住院日",
"手术按时开台率",
"投诉处理及时率",
"医生平均接诊时间"
],
"频率": "每日",
"数据延迟": "< 30分钟",
"存储周期": "1年"
},
"月度监控": {
"指标": [
"患者满意度",
"护理满意度",
"药占比",
"医疗收入增长率"
],
"频率": "每月",
"数据延迟": "< 1天",
"存储周期": "5年"
}
},
"数据源配置": {
"HIS系统": {
"连接方式": "数据库直连",
"更新频率": "实时",
"数据表": [
"患者信息表",
"入出院记录表",
"门诊记录表",
"医嘱表"
]
},
"LIS系统": {
"连接方式": "API接口",
"更新频率": "实时",
"数据接口": [
"检验结果接口",
"报告状态接口",
"质控数据接口"
]
},
"财务系统": {
"连接方式": "ETL同步",
"更新频率": "每日",
"数据范围": [
"收入数据",
"成本数据",
"费用明细"
]
}
},
"报告配置": {
"实时监控报告": {
"生成频率": "实时",
"包含内容": [
"关键指标状态",
"异常预警信息",
"趋势变化图表"
],
"发送对象": ["值班医生", "护士长", "科主任"]
},
"日度质量报告": {
"生成时间": "每日8:00",
"包含内容": [
"昨日指标汇总",
"异常情况分析",
"改进建议"
],
"发送对象": ["医务科", "护理部", "质控科"]
},
"周度分析报告": {
"生成时间": "每周一9:00",
"包含内容": [
"周度指标趋势",
"科室对比分析",
"质量改进跟踪"
],
"发送对象": ["院领导", "科主任", "护士长"]
},
"月度综合报告": {
"生成时间": "每月1日",
"包含内容": [
"月度指标评估",
"质量改进成效",
"下月工作重点"
],
"发送对象": ["院长", "副院长", "质控委员会"]
}
}
}
def calculate_indicator_value(self, indicator_name: str, data: Dict[str, Any]) -> float:
"""计算指标值"""
calculation_rules = {
"院内感染率": lambda d: (d.get("院内感染人数", 0) / max(d.get("住院总人数", 1), 1)) * 100,
"药物不良反应率": lambda d: (d.get("药物不良反应人数", 0) / max(d.get("用药总人数", 1), 1)) * 100,
"手术并发症率": lambda d: (d.get("手术并发症人数", 0) / max(d.get("手术总人数", 1), 1)) * 100,
"平均住院日": lambda d: d.get("总住院天数", 0) / max(d.get("出院人数", 1), 1),
"床位使用率": lambda d: (d.get("实际占用床日数", 0) / max(d.get("开放床日数", 1), 1)) * 100,
"门诊预约率": lambda d: (d.get("预约门诊人数", 0) / max(d.get("门诊总人数", 1), 1)) * 100,
"患者满意度": lambda d: (d.get("满意患者数", 0) / max(d.get("调查患者数", 1), 1)) * 100,
"药占比": lambda d: (d.get("药品费用", 0) / max(d.get("医疗总费用", 1), 1)) * 100,
"医疗收入增长率": lambda d: ((d.get("本期收入", 0) - d.get("上期收入", 0)) / max(d.get("上期收入", 1), 1)) * 100
}
if indicator_name in calculation_rules:
try:
return calculation_rules[indicator_name](data)
except Exception as e:
print(f"计算指标 {indicator_name} 时出错: {e}")
return 0.0
else:
return data.get(indicator_name, 0.0)
def evaluate_indicator(self, indicator_name: str, value: float, category: str) -> Dict[str, Any]:
"""评估指标状态"""
if category not in self.indicators or indicator_name not in self.indicators[category]:
return {"status": "unknown", "level": "绿色", "message": "指标未定义"}
indicator_config = self.indicators[category][indicator_name]
target_value = indicator_config["目标值"]
warning_threshold = indicator_config["预警阈值"]
danger_threshold = indicator_config["危险阈值"]
# 判断指标状态
if self.meets_target(value, target_value):
return {
"status": "normal",
"level": "绿色",
"message": "指标正常",
"score": 100
}
elif self.exceeds_threshold(value, warning_threshold):
if self.exceeds_threshold(value, danger_threshold):
return {
"status": "danger",
"level": "红色",
"message": "指标严重异常",
"score": 30
}
else:
return {
"status": "warning",
"level": "橙色",
"message": "指标异常",
"score": 60
}
else:
return {
"status": "attention",
"level": "黄色",
"message": "指标需要关注",
"score": 80
}
def meets_target(self, value: float, target_str: str) -> bool:
"""检查是否达到目标值"""
try:
if '<' in target_str:
threshold = float(target_str.replace('<', '').replace('%', '').replace('天', '').replace('分钟', '').strip())
return value < threshold
elif '>' in target_str:
threshold = float(target_str.replace('>', '').replace('%', '').replace('天', '').replace('分钟', '').strip())
return value > threshold
elif '-' in target_str and '合理区间' not in target_str:
parts = target_str.replace('%', '').split('-')
min_val = float(parts[0].strip())
max_val = float(parts[1].strip())
return min_val <= value <= max_val
else:
return True # 对于"合理区间"等描述性目标,默认为达标
except:
return True
def exceeds_threshold(self, value: float, threshold_str: str) -> bool:
"""检查是否超过阈值"""
try:
if '>' in threshold_str:
threshold = float(threshold_str.replace('>', '').replace('%', '').replace('天', '').replace('分钟', '').strip())
return value > threshold
elif '<' in threshold_str:
threshold = float(threshold_str.replace('<', '').replace('%', '').replace('天', '').replace('分钟', '').strip())
return value < threshold
elif '或' in threshold_str:
# 处理类似 "< 80% 或 > 98%" 的情况
conditions = threshold_str.split('或')
return any(self.exceeds_threshold(value, cond.strip()) for cond in conditions)
elif '偏离合理区间' in threshold_str:
# 处理偏离百分比的情况
percentage = float(threshold_str.replace('偏离合理区间', '').replace('%', '').strip())
# 这里需要根据具体的合理区间来判断,简化处理
return abs(value - 100) > percentage # 假设合理区间中心值为100
else:
return False
except:
return False
def monitor_indicators(self, hospital_data: Dict[str, Any]) -> Dict[str, Any]:
"""监控所有指标"""
monitoring_result = {
"监控时间": datetime.datetime.now().isoformat(),
"医院名称": hospital_data.get("hospital_name", "未知医院"),
"指标评估": {},
"总体状态": "绿色",
"预警信息": [],
"改进建议": []
}
all_scores = []
alert_levels = []
# 遍历所有指标类别
for category, indicators in self.indicators.items():
monitoring_result["指标评估"][category] = {}
for indicator_name, indicator_config in indicators.items():
# 计算指标值
indicator_value = self.calculate_indicator_value(indicator_name, hospital_data)
# 评估指标状态
evaluation = self.evaluate_indicator(indicator_name, indicator_value, category)
# 记录评估结果
monitoring_result["指标评估"][category][indicator_name] = {
"当前值": indicator_value,
"目标值": indicator_config["目标值"],
"状态": evaluation["status"],
"级别": evaluation["level"],
"消息": evaluation["message"],
"评分": evaluation["score"],
"责任科室": indicator_config["责任科室"]
}
all_scores.append(evaluation["score"])
alert_levels.append(evaluation["level"])
# 生成预警信息
if evaluation["status"] != "normal":
alert = {
"指标名称": indicator_name,
"指标类别": category,
"当前值": indicator_value,
"预警级别": evaluation["level"],
"预警消息": evaluation["message"],
"责任科室": indicator_config["责任科室"],
"建议措施": self.get_improvement_suggestion(indicator_name, evaluation["status"])
}
monitoring_result["预警信息"].append(alert)
# 计算总体评分
overall_score = sum(all_scores) / len(all_scores) if all_scores else 100
# 确定总体状态
if "红色" in alert_levels:
monitoring_result["总体状态"] = "红色"
elif "橙色" in alert_levels:
monitoring_result["总体状态"] = "橙色"
elif "黄色" in alert_levels:
monitoring_result["总体状态"] = "黄色"
else:
monitoring_result["总体状态"] = "绿色"
monitoring_result["总体评分"] = overall_score
# 生成改进建议
monitoring_result["改进建议"] = self.generate_improvement_recommendations(monitoring_result["预警信息"])
return monitoring_result
def get_improvement_suggestion(self, indicator_name: str, status: str) -> str:
"""获取改进建议"""
suggestions = {
"院内感染率": {
"warning": "加强手卫生管理,完善感控制度",
"danger": "立即启动感控应急预案,全面排查感染源"
},
"药物不良反应率": {
"warning": "加强用药监测,完善ADR报告制度",
"danger": "立即审查用药安全,暂停可疑药物使用"
},
"手术并发症率": {
"warning": "加强术前评估,完善手术质量管理",
"danger": "立即审查手术流程,暂停高风险手术"
},
"平均住院日": {
"warning": "优化诊疗流程,加强出院管理",
"danger": "全面审查住院必要性,加快床位周转"
},
"患者满意度": {
"warning": "改善服务态度,优化就医流程",
"danger": "立即整改服务问题,加强患者沟通"
}
}
if indicator_name in suggestions and status in suggestions[indicator_name]:
return suggestions[indicator_name][status]
else:
return "请联系相关科室制定改进措施"
def generate_improvement_recommendations(self, alerts: List[Dict[str, Any]]) -> List[str]:
"""生成改进建议"""
recommendations = []
# 按科室分组预警
department_alerts = {}
for alert in alerts:
dept = alert["责任科室"]
if dept not in department_alerts:
department_alerts[dept] = []
department_alerts[dept].append(alert)
# 为每个科室生成建议
for dept, dept_alerts in department_alerts.items():
if len(dept_alerts) > 1:
recommendations.append(f"{dept}需要重点关注多项指标异常,建议制定综合改进方案")
else:
alert = dept_alerts[0]
recommendations.append(f"{dept}需要关注{alert['指标名称']},{alert['建议措施']}")
# 添加总体建议
if len(alerts) > 5:
recommendations.append("多项指标异常,建议启动质量改进专项行动")
elif len(alerts) == 0:
recommendations.append("所有指标正常,继续保持良好的医疗质量管理")
return recommendations
def generate_monitoring_report(self, monitoring_result: Dict[str, Any]) -> str:
"""生成监控报告"""
report = f"""
=== 医疗指标监控报告 ===
监控时间: {monitoring_result['监控时间']}
医院名称: {monitoring_result['医院名称']}
总体状态: {monitoring_result['总体状态']}
总体评分: {monitoring_result['总体评分']:.1f}
=== 指标评估详情 ===
"""
for category, indicators in monitoring_result["指标评估"].items():
report += f"\n【{category}】\n"
for indicator_name, result in indicators.items():
status_icon = {
"绿色": "✅",
"黄色": "⚠️",
"橙色": "🔶",
"红色": "❌"
}.get(result["级别"], "❓")
report += f" {status_icon} {indicator_name}: {result['当前值']:.2f} (目标: {result['目标值']}) - {result['消息']}\n"
if monitoring_result["预警信息"]:
report += f"\n=== 预警信息 ===\n"
for i, alert in enumerate(monitoring_result["预警信息"], 1):
report += f"{i}. 【{alert['预警级别']}】{alert['指标名称']}: {alert['预警消息']}\n"
report += f" 责任科室: {alert['责任科室']}\n"
report += f" 建议措施: {alert['建议措施']}\n\n"
if monitoring_result["改进建议"]:
report += f"=== 改进建议 ===\n"
for i, suggestion in enumerate(monitoring_result["改进建议"], 1):
report += f"{i}. {suggestion}\n"
return report
def save_monitoring_data(self, monitoring_result: Dict[str, Any]):
"""保存监控数据"""
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
hospital_name = monitoring_result.get("医院名称", "unknown")
# 保存到历史数据
if hospital_name not in self.historical_data:
self.historical_data[hospital_name] = []
self.historical_data[hospital_name].append({
"timestamp": timestamp,
"data": monitoring_result
})
# 保留最近30天的数据
cutoff_date = datetime.datetime.now() - datetime.timedelta(days=30)
cutoff_timestamp = cutoff_date.strftime("%Y%m%d_%H%M%S")
self.historical_data[hospital_name] = [
record for record in self.historical_data[hospital_name]
if record["timestamp"] >= cutoff_timestamp
]
def get_trend_analysis(self, hospital_name: str, indicator_name: str, days: int = 7) -> Dict[str, Any]:
"""获取趋势分析"""
if hospital_name not in self.historical_data:
return {"error": "没有历史数据"}
# 获取最近几天的数据
cutoff_date = datetime.datetime.now() - datetime.timedelta(days=days)
cutoff_timestamp = cutoff_date.strftime("%Y%m%d_%H%M%S")
recent_data = [
record for record in self.historical_data[hospital_name]
if record["timestamp"] >= cutoff_timestamp
]
if not recent_data:
return {"error": "没有足够的历史数据"}
# 提取指标值
values = []
timestamps = []
for record in recent_data:
# 在指标评估中查找指标值
for category, indicators in record["data"]["指标评估"].items():
if indicator_name in indicators:
values.append(indicators[indicator_name]["当前值"])
timestamps.append(record["timestamp"])
break
if not values:
return {"error": f"未找到指标 {indicator_name} 的数据"}
# 计算趋势
if len(values) >= 2:
trend = "上升" if values[-1] > values[0] else "下降" if values[-1] < values[0] else "稳定"
change_rate = ((values[-1] - values[0]) / values[0]) * 100 if values[0] != 0 else 0
else:
trend = "稳定"
change_rate = 0
return {
"indicator_name": indicator_name,
"period": f"最近{days}天",
"data_points": len(values),
"current_value": values[-1] if values else 0,
"initial_value": values[0] if values else 0,
"trend": trend,
"change_rate": change_rate,
"values": values,
"timestamps": timestamps
}
# 创建医疗指标监控器实例
indicator_monitor = MedicalIndicatorMonitor()
# 示例:监控医院指标
sample_hospital_data = {
"hospital_name": "第一人民医院",
"院内感染人数": 15,
"住院总人数": 800,
"药物不良反应人数": 5,
"用药总人数": 1200,
"手术并发症人数": 3,
"手术总人数": 150,
"总住院天数": 6800,
"出院人数": 680,
"实际占用床日数": 720,
"开放床日数": 800,
"预约门诊人数": 2400,
"门诊总人数": 3000,
"满意患者数": 450,
"调查患者数": 500,
"药品费用": 1500000,
"医疗总费用": 5000000,
"本期收入": 5200000,
"上期收入": 5000000
}
print("=== 医疗指标监控示例 ===\n")
# 执行监控
monitoring_result = indicator_monitor.monitor_indicators(sample_hospital_data)
# 生成报告
report = indicator_monitor.generate_monitoring_report(monitoring_result)
print(report)
# 保存监控数据
indicator_monitor.save_monitoring_data(monitoring_result)
# 趋势分析示例
trend_analysis = indicator_monitor.get_trend_analysis("第一人民医院", "院内感染率", 7)
if "error" not in trend_analysis:
print(f"\n=== 趋势分析 ===")
print(f"指标: {trend_analysis['indicator_name']}")
print(f"时间段: {trend_analysis['period']}")
print(f"趋势: {trend_analysis['trend']}")
print(f"变化率: {trend_analysis['change_rate']:.2f}%")