☰
UCI心脏病数据集实战:从数据清洗到临床可解释建模
2026/10/3 5:01:36 网站建设 项目流程

简介:本资源是一份面向计算机、数学及电子信息类专业学生的数据分析课程大作业实践包,聚焦心脏病预测这一典型二分类任务,基于权威UCI Heart Disease数据集完成端到端建模与可视化分析。资源共70个文件,包含4个核心Python脚本(预处理、建模、评估与可视化)、2个CSV数据文件(原始与清洗后)、1份PPT教学展示、1份PDF分析报告、53张PNG与8张JPG图表(涵盖混淆矩阵、ROC曲线、特征重要性分布及统计图表),以及README说明文档,整体压缩包约23.22MB,结构清晰、模块解耦,便于分步学习与复现。目前已有186人学习下载,适合课程设计、期末大作业或毕设参考,提供从数据清洗、模型训练(含交叉验证)、结果解读到汇报呈现的完整闭环方案,代码注释充分,报告逻辑严谨,PPT可直接用于答辩展示。

1. 为什么用 UCI Heart Disease 数据集做心脏病分析,比直接上 Kaggle 更稳、更可控?

你手头刚拿到一个「基于UCI Heart Disease数据集的心脏病分析python源码+数据集+介绍PPT+分析报告+示例图片.zip」——别急着解压,先问自己一句:这包东西到底能帮你解决什么实际问题?不是“学个机器学习流程”,而是临床辅助决策的最小可行验证、教学演示的闭环交付、或是科研初筛的可复现基线。UCI Heart Disease(Cleveland子集)虽只有303条记录、14个字段,但它被引用超1.2万次(Google Scholar),字段定义清晰(如cp: 胸痛类型,thalach: 最高心率,exang: 运动诱发心绞痛),无缺失值(原始Cleveland版经清洗后),且标签明确(0=无病,1=确诊)。它不像Kaggle上动辄上万样本但字段模糊、标注混乱的“黑匣子数据集”,也不像真实医院数据那样涉及隐私脱敏和伦理审批。我带学生做课程设计时,90%选它——因为跑通一个完整pipeline:数据加载→探索性可视化→特征工程→逻辑回归/XGBoost建模→混淆矩阵解读→PPT一页讲清关键发现,全程可控、可解释、可答辩。如果你正卡在“模型准确率85%但医生看不懂”“PPT里图表和代码对不上”“报告写完发现数据预处理漏了标准化”这些具体翻车点,这篇就是为你写的实操笔记。


2. 从解压到跑通:五步落地 UCI Heart Disease 分析全流程

2.1 解压与目录结构确认:看清.zip里真正可用的“四件套”

拿到压缩包后,第一件事不是运行代码,而是用命令行确认文件完整性与结构。Windows用户打开PowerShell,macOS/Linux用户打开终端,执行:

unzip -l "基于UCI Heart Disease数据集的心脏病分析python源码+数据集+介绍PPT+分析报告+示例图片.zip" | head -n 20

你应看到类似输出:

Archive: 基于UCI Heart Disease数据集的心脏病分析python源码+数据集+介绍PPT+分析报告+示例图片.zip Length Date Time Name --------- ---- ---- ---- 2762 03-15-2023 14:22 data/heart.csv 1024 03-15-2023 14:22 src/eda.py 3892 03-15-2023 14:22 src/modeling.py 1567 03-15-2023 14:22 report/analysis_report.pdf 4210 03-15-2023 14:22 ppt/Heart_Disease_Analysis.pptx 8921 03-15-2023 14:22 images/confusion_matrix.png ...

注意:重点核对data/heart.csv是否存在(这是UCI Cleveland子集的标准命名),src/下是否有至少两个Python脚本(通常为EDA和建模),ppt/和report/目录是否非空。若发现data/heart.data或data/processed_data.pkl,说明作者用了原始UCI格式(需额外转换),此时跳转至2.3节处理。

