心血关疾病
2026/6/19 17:58:47 网站建设 项目流程

心血管疾病是全球致死率最高的疾病之一,早期筛查、快速风险预判能极大降低重症发病概率。本文基于医院真实心血管医疗数据集(1319 条患者临床指标),完整复现数据读取→探索性数据分析 EDA→异常清洗预处理→特征工程→多分类模型训练对比全流程,对比逻辑回归、决策树、随机森林、XGBoost、SVM 五大经典二分类算法,通过混淆矩阵、分类报告、ROC-AUC 综合评估模型性能,最终选出适配医疗诊断场景的最优模型,代码可直接运行,适合机器学习入门、课程大作业、毕设参考。

一、项目环境与依赖库

1.1 导入全部依赖

python

运行

import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl from scipy.stats import chi2_contingency from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.svm import SVC from xgboost import XGBClassifier from sklearn.metrics import classification_report, confusion_matrix, roc_curve, auc import warnings # 屏蔽运行警告 warnings.filterwarnings('ignore') # 解决matplotlib中文、负号显示 mpl.rcParams['font.family']='SimHei' plt.rcParams['axes.unicode_minus']=False

二、数据集加载与基础信息探查

2.1 数据读取与列名中文转换

数据集文件:Medicaldataset.csv,共 1319 条患者样本,9 个字段:年龄、性别、心率、收缩压、舒张压、血糖、肌酸激酶同工酶、肌钙蛋白、诊断结果(positive 患病 /negative 健康)。

python

运行

# 读取csv数据 df=pd.read_csv("Medicaldataset.csv") # 重命名中文列 columns=['年龄','性别','心率','收缩压','舒张压','血糖','肌酸激酶同工酶','肌钙蛋白','结果'] df.columns=columns # 查看前5行 df.head()

2.2 基础数据信息

python

运行

# 数据类型、非空值统计 df.info() # 数值特征描述统计 df.describe() # 重复值检测 print("重复样本数量:",df.duplicated().sum())

输出解读

  1. 数据集共 1319 条样本,无缺失值、无重复数据;
  2. 5 个 int 整型特征(年龄、性别、心率、收缩压、舒张压),3 个浮点生化指标,1 个文本标签(诊断结果);
  3. 年龄均值 56.19,样本集中中老年人群;男性占比 65.96%,样本男性多于女性;
  4. 心率、血糖、肌酸激酶同工酶最大值远超正常生理区间,存在大量极端异常值。

2.3 原始数据箱线图(异常值可视化)

python

运行

df.plot(kind='box',figsize=(14,8)) plt.title("原始数据各特征箱线图(异常值分布)") plt.show()

对应可视化图:

rym {"type":"ImageRefCard","refs":["问诊 1 - 第一张箱线图"],"titles":["原始数据箱线图"]}

从箱线图可见:心率、血糖、肌酸激酶同工酶、肌钙蛋白存在大量离群极端点,属于临床不合理数据,需要清洗;部分样本舒张压>收缩压,违背生理常识,需修正。

三、数据预处理(医疗数据清洗核心步骤)

3.1 极端生理异常样本剔除

临床生理阈值规则:心率<1000、收缩压>50、舒张压<140,过滤极端错误数据:

python

运行

# 过滤极端异常值 df=df.loc[(df['心率']<1000)& (df['收缩压']>50)&(df['舒张压']<140)] print("清洗后样本量:",df.shape[0]) # 输出:1314条,剔除5条极端错误样本

3.2 修正舒张压>收缩压逻辑错误样本

血压生理规则:收缩压必然大于舒张压,交换异常样本的两列数值:

python

运行

# 筛选异常血压数据 wrong_data=df[df['舒张压']>df['收缩压']] # 交换两列数值 df.loc[wrong_data.index,['收缩压','舒张压']] = df.loc[wrong_data.index,['舒张压','收缩压']].values.copy() # 校验修正结果 df.loc[wrong_data.index[0:5]]

3.3 清洗后数据重绘箱线图

