心脏病及其相关因素
摘要: 心脏病是一种常见的疾病,在没有直接地发病倾向前,我们总是关注与其可能有关的各种因素,以及患有心脏病带来的常见的影响。在该数据可视化中,我们主要通过热力图,散点图,饼状图等可视化方法展现心脏病及常见的因素的关系。特别的,我们发现患病与否和年龄,性别,静息血压,最大心率,胸痛类型,胆固醇含量等因素有明显的关系,并且患有心脏病对心率有着显著影响.
数据来源于kaggle(网站),主要变量涉及:年龄age,性别sex,经历过的胸痛类型cp,静息血压trestbps,胆固醇chol,空腹血糖fbs,静息心电测量restecg,最大心率thalach,是否有过心绞痛exang,ST抑制oldpeak,最高运动ST段的斜率slope,荧光显色的主要血管数量ca,地中海贫血thal,心脏病target
import pandas as pd
# 加载数据集
df = pd.read_csv('./UCI Heart Disease Dataset.csv')
import seaborn as sns
import matplotlib.pyplot as plt
# 计算特征之间的相关系数
correlation_matrix = df.corr()
# 设置中文字体为黑体
plt.rcParams['font.sans-serif'] = ['SimHei']
# 创建画布
plt.figure(figsize=(10, 8))
# 绘制热力图
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', vmin=-1, vmax=1)
# 设置标题
plt.title('特征之间的相关性热力图')
plt.show()

首先我们通过热力图,观察各个因素之间的关系。不难发现,slope与oldpeak呈明显正相关,这说明如果坡度值增加,ST抑制越明显。以及是否患心脏病与是否患有地中海贫血有着最显著的相关性
# 绘制age分布的柱状图
plt.hist(df['age'], bins=20, edgecolor='black')
# 添加标题和标签
plt.title('年龄分布柱状图')
plt.xlabel('年龄')
plt.xticks(rotation=45)
plt.ylabel('频数')
# 显示图表
plt.show()

然后通过年龄分布的柱状图可以发现,心脏病以中年为主要患者。
# 筛选出患病的数据
sick_data = df[df['target'] == 1]
# 计算患病男性和女性的数量
male_count = sick_data['sex'].sum()
female_count = len(sick_data) - male_count
# 计算比例
total = male_count + female_count
male_ratio = male_count / total
female_ratio = female_count / total
# 绘制饼图
labels = ['男性', '女性']
sizes = [male_ratio, female_ratio]
plt.pie(sizes, labels=labels, autopct='%1.1f%%')
plt.axis('equal')
plt.title('患病男女比例')
plt.show()

由男女比例的饼状图可以发现,男性患者占了大部分。
import seaborn as sns
import matplotlib.pyplot as plt
# 绘制小提琴图
sns.violinplot(x=df['target'], y=df['trestbps'], data=df)
# 设置标题和坐标轴标签
plt.title('根据目标变量和静息血压的小提琴图')
plt.xlabel('目标变量(是否患病)')
plt.xticks(rotation=45)
plt.ylabel('静息血压')
# 显示图形
plt.show()

根据静息血压的小提琴图可以发现,患病群体的静息血压总体有明显上升趋势。
import matplotlib.pyplot as plt
# 绘制患病的散点图
plt.scatter(df[df['target'] == 1]['age'], df[df['target'] == 1]['thalach'], c="red")
# 绘制未患病的散点图
plt.scatter(df[df['target'] == 0]['age'], df[df['target'] == 0]['thalach'], c='blue')
# 添加图例
plt.legend(["患病", "未患病"])
# 设置x轴和y轴标签
plt.xlabel("年龄")
plt.xticks(rotation=45)
plt.ylabel("最大心率")
# 显示图形
plt.show()

根据年龄与最大心率的散点图可以发现,患病群体的最大心率总体上明显比非患病群体的小。
import seaborn as sns
import matplotlib.pyplot as plt
# 绘制trestbps特征按target分组的箱线图
sns.boxplot(x='target', y='trestbps', data=df)
plt.title('不同患病状态下静息血压的分布箱线图')
plt.show()

根据静息血压的箱线图可以发现,患病群体的静息血压总体要更高,这与小提琴图的结论类似。
fig, axes = plt.subplots(1, 2, figsize=(15, 5))
# 年龄分布子图
sns.histplot(df['age'], bins=20, kde=True, ax=axes[0])
axes[0].set_title('年龄分布')
# 最大心率与目标变量的箱线图
sns.boxplot(x='target', y='thalach', data=df, ax=axes[1])
axes[1].set_title('不同患病状态下最大心率的分布')
plt.tight_layout()
plt.show()

由年龄分布子图可以发现,患病群体在年龄上有显著的阶段区别;由最大心率的箱线图可以发现,患病群体的最大心率总体上比未患病群体要低很多。
# 统计不同cp类型下患病和未患病的数量
cp_group = df.groupby(['cp', 'target']).size().unstack()
# 绘制分组柱状图
cp_group.plot(kind='bar')
plt.title('不同胸痛类型下患病和未患病的数量')
plt.xlabel('胸痛类型')
plt.ylabel('数量')
plt.xticks(rotation=45)
plt.show()

由胸痛类型的柱状图可以发现,患病群体有第四种胸痛的数量比未患病群体的要多得多,并且另外三种类型要少得多。
# 按年龄区间分组并计算患病和未患病的比例
bins = [30, 40, 50, 60, 70, 80]
df['age_group'] = pd.cut(df['age'], bins=bins)
grouped = df.groupby('age_group')['target'].value_counts(normalize=True).unstack()
# 绘制面积图
grouped.plot(kind='area', stacked=True)
plt.title('不同年龄区间下患病和未患病的比例变化')
plt.xlabel('年龄区间')
plt.xticks(rotation=45)
plt.ylabel('比例')
plt.show()

观察不同年龄区间的比例图,可以发现40岁以上的患病比例明显增多。
from pandas.plotting import parallel_coordinates
# 选择要绘制平行坐标图的特征
features = ['age', 'trestbps', 'chol', 'thalach', 'target']
temp_df = df[features]
# 绘制平行坐标图
parallel_coordinates(temp_df, 'target', colormap='viridis')
plt.title('平行坐标图展示特征与目标变量的关系')
plt.show()

根据平行坐标图,可以发现患病群体和非患病群体在胆固醇的含量上有明显区别。
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 分离患病和未患病数据
sick_data = df[df['target'] == 1]
healthy_data = df[df['target'] == 0]
# 绘制患病数据的散点
ax.scatter(sick_data['age'], sick_data['thalach'], sick_data['oldpeak'], c='r', marker='o', label='患病')
# 绘制未患病数据的散点
ax.scatter(healthy_data['age'], healthy_data['thalach'], healthy_data['oldpeak'], c='b', marker='^', label='未患病')
ax.set_xlabel('年龄')
ax.set_ylabel('最大心率')
ax.set_zlabel('运动引起的ST段下降')
ax.set_title('三维散点图展示年龄、最大心率、ST段下降与患病状态的关系')
ax.legend()
plt.show()

根据三维散点图,可以直观地看到,患病群体在oldpeak上比未患病群体明显更大,最大心率却更小,于是在图里总体分布朝外。\
结论:通过数据可视化的方法,我们明显发现心脏病患病情况与年龄,心脏,静息血压,最大心率,胸痛类型,胆固醇含量等因素有明显的关系,这确实地反应了心脏病与各种因素间的关系。