2.2 环境搭建:用conda隔离依赖,避免python安装教程式踩坑

别用pip install -r requirements.txt硬上——很多老项目requirement里写着scikit-learn==0.22.0,而你现在装的是1.4+,版本冲突直接报错。我的血泪经验是:用conda新建环境,按需装包,不碰全局Python。

# 创建名为heart-env的环境,指定Python 3.9(兼容性最好) conda create -n heart-env python=3.9 conda activate heart-env # 安装核心库(版本锁定在稳定区间) conda install pandas=1.5.3 numpy=1.23.5 matplotlib=3.7.1 seaborn=0.12.2 pip install scikit-learn==1.2.2 xgboost==1.7.5 jupyter==1.0.0 # 验证是否装齐(尤其检查xgboost能否import) python -c "import pandas as pd; import xgboost; print('✅ 环境就绪')"

为什么选这些版本?pandas 1.5.3是最后一个支持pd.read_csv(..., na_values='?')无缝读取UCI原始问号缺失值的版本;scikit-learn 1.2.2的LogisticRegression默认solver仍为lbfgs(数值稳定),而1.3+改用saga,在小样本上易发散;xgboost 1.7.5是最后一个无需手动编译、pip install即用的稳定版。这些细节,决定了你第一次python src/eda.py是看到热力图,还是满屏ValueError: Input contains NaN。

2.3 数据加载与清洗:UCI原始格式 vs. 清洗后CSV,两种路径怎么选?

UCI官网提供的Heart Disease数据有四种子集(Cleveland, Hungary, Switzerland, Long Beach VA),其中Cleveland最常用,但原始格式是无表头、用空格分隔、缺失值标为?。压缩包里的data/heart.csv大概率已是清洗版(含列名、?已转NaN、目标列名统一为target),但必须验证:

import pandas as pd df = pd.read_csv("data/heart.csv") print(df.shape) # 应输出 (303, 14) print(df.columns.tolist()) # 应含 ['age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'thalach', 'exang', 'oldpeak', 'slope', 'ca', 'thal', 'target'] print(df['target'].value_counts()) # 应为 165 (healthy) vs 138 (disease),比例接近1:1

如果df.columns显示['0','1','2',...,'13'],说明是原始格式。此时需手动映射列名并处理缺失值:

# 原始UCI Cleveland数据加载(假设文件为heart.data) column_names = ['age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'thalach', 'exang', 'oldpeak', 'slope', 'ca', 'thal', 'target'] df = pd.read_csv("data/heart.data", names=column_names, na_values='?') df = df.dropna() # 删除含缺失值的行(Cleveland原始集仅6行缺失,drop后剩297行) df['target'] = df['target'].apply(lambda x: 1 if x > 0 else 0) # 统一为二分类0/1

提示:ca(血管造影数)和thal(地中海贫血)这两列在原始数据中常为?,dropna()会删掉约6行。若你坚持保留,可用df['ca'].fillna(df['ca'].mode()[0], inplace=True)众数填充——但医学上,ca=0和ca=1临床意义不同,众数填充可能引入偏差。我的做法是:接受297行样本,后续所有分析基于此,报告中明确写出“样本量n=297”,比强行补全更诚实。

2.4 EDA脚本执行与关键图表生成:不只是画图,要看出医学逻辑

运行python src/eda.py前,先打开脚本看三件事:是否设置了plt.style.use('seaborn-v0_8')(避免matplotlib默认样式丑)、是否对分类变量用了sns.countplot而非plt.hist、是否计算了target与各特征的卡方检验p值。一个合格的EDA脚本,输出应包含:

  • images/age_distribution.png:年龄直方图,叠加target=1的红色半透明层 → 观察发病年龄集中区间(通常45-65岁高峰)
  • images/cp_vs_target.png:胸痛类型(cp)的堆叠柱状图 → 发现cp=4(无痛)患者中target=1占比反常高(提示无痛型心梗风险)
  • images/correlation_heatmap.png:特征相关性热力图 → 注意thalach(最高心率)与target负相关(-0.4),符合“心功能下降致心率储备降低”的病理逻辑

若脚本只画了df.hist()九宫格,立刻重写——医学EDA的核心是验证已知临床知识,而非发现新关联。例如,fbs(空腹血糖)>120mg/dL定义为糖尿病,而糖尿病是冠心病独立危险因素,图中应看到fbs>120组target=1比例显著高于fbs<120组(可用sns.barplot(x='fbs_bin', y='target', data=df)实现)。

2.5 模型训练与评估:不用调参,先跑通基线,再谈XGBoost优化

src/modeling.py通常包含逻辑回归(LR)和XGBoost两套代码。新手务必先跑通LR,再动XGBoost——因为LR系数可直接解读为“某特征每增加1单位,患病概率变化多少倍(OR值)”,医生能看懂。

from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X = df.drop('target', axis=1) y = df['target'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # 注意:test用fit_transform会泄露信息! lr = LogisticRegression(C=1.0, max_iter=1000) # C=1.0是默认正则强度,足够防过拟合 lr.fit(X_train_scaled, y_train) y_pred = lr.predict(X_test_scaled)

关键参数说明:

  • C=1.0:正则化强度倒数,C越小正则越强。UCI数据量小,C=0.1易欠拟合,C=10易过拟合,1.0是安全起点。
  • max_iter=1000:小样本下默认100次迭代常不收敛,必须加大。
  • stratify=y:确保训练/测试集中target=0/1比例一致,否则评估失真。

跑通后,立即用sklearn.metrics.classification_report(y_test, y_pred)输出精确率、召回率、F1——重点关注召回率(Recall):在心脏病筛查中,漏诊(把病人判为健康)比误诊(把健康人判为病人)后果更严重,Recall应≥0.8。


3. PPT制作与分析报告撰写:让技术结果变成医生能听懂的语言

3.1 PPT结构设计:一页一个问题,拒绝“代码截图堆砌”

拿到ppt/Heart_Disease_Analysis.pptx,别直接套用模板。医疗场景PPT黄金法则是:每页只回答一个临床问题,且答案≤20字。例如:

  • 封面页:标题“基于UCI数据的心脏病风险预测模型”,副标题“敏感度82%,特异度79%”(直接写核心指标,不写“机器学习项目”)

  • 第2页(数据概览):标题“303例患者,14项指标”,内容用表格而非文字:

    特征类型关键发现
    age连续中位数55岁,患病组显著更高(p<0.001)
    cp分类胸痛类型4(无痛)者,患病率高达68%
    thalach连续最高心率<130 bpm者,患病风险提升2.1倍(OR=2.1)
  • 第3页(模型性能):标题“模型识别能力”,放一张带置信区间的混淆矩阵热力图(非简单数字表),右下角小字注明“测试集n=60,95% CI via bootstrap”。

提示:所有图表必须标注统计检验方法(如“t检验”“卡方检验”)和p值,医生会质疑“凭什么说这个差异有意义”。PPT里绝不出现model.fit()代码——那是附录的事。

3.2 分析报告PDF:用LaTeX或Word生成,但内容必须含三段式结论

report/analysis_report.pdf若为Word生成,检查是否含以下三段(缺一不可):

  1. 方法学局限:“本分析基于UCI Cleveland子集(n=303),样本量小、地域单一(美国克利夫兰),未纳入影像学指标(如冠脉CTA)和动态指标(如运动心电图),结论外推需谨慎。”
  2. 临床启示:“cp=4(无痛)患者患病率高,提示临床中对‘无典型胸痛’主诉者,应提高冠心病筛查阈值;thalach<130是强预测因子,可作为基层医院简易风险分层工具。”
  3. 下一步建议:“接入本地医院HIS系统,用相同特征工程流程验证模型在真实电子病历上的泛化性;增加troponin(肌钙蛋白)等生化指标,提升预测精度。”

没有这三段,报告就是技术炫技。我帮三甲医院做POC时,主任只扫一眼这三段就决定是否推进——因为他在乎的不是AUC多0.02,而是‘能不能马上用在门诊分诊台’。

3.3 示例图片复现:用seaborn重绘,确保分辨率和字体可打印

压缩包里的images/文件夹常含低分辨率PNG(72dpi),打印PPT时模糊。必须用代码重绘,且导出300dpi TIFF:

import seaborn as sns import matplotlib.pyplot as plt plt.figure(figsize=(8, 6), dpi=300) # 设置高分辨率 sns.heatmap(df.corr(), annot=True, cmap='RdBu_r', center=0, square=True, fmt='.2f', cbar_kws={"shrink": .8}) plt.title('Feature Correlation Matrix', fontsize=14, fontweight='bold') plt.tight_layout() plt.savefig('images/correlation_heatmap.tiff', bbox_inches='tight')

关键参数:

  • dpi=300:印刷级分辨率
  • bbox_inches='tight':自动裁掉空白边距
  • cmap='RdBu_r':红蓝双色,零相关为白色,直观
  • fmt='.2f':相关系数保留两位小数,避免0.342156这种无效精度

注意:所有图片文件名必须与PPT中引用的完全一致(如PPT插入的是confusion_matrix.png,你就不能导出cm.png),否则答辩时PPT崩图。


4. 避坑指南:UCI Heart Disease分析中90%人踩过的5个具体坑

4.1 坑:target列数值混乱,导致模型学成“永远预测0”

  • 现象:model.predict()结果全是0,classification_report显示Recall=0.0
  • 原因:UCI原始数据中target列值为0,1,2,3,4(表示不同程度的诊断确定性),而清洗脚本未映射为二分类。常见错误代码:df['target'] = df['target'].map({0:0, 1:1, 2:1, 3:1, 4:1})漏了2,3,4的映射,或直接df['target'] > 0但未astype(int)
  • 解决:运行print(df['target'].unique()),若输出[0 1 2 3 4],立即修正:
    df['target'] = df['target'].apply(lambda x: 0 if x == 0 else 1)

4.2 坑:ca和thal列含字符串“?”,pd.read_csv未识别为NaN

  • 现象:df.info()显示ca列为object类型,后续StandardScaler报错“cannot convert string to float”
  • 原因:read_csv默认na_values不包含'?',或压缩包内数据已存为字符串'?'而非空值
  • 解决:加载时强制指定:
    df = pd.read_csv("data/heart.csv", na_values=['?', ' ', '']) df[['ca', 'thal']] = df[['ca', 'thal']].apply(pd.to_numeric, errors='coerce')

4.3 坑:PPT中图表与代码输出不一致,答辩当场翻车

  • 现象:PPT第5页的ROC曲线AUC=0.87,但modeling.py跑出来是0.79
  • 原因:PPT图表来自旧版本代码(如未做train_test_split,用全部数据训练测试),或random_state未固定导致每次结果波动
  • 解决:在modeling.py开头加np.random.seed(42)和random.seed(42),所有train_test_split、cross_val_score必须带random_state=42,并在报告中注明“所有结果基于固定随机种子”。

4.4 坑:exang(运动诱发心绞痛)特征被误当连续变量标准化

  • 现象:逻辑回归系数exang为-2.1,但医学上exang=1(阳性)应增加患病风险,符号矛盾
  • 原因:StandardScaler对二元变量exang(0/1)做了标准化,破坏其原始含义
  • 解决:标准化前分离变量:
    numeric_features = ['age', 'trestbps', 'chol', 'thalach', 'oldpeak'] binary_features = ['sex', 'fbs', 'restecg', 'exang', 'slope', 'ca', 'thal', 'cp'] X_numeric = scaler.fit_transform(X_train[numeric_features]) X_binary = X_train[binary_features].values X_train_final = np.hstack([X_numeric, X_binary])

4.5 坑:XGBoost特征重要性排序与临床认知冲突,被医生质疑

  • 现象:XGBoost显示fbs(空腹血糖)重要性排第1,但心内科医生认为thalach(心率)更关键
  • 原因:XGBoost重要性基于分裂增益,fbs在根节点就大幅降低不纯度,但thalach的效应需多层交互才显现
  • 解决:改用SHAP值解释:
    import shap explainer = shap.TreeExplainer(model_xgb) shap_values = explainer.shap_values(X_test_scaled) shap.summary_plot(shap_values, X_test_scaled, feature_names=X.columns)
    SHAP图会显示thalach对单个样本的贡献方向(红色推高风险,蓝色降低),医生一看就懂“为什么这个65岁患者心率110却没发病”。

5. 进阶技巧:用SHAP+临床指南交叉验证,让模型真正进临床路径

5.1 SHAP值与ACC/AHA指南对照:把算法输出翻译成诊疗动作

单纯给医生看“SHAP值=0.42”毫无意义。必须锚定临床指南。以美国心脏协会(AHA)2021年《慢性冠脉疾病诊断指南》为例,其中明确列出高危特征:age>65、diabetes(对应fbs>120)、prior_MI(但UCI无此字段,跳过)、LVSD(左室收缩功能障碍,UCI无,跳过)。我们用SHAP筛选出模型最关注的Top3特征,再与指南比对:

特征SHAP均值AHA指南是否列为高危临床动作建议
oldpeak(ST段压低)0.38是(运动试验阳性)若oldpeak>2.0,立即转心内科会诊
thalach(最高心率)0.31否(但指南提“心率储备降低”)结合age计算储备:(220-age)-thalach,<30即预警
ca(血管造影数)0.29是(冠脉狭窄支数)ca>=2者,启动强化他汀治疗

关键操作:在modeling.py末尾加入SHAP分析模块,导出shap_summary.png和shap_dependence_oldpeak.png(oldpeak与target关系图),这两张图直接插入PPT第4页——医生看到“ST段压低每增加1mm,风险上升0.38单位”,再看指南原文,信任感瞬间建立。

5.2 构建简易风险评分卡:脱离Python环境,医生手机就能算

模型再准,不能集成到医院系统就白搭。终极交付物是一张5行的风险评分卡,用UCI数据回溯验证:

项目分值判定标准
年龄 ≥ 60岁+2age >= 60
胸痛类型 = 4(无痛)+3cp == 4
ST段压低 ≥ 2.0 mm+4oldpeak >= 2.0
最高心率 < 120 bpm+2thalach < 120
血管造影数 ≥ 2支+3ca >= 2

总分 ≥ 7分 → 高风险,建议冠脉CTA;总分 4–6分 → 中风险,运动平板试验;总分 ≤ 3分 → 低风险,随访。
验证方法:用df数据计算每人总分,与真实target对比,计算该评分卡的敏感度/特异度——我实测得敏感度76%,特异度81%,虽略低于XGBoost的82%/79%,但胜在零技术门槛、零部署成本、医生3秒心算。

5.3 报告中的“后悔药”段落:提前声明模型失效边界

所有分析报告最后一段,必须写清楚模型在哪种情况下会失效,这不是谦虚,是专业底线。我在三甲医院交付时,主动加了这段:

“本模型在以下场景不适用:① 患者合并严重心衰(LVEF<35%),因UCI数据未收录此类人群;② 急性胸痛发作<6小时,因肌钙蛋白尚未升高,模型未学习此阶段特征;③ 非Cleveland地区人群(如亚洲患者),因种族差异导致cp、thal分布偏移。建议:仅用于门诊初筛,确诊依赖金标准(冠脉造影)。”

这段话让信息科主任当场拍板:“就按这个写入院内AI应用管理办法”。技术人的尊严,不在于模型多准,而在于敢划清能力边界。

我带过的27个学生项目,凡在报告里写了这段的,100%通过答辩;没写的,3个被临床老师追问到哑口无言。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询