心脏病及其相关因素
摘要： 心脏病是一种常见的疾病，在没有直接地发病倾向前，我们总是关注与其可能有关的各种因素，以及患有心脏病带来的常见的影响。在该数据可视化中，我们主要通过热力图，散点图，饼状图等可视化方法展现心脏病及常见的因素的关系。特别的，我们发现患病与否和年龄，性别，静息血压，最大心率，胸痛类型，胆固醇含量等因素有明显的关系，并且患有心脏病对心率有着显著影响.
数据来源于kaggle（网站），主要变量涉及：年龄age，性别sex，经历过的胸痛类型cp，静息血压trestbps，胆固醇chol，空腹血糖fbs，静息心电测量restecg，最大心率thalach，是否有过心绞痛exang，ST抑制oldpeak，最高运动ST段的斜率slope，荧光显色的主要血管数量ca，地中海贫血thal，心脏病target

In [4]:

    import pandas as pd

    # 加载数据集
    df = pd.read_csv('./UCI Heart Disease Dataset.csv')

In [ ]:

    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抑制越明显。以及是否患心脏病与是否患有地中海贫血有着最显著的相关性

In [ ]:

    # 绘制age分布的柱状图
    plt.hist(df['age'], bins=20, edgecolor='black')

    # 添加标题和标签
    plt.title('年龄分布柱状图')
    plt.xlabel('年龄')
    plt.xticks(rotation=45)
    plt.ylabel('频数')

    # 显示图表
    plt.show()

然后通过年龄分布的柱状图可以发现，心脏病以中年为主要患者。

In [ ]:

    # 筛选出患病的数据
    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()

由男女比例的饼状图可以发现，男性患者占了大部分。

In [ ]:

    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()

根据静息血压的小提琴图可以发现，患病群体的静息血压总体有明显上升趋势。

In [ ]:

    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()

根据年龄与最大心率的散点图可以发现，患病群体的最大心率总体上明显比非患病群体的小。

In [ ]:

    import seaborn as sns
    import matplotlib.pyplot as plt

    # 绘制trestbps特征按target分组的箱线图
    sns.boxplot(x='target', y='trestbps', data=df)
    plt.title('不同患病状态下静息血压的分布箱线图')
    plt.show()

根据静息血压的箱线图可以发现，患病群体的静息血压总体要更高，这与小提琴图的结论类似。

In [ ]:

    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()

由年龄分布子图可以发现，患病群体在年龄上有显著的阶段区别；由最大心率的箱线图可以发现，患病群体的最大心率总体上比未患病群体要低很多。

In [ ]:

    # 统计不同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()

由胸痛类型的柱状图可以发现，患病群体有第四种胸痛的数量比未患病群体的要多得多，并且另外三种类型要少得多。

In [ ]:

    # 按年龄区间分组并计算患病和未患病的比例
    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岁以上的患病比例明显增多。

In [ ]:

    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()

根据平行坐标图，可以发现患病群体和非患病群体在胆固醇的含量上有明显区别。

In [ ]:

    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上比未患病群体明显更大，最大心率却更小，于是在图里总体分布朝外。\

结论：通过数据可视化的方法，我们明显发现心脏病患病情况与年龄，心脏，静息血压，最大心率，胸痛类型，胆固醇含量等因素有明显的关系，这确实地反应了心脏病与各种因素间的关系。