python

运行

df.plot(kind='box',figsize=(14,8)) plt.title("清洗异常值后特征箱线图") plt.show()

对应可视化图:

rym {"type":"ImageRefCard","refs":["问诊 1 - 第二张箱线图"],"titles":["清洗后箱线图"]}

四、探索性数据分析 EDA(特征与患病关系挖掘)

4.1 人群基础画像:年龄分布 + 性别占比

python

运行

plt.figure(figsize=(12,10)) # 子图1:年龄直方图+核密度曲线 plt.subplot(211) plt.hist(df['年龄'],bins=20) df['年龄'].plot(kind='kde',secondary_y=True) plt.title('患者年龄分布直方图+核密度图') # 子图2:性别饼图 plt.subplot(212) gender_data=df['性别'].value_counts() plt.pie(gender_data, autopct='%.2f%%', labels=['男','女'], shadow=True, explode=(0.05,0)) plt.title('数据集性别占比') plt.tight_layout() plt.show()

对应可视化图:

rym {"type":"ImageRefCard","refs":["问诊 1 - 年龄性别分布图"],"titles":["年龄分布 + 性别饼图"]}

分析结论

  1. 年龄近似正态分布,50-75 岁中老年群体占比最高,是心脏病高发人群;
  2. 男性样本 65.98%,女性 34.02%,男性样本数量显著高于女性。

4.2 各临床指标与心脏病诊断分组对比

将数据按 ** 阳性(患病)/ 阴性(健康)** 分组,绘制多子图箱线图,直观对比指标差异:

python

运行

plt.figure(figsize=(20,16)) # 1.年龄vs诊断 plt.subplot(3,3,1) pos_age=df[df['结果']=='positive']['年龄'] neg_age=df[df['结果']=='negative']['年龄'] plt.boxplot([pos_age,neg_age], labels=['阳性','阴性']) plt.title('年龄与心脏病诊断关系') # 2.心率vs诊断 plt.subplot(3,3,2) pos_heart=df[df['结果']=='positive']['心率'] neg_heart=df[df['结果']=='negative']['心率'] plt.boxplot([pos_heart,neg_heart],labels=['阳性','阴性']) plt.title('心率与心脏病诊断关系') # 3.阳性样本性别饼图 plt.subplot(333) pos_data=df[df['结果']=='positive'] gender_pos=pos_data['性别'].value_counts() plt.pie(gender_pos,labels=['男','女'],autopct='%.2f%%') plt.title('确诊心脏病患者性别比例') # 4-8:血压、血糖、肌酸激酶、肌钙蛋白分组箱线 ax4=plt.subplot(334) df.boxplot(column='收缩压',by='结果',ax=ax4) ax5=plt.subplot(335) df.boxplot(column='舒张压',by='结果',ax=ax5) ax6=plt.subplot(336) df.boxplot(column='血糖',by='结果',ax=ax6) ax7=plt.subplot(337) df.boxplot(column='肌酸激酶同工酶',by='结果',ax=ax7) ax8=plt.subplot(338) df.boxplot(column='肌钙蛋白',by='结果',ax=ax8) plt.suptitle('') plt.show()

对应可视化图:

rym {"type":"ImageRefCard","refs":["问诊 1 - 多特征分组箱线图"],"titles":["各指标按患病分组对比图"]}

关键医学规律挖掘

  1. 肌酸激酶同工酶、肌钙蛋白两个心肌损伤标志物,阳性患者数值显著高于阴性,是区分心脏病核心特征;
  2. 患病人群平均年龄略高于健康人群;
  3. 收缩压、血糖在阳性样本整体分布更高,存在轻度正相关;
  4. 确诊心脏病患者中男性占比接近 70%,男性患病风险样本层面更高。

4.3 性别 + 诊断双维度分组指标分布

python

运行

df.boxplot(column=['血糖','年龄','收缩压','舒张压'],by=['性别','结果'],figsize=(14,10)) plt.xticks(rotation=45) plt.suptitle('') plt.show()

对应可视化图:

rym {"type":"ImageRefCard","refs":["问诊 1 - 双分组箱线图"],"titles":["性别 + 诊断双分组指标分布"]}

五、特征工程与数据集划分

5.1 标签二值化(建模标准)

将文本标签positive/negative转为 0/1 二分类数值:

python

运行

df['Result_Binary']=(df['结果']=='positive').astype(int)

5.2 筛选核心预测特征

根据 EDA 分析,心肌标志物区分度最强,选取 4 个核心特征建模:性别、年龄、肌酸激酶同工酶、肌钙蛋白

python

运行

features=['性别','年龄','肌酸激酶同工酶','肌钙蛋白'] X=df[features].copy() y=df['Result_Binary']

5.3 连续特征标准化

逻辑回归、SVM 对特征量纲敏感,对年龄、两项心肌指标标准化:

python

运行

continuous_vars=['年龄','肌酸激酶同工酶','肌钙蛋白'] X[continuous_vars] = X[continuous_vars].astype(float) scaler=StandardScaler() X.loc[:,continuous_vars]=scaler.fit_transform(X[continuous_vars])

5.4 训练集 / 测试集划分(8:2 分层抽样)

分层抽样stratify=y保证训练、测试集患病 / 健康样本比例一致,避免类别偏移:

python

运行

X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=15,stratify=y)

六、通用模型评估函数(统一输出混淆矩阵 + ROC)

封装评估逻辑,复用至 5 个模型,输出分类报告、混淆矩阵热力图、ROC-AUC 曲线:

python

运行

def evaluate_model(model,model_name,X_train,X_test,y_train,y_test): # 模型训练 model.fit(X_train,y_train) # 测试集预测 y_pred=model.predict(X_test) print(f"====={model_name} 模型评估报告=====") print(classification_report(y_test,y_pred)) # 绘制混淆矩阵 cm=confusion_matrix(y_test,y_pred) plt.figure(figsize=(8,6)) plt.imshow(cm, cmap='hot', interpolation='nearest') plt.colorbar() for i in range(2): for j in range(2): plt.text(j, i,f'{cm[i, j]}',ha='center',va='center',color='white',fontsize=15) plt.title(f'{model_name}混淆矩阵') plt.show() # 绘制ROC曲线、计算AUC if hasattr(model,"predict_proba"): y_prob=model.predict_proba(X_test)[:,1] else: y_prob=model.decision_function(X_test) fpr, tpr,_= roc_curve(y_test, y_prob) roc_auc=auc(fpr,tpr) plt.figure(figsize=(8,6)) plt.plot(fpr,tpr,color='darkorange',lw=2,label=f'ROC曲线(面积={roc_auc:.2f})') plt.plot([0,1],[0,1],color='navy',lw=2,linestyle='--') plt.xlabel('假阳率(FPR)') plt.ylabel('真阳率(TPR)') plt.title(f'{model_name}ROC曲线') plt.legend(loc="lower right") plt.show() return model,roc_auc

七、五大分类模型训练与结果对比

7.1 逻辑回归(基线线性模型)

python

运行

lr_model=LogisticRegression(random_state=15, class_weight='balanced') lr_model,lr_auc=evaluate_model(lr_model,"逻辑回归",X_train,X_test,y_train,y_test)

结果指标:准确率 0.83,AUC=0.92 混淆矩阵、ROC 曲线:

rym {"type":"ImageRefCard","refs":["问诊 1 - 逻辑回归混淆矩阵","问诊 1 - 逻辑回归 ROC"],"titles":["逻辑回归混淆矩阵","逻辑回归 ROC 曲线"]}

7.2 决策树(单树非线性模型)

python

运行

dt_model=DecisionTreeClassifier(random_state=15, class_weight='balanced') dt_model,dt_auc=evaluate_model(dt_model,"决策树",X_train,X_test,y_train,y_test)

结果指标:准确率 0.98,AUC=0.98 混淆矩阵 + ROC 曲线:

rym {"type":"ImageRefCard","refs":["问诊 1 - 决策树混淆 ROC"],"titles":["决策树混淆矩阵 + ROC"]}

7.3 随机森林(集成树模型)

python

运行

rf_model= RandomForestClassifier(random_state=15, class_weight='balanced') rf_model,rf_auc=evaluate_model(rf_model,"随机森林",X_train,X_test,y_train,y_test)

结果指标:准确率 0.97,AUC=0.99 混淆矩阵、ROC 曲线:

rym {"type":"ImageRefCard","refs":["问诊 1 - 随机森林混淆矩阵","问诊 1 - 随机森林 ROC"],"titles":["随机森林混淆矩阵","随机森林 ROC 曲线"]}

7.4 XGBoost(梯度提升树)

python

运行

xgb_model = XGBClassifier(random_state=15, scale_pos_weight=sum(y_train==0)/sum(y_train==1)) xgb_model, xgb_auc = evaluate_model(xgb_model,"XGBoost",X_train,X_test,y_train,y_test)

结果指标:准确率 0.98,AUC=0.99 混淆矩阵 + ROC 曲线:

rym {"type":"ImageRefCard","refs":["问诊 1-XGBoost 混淆 ROC"],"titles":["XGBoost 混淆矩阵 + ROC"]}

7.5 SVM 支持向量机

python

运行

svm_model= SVC(random_state=15,class_weight='balanced',probability=True) svm_model, svm_auc=evaluate_model(svm_model,"支持向量机",X_train,X_test,y_train,y_test)

结果指标:准确率 0.83,AUC=0.92 ROC 曲线:

rym {"type":"ImageRefCard","refs":["问诊 1-SVMROC"],"titles":["SVM 模型 ROC 曲线"]}

八、模型综合对比与结论

8.1 性能汇总表

表格

模型整体准确率AUC 值特点
逻辑回归83%0.92线性基线,可解释性强,精度偏低
SVM83%0.92依赖标准化,非线性拟合弱,训练慢
决策树98%0.98单树简单,无标准化需求,易轻微过拟合
随机森林97%0.99集成学习,泛化能力强,稳定性高
XGBoost98%0.99梯度提升,分类精度最高,医疗场景最优

8.2 实验结论

  1. 树类集成模型全面优于线性模型:随机森林、XGBoost、决策树依靠捕捉心肌标志物与患病的非线性关系,AUC、准确率远高于逻辑回归、SVM;
  2. XGBoost 与随机森林综合性能最优:AUC 达到 0.99,几乎可以完美区分健康与心脏病患者,适合用于临床辅助诊断;
  3. 决策树适合快速落地轻量化场景:无需特征标准化、推理速度快,单模型准确率 98%,部署成本低;
  4. 核心特征验证:肌酸激酶同工酶、肌钙蛋白是预测心脏病的决定性指标,与临床医学理论完全吻合。

8.3 项目拓展优化方向

  1. 超参数网格搜索 GridSearchCV 优化树模型深度、学习率,进一步降低过拟合;
  2. 引入 SHAP 值分析特征重要性,增强医疗模型可解释性;
  3. 增加交叉验证 K-fold,验证模型泛化能力;
  4. 封装模型为 Flask 简易 Web 接口,实现单患者指标在线预测;
  5. 扩充样本量,加入胆固醇、心电图等更多临床特征。

九、完整项目总结

本文完整走完医疗心血管数据集从原始脏数据到多模型对比的全流程,解决了医疗数据特有的生理异常值、逻辑错误样本清洗问题,通过 EDA 挖掘出心肌损伤标志物与心脏病的强关联规律,对比 5 种主流机器学习算法完成二分类建模。 在医疗诊断场景下,XGBoost、随机森林具备极高的区分能力,可作为医生辅助筛查工具;若追求轻量化部署,决策树是性价比之选。整套代码完整可复现,适合机器学习初学者、课程设计、毕业设计参考。

文末附完整源码下载提示

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

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

立即咨询