数据来源:kaggle
数据获取方式:
关注公众号:YOLO的学习进阶日常
回复:心脏病
为什么想做这个分析案例?
心脏病已经成为人类健康的三大杀手之一,为找到心脏病的病因,特此参考了一些公众号推文和知乎,kaggle这些平台的文章来做一个关于心脏病的分析。本文只涉及数据分析,数据处理和可视化,没有机器学习和深度学习,适合初学者的案例练手,大佬就不用过多参考这篇推文了。
import pandas as pd
import warnings
import seaborn as sns
sns.axes_style("dark")
warnings.filterwarnings('ignore')
data=pd.read_csv("heart.csv",engine='python',sep=',')
data.head(2)
age | sex | cp | trestbps | chol | fbs | restecg | thalach | exang | oldpeak | slope | ca | thal | target | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 63 | 1 | 3 | 145 | 233 | 1 | 0 | 150 | 0 | 2.3 | 0 | 0 | 1 | 1 |
1 | 37 | 1 | 2 | 130 | 250 | 0 | 1 | 187 | 0 | 3.5 | 0 | 0 | 2 | 1 |
列名解释:
age:年龄
sex:性别(1=男,0=女)
cp:疼痛类型(0=典型心绞痛;1=非典型心绞痛;2=非心绞痛;3=没有症状)
trestbps:静息血压(解释:静息心率指在清醒、不活动的安静状态下,每分钟心跳的次数。
静息血压就是在此状态下的测量血压)
chol:胆固醇
fbs: 人的空腹血糖(> 120 mg/dl=1; 0=假)解释:空腹血糖(饭前/餐前血糖): 80 - 130mg/dL. 餐后2小时血糖: 80 - 160mg/dL.
restecg:心电图(0=正常,1=患有ST-T波异常,2=根据Estes的标准显示可能或确定的左心室肥大,严重的情况)
thalach:最大的心率
exang:运动引起的心绞痛(1=是;0=不是)
oldpeak:相对于休息来说运动引起的ST段抑制 解释:(http://heart.dxy.cn/article/143557)
slope:运动高峰的心电图(1=上坡,2=平坦,3=下坡)
ca: 萤光显色的主要血管数目(0-4)荧光显色主要是跟糖尿病有一些关系
thal: 一种称为地中海贫血的血液疾病(3=正常; 6=固定缺陷; 7=可逆缺陷)
target: 心脏病(0=否,1=是)
医学知识科普时间:
- 地中海贫血:https://zh.wikipedia.org/wiki/%E5%9C%B0%E4%B8%AD%E6%B5%B7%E8%B2%A7%E8%A1%80
地中海贫血(Thalassemias):又称珠蛋白生成障碍性贫血,海洋性贫血症,简称地贫,是遗传性血液疾病,会造成血红蛋白合成障碍,其症状可依不同分型而有所不同,程度可能从无症状到严重。通常地中海贫血伴随典型的贫血症状,即红血球细胞水平低下。- 如何通俗易懂的看懂心电图:https://zhuanlan.zhihu.com/p/40666359
- 心率:指正常人安静状态下每分钟心跳的次数,也叫安静心率,一般为60~100次/分,可因年龄、性别或其他生理因素产生个体差异。一般来说,年龄越小,心率越快,老年人心跳比年轻人慢,女性的心率比同龄男性快,这些都是正常的生理现象。安静状态下,成人正常心率为60~100次/分钟,理想心率应为55~70次/分钟
data.info()
没有缺失值,医学数据的异常数据值得研究因此接下来,查看数据的各个指标,这个只有304个数据因此只能有一点点的参考价值,不能以偏概全。
因为是针对心脏病进行研究,来看一下有多少人患病有多少人没患病
countNoDisease = len(data[data.target == 0])
countHaveDisease = len(data[data.target == 1])
print(f'没患病人数:{countNoDisease }',end=' ,')
print("没有得心脏病比率: {:.2f}%".format((countNoDisease / (len(data.target))*100)))
print(f'有患病人数:{countHaveDisease }',end=' ,')
print("患有心脏病比率: {:.2f}%".format((countHaveDisease / (len(data.target))*100)))
没患病人数:138 ,没有得心脏病比率: 45.54%
有患病人数:165 ,患有心脏病比率: 54.46%
从比例看出患病和没患病的人差不多,接下来用饼图看一下他们的性别比例
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
gender_dict=data['sex'].value_counts()
colors = ['tomato', 'lightskyblue']
plt.figure(figsize=(8, 6))
plt.pie(gender_dict.values,labels=['男','女'],autopct="%0.2f%%",explode = (0,0.05),colors=colors, \
shadow=False, pctdistance=0.8,\
startangle=90, textprops={'fontsize': 16})
plt.show()
从图中可以看出男性的患病率是大于女性的,但是也只是对于这个数据而言,我们可以将这个作为一个特征值去进行下面的特征分析。先分别看一下男女的患病和为患病的比例
pd.crosstab(data.sex,data.target).plot(kind="bar",figsize=(10,6),color=['tomato', 'lightskyblue' ])
plt.title('各性别下患病图示')
plt.xlabel('性别 (0 = 女性, 1 = 男性)')
plt.xticks(rotation=0)
plt.legend(["未患病", "患有心脏病"])
plt.ylabel('人数')
plt.show()
从图中可以看出,女性患病的概率大于男性患病的比例,女性患病的比例达到了快75%,男性患病比例只有45%
因此根据这个数据集可以得到第一个结论 女性患心脏病的概率大于男性
fig,axes=plt.subplots(2,2,figsize=(8,8))
age_dist=data[['age','target']]
age_dist['age_range']=pd.cut(age_dist['age'],bins=[0,18,40,66,200],include_lowest=True,right=False,\
labels=['儿童','青年','中年','老年'])
sns.countplot(x='age_range',hue='target',data=age_dist,ax=axes[0,0],palette="Set2")
axes[0,0].set_xlabel("年龄段")
youth=age_dist[age_dist['age_range']=='青年']['target'].value_counts()
axes[0,1].pie(youth,labels=['正常','患病'],autopct='%.2f%%',colors = ['tomato', 'lightskyblue'])
axes[0,1].set_title("青年人患病比例")
youth=age_dist[age_dist['age_range']=='中年']['target'].value_counts()
axes[1,0].pie(youth,labels=['正常','患病'],autopct='%.2f%%',colors = ['tomato', 'lightskyblue'])
axes[1,0].set_title("中年人患病比例")
youth=age_dist[age_dist['age_range']=='老年']['target'].value_counts()
axes[1,1].pie(youth,labels=['正常','患病'],autopct='%.2f%%',colors = ['tomato', 'lightskyblue'])
axes[1,1].set_title("老年人患病比例")
Text(0.5, 1.0, '老年人患病比例')
为什么我要做三个饼图呢?
因为柱状图只能表示出来各个年龄段人数的多少,只能看出中年人患病的人比较大,但是我们更多的想要知道是不是年龄越大患病的概率就越大,因此需要更加直观的进行分析。通过对于饼图的分析,蓝色部分可以看出,年龄越大确实患病概率就越大了
除了年龄以外,心率也是心脏病的关键指标,是否年龄越大心率就会越大呢?可以通过小提琴图来分析
data['age_range']=pd.cut(data['age'],bins=[0,18,40,66,200],include_lowest=True,right=False,\
labels=['儿童','青年','中年','老年'])
ax=sns.swarmplot(x='age_range',y='thalach',data=data,hue='target')
ax.set_xlabel("年龄段")
Text(0.5, 0, '年龄段')
从图中可以发现,青年人的心率>中年人>老年人 所以心率的趋势是随着年龄的增长而不断的降低的,但是可以发现,在同一个年龄段内,患病的人普遍比为患病的人心率更高,所以证实了心率越快其实更容易患心脏病的假设。
很多人都以为心率越大血压也越大,下面用散点图来看一下
plt.scatter(x=data.thalach[data.target==1], y=data.trestbps[data.target==1], c="#FFA773")
plt.scatter(x=data.thalach[data.target==0], y=data.trestbps[data.target==0], c="#8DE0FF")
plt.legend(["患病",'未患病'])
plt.xlabel("心率")
plt.ylabel("血压")
plt.show()
从图中可以看出,心率和血压并无线性相关关系,因此不能说明心率越大血压就越高,那么是否是血压越高,患心脏病的概率也就越大呢?
ax=sns.swarmplot(x='target',y='trestbps',data=data)
ax.set_xlabel("是否患病")
ax.set_ylabel("血压")
Text(0, 0.5, '血压')
从图中也可以看出,其实血压的高低和是否患病也没有很明显的相关性,接下来看一下胸痛级别和心脏病的关系。
fig,ax=plt.subplots(1,2,figsize=(14,5))
sns.countplot(x='cp',data=data,hue='target',palette='Set2',ax=ax[0])
ax[0].set_xlabel("胸痛类型")
data.cp.value_counts().plot.pie(ax=ax[1],autopct='%1.1f%%',explode=[0.05,0,0,0],shadow=True, cmap='Blues')
ax[1].set_title("胸痛类型")
Text(0.5, 1.0, '胸痛类型')
从图中可以看出未患病的人主要是0类疼痛,但是患者主要是1~3类疼痛。说明疼痛的级别确实跟心脏病是有一定联系的,但是具体的还需要根据现实情况来进行分析。后续还有很多的研究大家可以自己发挥一下想象和假设,我做这个案例就是为了方便我以后自己做可视化的时候好直接复制粘贴的代码(我有点懒…
总结如下: