数据分析实战:利用python对心脏病数据集进行分析

我们都很害怕生病,但感冒发烧这种从小到大的疾病我们已经麻木了,因为一星期他就会好,但是随着长大,各种发炎、三高、心脏病、冠心病响应而生。
心脏病作为一种发作起来让人看了就觉得恐怖的疾病,每年不知道夺走多少生命。而那些患病健在的人们也必须在自己后续的生命里割舍太多东西,以防止心脏病发作。
没有得病的时候,我们永远觉得它离自己很远。我对心脏病的认知就是这样,我不知道它患病的原因,也不知哪些原因会引起心脏病。而患病后如何保持正常生活等等,一概不知。
今天在kaggle上看到一个心脏病数据(数据集下载地址和源码见文末),那么借此深入分析一下。
数据集读取与简单描述 首先导入library和设置好超参数,方便后续分析。
importnumpyasnp importpandasaspd importmatplotlib.pyplotasplt importseabornassns 通过对数据集读取和描述可以得到这两个表格:
可以看到有303行14列数据,每列的标题是age、sex、cp、……、target。他们就像每次去医院的化验单,非专业人士很多都不认识。所以利用官方的解释翻译后含义如下:
age: 该朋友的年龄
sex: 该朋友的性别 (1 = 男性, 0 = 女性)
cp: 经历过的胸痛类型(值1:典型心绞痛,值2:非典型性心绞痛,值3:非心绞痛,值4:无症状)
trestbps: 该朋友的静息血压(入院时的毫米汞柱)
chol: 该朋友的胆固醇测量值,单位 :mg/dl
fbs: 人的空腹血糖(> 120 mg/dl,1=真;0=假)
restecg: 静息心电图测量(0=正常,1=患有st-t波异常,2=根据estes的标准显示可能或确定的左心室肥大)
thalach: 这朋友达到的最大心率
exang: 运动引起的心绞痛(1=有过;0=没有)
oldpeak: st抑制,由运动引起的相对于休息引起的(“ st”与ecg图上的位置有关。这块比较专业,可以点这个看一个解读)
slope: 最高运动st段的斜率(值1:上坡,值2:平坦,值3:下坡)
ca: 萤光显色的主要血管数目(0-4)
thal: 一种称为地中海贫血的血液疾病(3=正常;6=固定缺陷;7=可逆缺陷)
target: 心脏病(0=否,1=是)
所以这些信息里都是患病或者健康者的一些身体指标,并没有和他是否抽烟、是否熬夜、是否遗传、是否作息规律那些东西,因此找不到指导现在我们生活的点,比如说明要戒烟戒酒那些东西。 顺手送上一篇知乎链接 此外上边只是我通过原版数据集给的解读翻译的,如有出错误,欢迎纠正
拿到一套数据首先是要看看这个数据大概面貌~
男女比例 先看看患病比率,男女比例这些常规的
countnodisease=len(data[data.target==0]) counthavedisease=len(data[data.target==1]) countfemale=len(data[data.sex==0]) countmale=len(data[data.sex==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))) print(f'女性人数:{countfemale}',end=',') print(女性比例:{:.2f}%.format((countfemale/(len(data.sex))*100))) print(f'男性人数:{countmale}',end=',') print(男性比例:{:.2f}%.format((countmale/(len(data.sex))*100))) 上边代码得到的答案如下,乍看上去男的多于女的,但前提是这个数据只是这个300人的样本展示,不代表全人类
没患病人数:138 ,没有得心脏病比率: 45.54%
有患病人数:165 ,患有心脏病比率: 54.46%
女性人数:96 ,女性比例: 31.68%
男性人数:207 ,男性比例: 68.32% 除了用饼图看这个面貌,还可以同时看一下
fig,ax=plt.subplots(1,3)#2个子区域 fig.set_size_inches(w=15,h=5)#设置画布大小 sns.countplot(x=sex,data=data,ax=ax[0]) plt.xlabel(性别(0=female,1=male)) sns.countplot(x=target,data=data,ax=ax[1]) plt.xlabel(是否患病(0=未患病,1=患病)) sns.swarmplot(x='sex',y='age',hue='target',data=data,ax=ax[2]) plt.xlabel(性别(0=female,1=male)) plt.show() 从这三联图可以看到男性1多余女性0,患病target1多于未患病0,在年龄分布提琴图里可以看到女性患者比例多于男性患者比例。
其中比列详细拆解一下,见下方代码和图示:
pd.crosstab(data.sex,data.target).plot(kind=bar,figsize=(15,6),color=['#30a9de','#efdc05']) plt.title('各性别下患病图示') plt.xlabel('性别(0=女性,1=男性)') plt.xticks(rotation=0) plt.legend([未患病,患有心脏病]) plt.ylabel('人数') plt.show() 可以看到这个数据集中女性患者数是健康数的3倍多。留下一个疑问,心脏病女性更容易得嘛?百度了一下,发现这个问题提问的人不少,但没有具体很科学的回答。google也同样如此。可能要找到这个答案需要再去找一找文献,但不是本文目的,因此没有去寻找这个真实比例。
在这个数据集中,男性多于女性一倍,分别207和96人;患病患者稍微多余未患病患者,患病165,138人。因为年龄可能是连续的,因此在第三幅图做年龄、性别、患病关系图,单从颜色观察可发现在这个数据集中,女性患病率大于男性。通过第四图和统计可以计算得到,男性患病率44.9% ,女性患病率75%。
需要注意,本文得到的患病率只是这个数据集的。
年龄和患病关系 通过以下代码来看一看:随着年龄增长患病比率有没有变化
(现在写这个文章的时候我才想到,可能即使有变化也没有意义,还是样本有限,如果这个样本空间覆盖再提升1000倍才能说明一些问题吧——即年龄和患有心脏病的关系)
pd.crosstab(data.age,data.target).plot(kind=bar,figsize=(25,8)) plt.title('患病变化随年龄分布图') plt.xlabel('岁数') plt.ylabel('比率') plt.savefig('heartdiseaseandages.png') plt.show() 输出的图像如下:就这张图来说37-54岁患病人数多于未患病人数,年龄再继续升高后有没有这个规律了,在70+岁后患病人数又增加,这条仅能作为数据展示,不能作为结论。
数据集中还有很多维度可以组合分析,下边开始进行组合式探索分析
年龄-心率-患病三者关系 在这个数据集中,心率的词是‘thalach’,所以看年龄、心率、是否患病的关系。
#散点图 plt.scatter(x=data.age[data.target==1],y=data.thalach[(data.target==1)],c=red) plt.scatter(x=data.age[data.target==0],y=data.thalach[(data.target==0)],c='#41d3bd') plt.legend([患病,未患病]) plt.xlabel(年龄) plt.ylabel(最大心率) plt.show() #再画个提琴图 sns.violinplot(x=data.target,y=data.trestbps,data=data) plt.show() 看到30岁心跳200那个点,吓我一跳,如果心脏病不是病,那200这个速度太让人膜拜了。
可以看到的是心跳速度患病的大概集中在140-200bpm之间。这个数据比未患病的人普遍高一些,从提琴图上也可以看到这个值分布比健康人高一些且更集中。
年龄和血压(trestbps)分布关系 大家都知道体检的时候血压是常规测试项目,那么我想血压和年龄有什么关系吗?有没有心脏病和年龄有关系吗?
来做个图看一下。并尝试用不同的颜色区分。
plt.scatter(x=data.age[data.target==1],y=data.trestbps[data.target==1],c=#ffa773) plt.scatter(x=data.age[data.target==0],y=data.trestbps[data.target==0],c=#8de0ff) plt.legend([患病,'未患病']) plt.xlabel(年龄) plt.ylabel(血压) plt.show() 看上去随着年龄增长,血压更飘了?从这个结果可以看到的是,静息血压患病人和未患病的人在血压方面都是均匀分布的,随着年龄增长也没有明显的分层变化。所以并不能直接从静息血压很好的判断出是否患心脏病。
那么血压与其他什么有关呢?
比如心率?好,来看看。
血压(trestbps)和心率(thalach)关系 血压、心率这两个都来自于心脏的动能,相当于发动机力量和发动机转速。我猜这俩有点关系,一起看看
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() 现实情况是,这个样本集中,除了能显示出患病新率高这个已有结果外,血压和心率没有相关性。
胸痛类型和心脏病、血压三者关系 表中有个数据是胸痛类型四个,分别是0123,他们和心脏病有关系吗,作图看看。
此外这块我要说的是,我上边的翻译是1 典型、2非典型、3非心绞痛、4无症状。
但是数据集中是0123 ,我再kaggle里看了很多人的作品,没有合理解释这个的,所以这个数据我只可视化展示,不分析。
sns.swarmplot(x='target',y='trestbps',hue='cp',data=data,size=6) plt.xlabel('是否患病') plt.show() fig,ax=plt.subplots(1,2,figsize=(14,5)) sns.countplot(x='cp',data=data,hue='target',palette='set3',ax=ax[0]) ax[0].set_xlabel(胸痛类型) data.cp.value_counts().plot.pie(ax=ax[1],autopct='%1.1f%%',explode=[0.01,0.01,0.01,0.01],shadow=true,cmap='blues') ax[1].set_title(胸痛类型) 结论是:从上图可以看到的是0类疼痛的人在非患病群体中占大多数,而在患病群体中,123三种胸痛的人占了大部分。
运动引起的心绞痛与患病、心率关系 承接胸痛类型,运动引起心绞痛与是否患病有没有关系呢?与心率有没有关系呢?作图看一下
ps:运动引起心绞痛(exang: 1=有过;0=没有)
sns.swarmplot(x='exang',y='thalach',hue='target',data=data,size=6) plt.xlabel('有没有过运动引起心绞痛') plt.ylabel('最大心率') plt.show() 得到的这个图像很有意思!
虽然最大心率是入院时候测的,但是在没有运动引起心绞痛的人中,最大心率集中度比较高,在160-180之间,而他们都患有心脏病。
我推测是:他们有心脏病,运动就难受,所以就不运动,所以根本不会有“运动时产生胸痛”这种问题。
而在运动中产生胸痛的人中(右边为1的)他们有很多产生过胸痛,这种人心率比较高,在120-150之间集中着,而其中很多人并没有心脏病,只是心率比较高。
大血管数量(ca)和血压(trestbps)、患病关系 plt.figure(figsize=(15,5)) sns.swarmplot(y='trestbps',data=data,x='ca',hue='target',palette='rdbu_r',size=7) plt.xlabel('大血管数量') plt.ylabel('静息血压') plt.show() plt.figure(figsize=(15,5)) sns.catplot(x=ca,y=age,hue=target,kind=swarm,data=data,palette='rdbu_r') plt.xlabel('大血管显色数量') plt.ylabel('年龄' 这个血管数量指银光显色。具体医学含义没搜到,所以不分析。只是为0的和患病有很大的相关性
年龄(age)和胆固醇(chol)关系 在我初高中的时候,我妈妈告诉我说,每天鸡蛋黄不要超过两个,不然会引起胆固醇高,那时候身体健康,从来不信这些话。我后来上大学了连每天一个都没保证住,但我记住了这句话,所以看到胆固醇三个字会想起这个家庭教育哈哈。
胆固醇侧面反映了血脂,那么下边生成一下胆固醇、年龄、患病三者关系散点图。为了区分,这次我又换了个颜色。
plt.scatter(x=data.age[data.target==1],y=data.chol[data.target==1],c=orange) plt.scatter(x=data.age[data.target==0],y=data.chol[data.target==0],c=green) plt.legend([患病,'未患病']) plt.xlabel(年龄) plt.ylabel(胆固醇) plt.show() #箱型图 sns.boxplot(x=data.target,y=data.chol,data=data) 在这个样本集中,患病者和非患病者胆固醇含量分布没有明显的分层现象,箱型图显示结果是合理上下限是一样的,只是25%、50%、75%三条线患病的人稍微稍微低一些。
结论就是胆固醇并不能直接反映有没有心脏病这件事。
相关性分析 分析了很多,那么哪些和患病相关的,而数据间又有啥关系呢?做个图看看,颜色越绿越相关,越红越负相关
plt.figure(figsize=(15,10)) ax=sns.heatmap(data.corr(),cmap=plt.cm.rdylbu_r,annot=true,fmt='.2f') a,b=ax.get_ylim() ax.set_ylim(a+0.5,b-0.5) 图像很好看对不对,只看最后一行,是否患病和cp、thalach、slope正相关,和exang、oldpeak、ca、thal等负相关。
本篇分析了心脏病数据集中的部分内容,14列其实有非常多的组合方式去分析。此外本文没有用到模型,只是数据可视化的方式进行简要分析。
本文中由于图片过大,在手机浏览可能看不清楚,故开源了代码,欢迎大家自己动手可视化试试。
如果有什么建议意见,欢迎留言。

FPGA如何使用RAM分区循环移位法实现解交织器
苹果iOS10.2升级搞乌龙 很多果粉遭到牵累中
TDA8445各引脚功能及电压
hCaptcha已成为全球最大的独立验证码服务提供商
微星推出三款PRO MP242显示器
数据分析实战:利用python对心脏病数据集进行分析
无源探头的带宽到底有没有意义
评测迪奥科USB-C to Lightning数据线:长达2米,提供苹果MFi认证
倒装焊与球栅阵列封装:电子行业的关键技术
空调电子膨胀阀的作用
一文读懂捷豹I-PACE技术
电力高清无线监控系统的结构及方案设计
新能源物流车:瑞驰新能源自3月份以来,连续8个月获得销量第一
4G芯片攻防战激烈 高通“内伤”严重
那朵伴随着成长阵痛而扶摇直上的阿里云,今年也已经十周岁
Longsys江波龙旗下品牌FORESEE的SSD产品P800的介绍
【芯选择】CC1101芯片的模块实例
2023年Q1美国新能源市场分析
长虹彩电各种机型常见故障总览
Efinity在Debug时会出现UUID mismatch错误案例分享