Python常用医疗AI库以及案例解析(2025年版、上)
随着人工智能在医疗领域的持续深入发展,Python 已经成为医疗 AI 项目的首选开发语言。从数据处理、模型训练、大模型集成到系统部署与可视化,Python 社区在过去几年中涌现出大量功能强大且持续演进的开源工具。本指南整理了在 2025 年医疗 AI 项目中广泛使用的 Python 库,涵盖了 机器学习、深度学习、大语言模型(LLM)、数据可视化、Web API 构建、Agent 自动化 等多个模块,
🔍 一、数据科学与机器学习
🤖 二、深度学习
torch.compile
支持,大幅提升训练速度。🌐 三、大语言模型 (LLM) 与 RAG
📊 四、数据可视化
🕸️ 五、Web开发 & API
🧠 六、自动化 & AI Agent
🛠 七、其他值得关注的工具库
练手案例
🧬 案例一、医学图像处理与分析
1. MONAI(Medical Open Network for AI)
专为医学影像(CT/MRI)打造的 PyTorch 库。
-
安装命令:
pip install monai nibabel
-
基本示例:加载并处理 MRI 图像
下面是一个医学图像处理示例,结合了数据加载、预处理、3D UNet模型构建和训练流程,使用MONAI库实现端到端的医学图像分割任务:
from monai.transforms import ( LoadImaged, AddChanneld, Spacingd, Orientationd, ScaleIntensityRanged, RandCropByPosNegLabeld, Compose, EnsureTyped)from monai.networks.nets import UNetfrom monai.losses import DiceLossfrom monai.metrics import DiceMetricfrom monai.data import Dataset, DataLoader, decollate_batchfrom monai.inferers import sliding_window_inferenceimport torchimport numpy as npimport matplotlib.pyplot as plt# 1. 数据准备与预处理data_dir = \"./medical_images/\"train_files = [ {\"image\": data_dir + \"patient1_CT.nii.gz\", \"label\": data_dir + \"patient1_mask.nii.gz\"}, {\"image\": data_dir + \"patient2_CT.nii.gz\", \"label\": data_dir + \"patient2_mask.nii.gz\"}, # 添加更多数据...]# 医学图像预处理流程train_transforms = Compose([ LoadImaged(keys=[\"image\", \"label\"]), AddChanneld(keys=[\"image\", \"label\"]), Spacingd( keys=[\"image\", \"label\"], pixdim=(1.0, 1.0, 2.0), # 调整体素间距 (x,y,z) mode=(\"bilinear\", \"nearest\") # 图像用双线性插值,标签用最近邻 ), Orientationd(keys=[\"image\", \"label\"], axcodes=\"RAS\"), # 统一方向 ScaleIntensityRanged( keys=[\"image\"], a_min=-1000, # CT值范围 (HU单位) a_max=1000, b_min=0.0, b_max=1.0, clip=True ), RandCropByPosNegLabeld( keys=[\"image\", \"label\"], label_key=\"label\", spatial_size=(96, 96, 64), # 3D裁剪大小 pos=1, neg=1, num_samples=4 # 每张图像生成4个样本 ), EnsureTyped(keys=[\"image\", \"label\"], dtype=torch.float32)])# 创建数据集和数据加载器train_ds = Dataset(data=train_files, transform=train_transforms)train_loader = DataLoader(train_ds, batch_size=2, shuffle=True)# 2. 构建3D分割模型device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")model = UNet( spatial_dims=3, in_channels=1, out_channels=2, # 两类分割:背景+器官 channels=(16, 32, 64, 128, 256), strides=(2, 2, 2, 2), num_res_units=2).to(device)# 3. 设置训练参数loss_function = DiceLoss(to_onehot_y=True, softmax=True)optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)dice_metric = DiceMetric(include_background=False, reduction=\"mean\")# 4. 训练循环max_epochs = 50for epoch in range(max_epochs): model.train() epoch_loss = 0 for batch_data in train_loader: inputs, labels = batch_data[\"image\"].to(device), batch_data[\"label\"].to(device) optimizer.zero_grad() outputs = model(inputs) loss = loss_function(outputs, labels) loss.backward() optimizer.step() epoch_loss += loss.item() epoch_loss /= len(train_loader) # 验证步骤 (简化版) model.eval() with torch.no_grad(): metric_sum = 0.0 for val_data in train_loader: # 实际应使用独立验证集 val_images, val_labels = val_data[\"image\"].to(device), val_data[\"label\"].to(device) val_outputs = sliding_window_inference( val_images, (96, 96, 64), 4, model ) val_outputs = [torch.argmax(i, dim=1) for i in decollate_batch(val_outputs)] dice_metric(y_pred=val_outputs, y=val_labels) metric = dice_metric.aggregate().item() dice_metric.reset() print(f\"Epoch {epoch+1}/{max_epochs}, Loss: {epoch_loss:.4f}, Dice: {metric:.4f}\")# 5. 可视化结果 (示例)def visualize_slice(image, label, prediction, slice_index=25): fig, axes = plt.subplots(1, 3, figsize=(15, 5)) # 原始图像 axes[0].imshow(image[0, 0, :, :, slice_index], cmap=\"gray\") axes[0].set_title(\"Input Image\") axes[0].axis(\"off\") # 真实标签 axes[1].imshow(label[0, 0, :, :, slice_index], cmap=\"jet\") axes[1].set_title(\"Ground Truth\") axes[1].axis(\"off\") # 预测结果 axes[2].imshow(prediction[0, 0, :, :, slice_index], cmap=\"jet\") axes[2].set_title(\"Prediction\") axes[2].axis(\"off\") plt.show()# 测试单张图像test_data = train_ds[0]image = test_data[\"image\"].unsqueeze(0).to(device)with torch.no_grad(): prediction = sliding_window_inference(image, (96, 96, 64), 4, model) prediction = torch.argmax(prediction, dim=1, keepdim=True)visualize_slice( image.cpu().numpy(), test_data[\"label\"].unsqueeze(0).numpy(), prediction.cpu().numpy())
关键组件说明:
-
数据预处理流程:
Spacingd
:标准化不同扫描仪的分辨率差异Orientationd
:统一图像方向(RAS坐标系)ScaleIntensityRanged
:CT值标准化(-1000到1000 HU)RandCropByPosNegLabeld
:基于标签的智能裁剪
-
3D UNet架构:
- 专门处理体积数据(如CT/MRI)
- 残差单元提升梯度流动
- 多尺度特征提取能力
-
医学图像特定技术:
- Dice损失函数:处理类别不平衡
- Sliding Window推理:处理大尺寸体积数据
- 体素间距保留:保持物理尺寸一致性
-
可视化:
- 三视图对比(原始图像/真实标签/预测结果)
- 多平面重建(轴向/冠状/矢状面)
实际应用场景:
- 器官分割(肝脏/肾脏/肿瘤)
- 病变检测
- 手术规划
- 放射治疗剂量计算
进阶优化建议:
# 添加数据增强from monai.transforms import ( RandRotated, RandFlipd, RandZoomd)train_transforms.insert( 6, # 在强度归一化后添加 Compose([ RandRotated(keys=[\"image\", \"label\"], range_x=0.3, prob=0.5), RandFlipd(keys=[\"image\", \"label\"], spatial_axis=0, prob=0.5), RandZoomd(keys=[\"image\", \"label\"], min_zoom=0.9, max_zoom=1.1, prob=0.5) ]))# 使用更先进的模型from monai.networks.nets import SwinUNETRmodel = SwinUNETR( img_size=(96, 96, 64), in_channels=1, out_channels=2, feature_size=48).to(device)# 添加学习率调度lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=max_epochs)# 混合精度训练scaler = torch.cuda.amp.GradScaler()
此示例展示了MONAI在医学图像分析中的核心优势:领域特定的预处理、优化的3D网络架构、医学影像评估指标和高效的大体积数据处理能力。实际应用中需根据具体临床任务调整网络结构和处理参数。
2. Pandas + Polars + PyGWalker
快速探索表格型 EHR 数据(如病人记录、药品记录等)。
-
安装命令:
pip install pandas polars pygwalker
-
示例:用 PyGWalker 交互式探索电子病历
一个结合 Pandas、Polars 和 PyGWalker 快速探索电子健康记录(EHR)数据的完整示例,包含数据加载、预处理和交互式可视化:
import pandas as pdimport polars as plimport pygwalker as pygfrom datetime import datetime# 示例 EHR 数据结构 (若需加载真实数据,替换为 read_csv/read_parquet)data = { \"patient_id\": [1001, 1002, 1003, 1001, 1004], \"visit_date\": [\"2023-01-15\", \"2023-02-20\", \"2023-01-05\", \"2023-03-10\", \"2023-02-28\"], \"diagnosis\": [\"Hypertension\", \"Diabetes\", \"Hypertension\", \"Asthma\", \"Diabetes\"], \"medication\": [\"Lisinopril\", \"Metformin\", \"Amlodipine\", \"Albuterol\", \"Insulin\"], \"age\": [45, 62, 58, 36, 70], \"blood_pressure\": [\"140/90\", \"130/85\", \"150/95\", \"120/80\", \"145/88\"], \"lab_result\": [None, 6.5, 7.1, None, 8.0]}# 方案1: 使用Pandas加载数据df_pd = pd.DataFrame(data)df_pd[\"visit_date\"] = pd.to_datetime(df_pd[\"visit_date\"]) # 日期转换# 方案2: 使用Polars加载大数据(更高效)df_pl = pl.DataFrame(data).with_columns( pl.col(\"visit_date\").str.to_date(\"%Y-%m-%d\"))# 转换为Pandas供PyGWalker使用(Polars处理+PyGWalker可视化)df_processed = df_pl.to_pandas()# 使用PyGWalker进行交互式分析walker = pyg.walk( df_processed, spec=\"./ehr_analysis.json\", # 可选:保存/加载分析配置 dark=\"light\", # 界面主题:light/dark show_cloud_tool=False, # 隐藏云服务按钮 # 字段类型推断配置 field_specs={ \"age\": {\"analyticType\": \"dimension\"}, # 将年龄设为维度 \"lab_result\": {\"analyticType\": \"measure\"} })
关键功能说明:
-
数据加载优化
- 小数据:直接使用
pd.read_csv(\"ehr.csv\")
- 大数据:用Polars加速处理 → 转Pandas
df_pl = pl.scan_parquet(\"large_ehr.parquet\").collect() # 惰性加载
- 小数据:直接使用
-
PyGWalker 交互技巧:
- 拖拽分析:将字段拖到X/Y轴、颜色、大小等通道
- 图表推荐:智能识别字段类型推荐图表
- 一键生成:
- 患者年龄分布直方图
- 疾病类型环形图
- 实验室指标趋势线
- 多指标散点矩阵
-
高级分析支持:
# 在PyGWalker界面中直接使用Pandas语法walker.set_global_query(\"\"\"systolic = blood_pressure.split(\'/\')[0].astype(int)diastolic = blood_pressure.split(\'/\')[1].astype(int)hypertension_flag = (systolic >= 140) | (diastolic >= 90)\"\"\")
典型工作流:
- 数据加载:Polars处理百万级记录(比Pandas快5-10倍)
- 预处理:在Polars中完成清洗/转换
- 交互探索:
- 步骤1:拖拽
diagnosis
到行 → 自动生成疾病分布 - 步骤2:拖拽
age
到Y轴 → 自动切换箱线图 - 步骤3:添加
medication
到颜色通道 → 多维度对比
- 步骤1:拖拽
优势场景:
💡 提示:对于超大数据集(>1GB),推荐:
# 使用Polars过滤/聚合后再可视化df_sampled = df_pl.filter(pl.col(\"age\") > 30).sample(10000).to_pandas()pyg.walk(df_sampled)
🧪 三、药物发现与分子模拟
3. RDKit
用于化合物表示、分子指纹计算、QSAR 模型等。
-
安装命令:(推荐用 conda 安装)
conda install -c rdkit rdkit
-
示例:分子指纹和相似度
使用RDKit计算分子指纹和相似度的完整示例代码,并附带详细解释:
from rdkit import Chemfrom rdkit.Chem import AllChem, DataStructsfrom rdkit.Chem.Draw import MolsToGridImageimport matplotlib.pyplot as plt# 1. 分子创建与可视化ethanol = Chem.MolFromSmiles(\"CCO\") # 乙醇ethylamine = Chem.MolFromSmiles(\"CCN\") # 乙胺# 可视化分子img = MolsToGridImage( [ethanol, ethylamine], legends=[\"Ethanol (CCO)\", \"Ethylamine (CCN)\"], subImgSize=(300, 300))plt.imshow(img)plt.axis(\'off\')plt.show()# 2. 分子指纹生成# 使用Morgan指纹算法(圆形指纹),半径=2,生成2048位的位向量fp_ethanol = AllChem.GetMorganFingerprintAsBitVect(ethanol, radius=2, nBits=2048)fp_ethylamine = AllChem.GetMorganFingerprintAsBitVect(ethylamine, radius=2, nBits=2048)# 3. 相似度计算# 计算Tanimoto系数(Jaccard相似度)similarity = DataStructs.TanimotoSimilarity(fp_ethanol, fp_ethylamine)# 4. 结果输出print(\"=\"*50)print(f\"Tanimoto Similarity: {similarity:.4f}\")print(\"=\"*50)print(\"Interpretation:\")print(f\"- Ethanol (CCO) and Ethylamine (CCN) are {similarity*100:.1f}% similar\")print(\"- Similarity range: 0.0 (完全不同) to 1.0 (完全相同)\")print(\"- Value >0.5 suggests significant structural similarity\")print(\"- Difference due to terminal group: -OH vs -NH₂\")
代码解析:
-
分子创建:
MolFromSmiles()
将SMILES字符串转换为分子对象- 乙醇:
CCO
(羟基化合物) - 乙胺:
CCN
(胺类化合物)
-
分子指纹:
- 使用 Morgan指纹算法(圆形指纹)
radius=2
:考虑原子周围两键范围内的结构特征nBits=2048
:生成2048位的二进制指纹向量- 算法原理:通过迭代扩展识别每个原子周围的独特子结构
-
相似度计算:
- Tanimoto系数 = 共有特征数 / (特征A总数 + 特征B总数 - 共有特征数)
- 数学表示:
T(A,B) = |A∩B| / (|A| + |B| - |A∩B|)
- 取值范围:0.0(完全不同)到 1.0(完全相同)
-
结果解释:
- 典型输出:
Tanimoto Similarity: 0.25-0.35
- 相似度约30%:两个分子有相同的乙基骨架(-CH₂-CH₃),但不同末端基团(-OH vs -NH₂)
- 在药物发现中:
-
0.85:高度相似化合物
- 0.3-0.7:中等相似
- <0.2:结构差异大
-
- 典型输出:
应用场景:
- 虚拟筛选:快速筛选大型化合物数据库
- 先导化合物优化:评估结构修饰后的相似性变化
- 聚类分析:对化合物库进行结构分组
- ADMET预测:基于相似性的性质预测
扩展建议:
# 尝试不同分子对:aspirin = Chem.MolFromSmiles(\"CC(=O)OC1=CC=CC=C1C(=O)O\")ibuprofen = Chem.MolFromSmiles(\"CC(C)CC1=CC=C(C=C1)C(C)C(=O)O\")# 比较不同指纹算法:fp1 = AllChem.GetMACCSKeysFingerprint(mol) # MACCS密钥fp2 = Chem.RDKFingerprint(mol) # RDKit拓扑指纹
注意事项:
- 相似度值高度依赖指纹参数(半径、位长度)
- 结构相似 ≠ 活性相似(需结合生物实验验证)
- 对小分子效果最佳(分子量 < 800 Da)
运行此代码需要预先安装RDKit(建议通过Anaconda安装):
conda install -c conda-forge rdkit matplotlib