当前位置: 首页 > 科技观察

数据分析实践:用Python分析心脏病数据集

时间:2023-03-17 11:53:55 科技观察

我们都怕生病,但是从小对感冒发烧这种病已经麻木了,因为他一个星期就会痊愈,但是作为我们长大了,各种炎症、三高、心脏病、冠心病都是应运而生的。心脏病,作为一种一发生就让人觉得可怕的疾病,每年夺去的生命数量不详。而那些从疾病中幸存下来的人也不得不在余生中放弃太多,以防止心脏病发作。当我们没有生病的时候,我们总觉得它离我们很远。这就是我对心脏病的了解,我不知道是什么原因引起的,我也不知道是什么原因引起的。至于病后如何维持正常的生活等等,我一概不知。今天在kaggle上看到一个心脏病数据(数据集的下载地址和源码见文末),就以此为基础深入分析一下。数据集读取和简单描述首先导入库并设置超参数,方便后续分析。importnumpyasnpimportpandasapdimportmatplotlib.pyplotaspltimportseabornassns通过读取和描述数据集可以得到这两个表:可以看到有303行14列数据,每列的标题分别是age,sex,cp,...,target。就像每次去医院的化验单一样,很多非专业人士不知道。所以使用官方的解释,翻译过来的意思是:age:朋友的年龄sex:朋友的性别(1=男,0=女)cp:经历过的胸痛类型(值1:典型心绞痛,值2:非典型心绞痛,值3:非心绞痛,值4:无症状)trestbps:朋友的静息血压(入院时的毫米汞柱)chol:朋友的胆固醇测量值,单位:mg/dlfbs:人的空腹血糖(>120mg/dl,1=真;0=假)restecg:静息心电图测量(0=正常,1=ST-T波异常,2=根据Estes'显示可能或确定的左心室肥大标准)thalach:这个朋友达到的最大心率exang:运动诱发的心绞痛(1=曾经;0=无).这块比较专业,可以点这里看解读)slope:最高运动ST段的斜率(值1:上坡,值2:平坦,值3:下坡)ca:主血数荧光显示的血管(0-4)thal:一种称为地中海贫血的血液疾病(3=正常;6=固定缺陷;7=可逆缺陷)目标:心脏病(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)#2subplotsfig.set_size_inches(w=15,h=5)#设置画布大小sns.countplot(x="sex",data=data,ax=ax[0])plt.xlabel("性别(0=女,1=男)")sns.countplot(x="target",data=data,ax=ax[1])plt.xlabel("生病与否(0=notsick,1=sick)")sns.swarmplot(x='sex',y='age',hue='target',data=data,ax=ax[2])plt.xlabel("gender(0=female,1=male)")plt.show()从这张tripletmap可以看出男1多于女0,患病target1多于未患病target10.在年龄分布小提琴图中,可以看到女性患者的比例多于男性患者。下面我们详细分解一下比例,看下面的代码和图表: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(["Notsick","withheartdisease"])plt.ylabel('Numberofpeople')plt.show()可以看到这个数据集中的女性患者数量是健康患者数量的三倍多。我留了一个问题,女性是不是更容易得心脏病?百度了一下,发现问这个问题的人很多,但是没有一个具体的、科学的答案。谷歌也是如此。可能需要搜索文献才能找到这个答案,但这不是本文的目的,所以我没有搜索这个真实的比例。在这个数据集中,男性是女性的两倍,分别为207人和96人;受影响的患者人数略多于未受影响的患者,分别为165和138名受影响的患者。因为年龄可能是连续的,所以在第三张图中做了年龄、性别、疾病的关系。单从颜色的观察可以发现,在这个数据集中,女性的患病率要大于男性。通过第四张图统计,可以计算出男性患病率为44.9%,女性患病率为75%。需要注意的是,本文得到的流行率仅针对该数据集。我们通过下面的代码来看一下年龄和疾病的关系:患病率是否随年龄变化?覆盖率应该增加1000倍才能解释一些问题——也就是年龄和心脏病的关系)pd.crosstab(data.age,data.target).plot(kind="bar",figsize=(25,8))plt.title('疾病分布随年龄变化')plt.xlabel('age')plt.ylabel('ratio')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(["disease","notsick"])plt.xlabel("age")plt.ylabel("maximumheartrate")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[数据.target==0],y=data.trestbps[data.target==0],c="#8DE0FF")plt.legend(["疾病",'没生病'])plt.xlabel("年龄")plt.ylabel("bloodpressure")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(["疾病",'notIllness'])plt.xlabel("heartrate")plt.ylabel("bloodpressure")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=ever;0=no)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('数字colored')plt.ylabel('age'指的是银光显示的血管数量,具体的医学意义没找到,所以不分析,只有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(["disease",'notsick'])plt.xlabel("age")plt.ylabel("cholesterol")plt.show()#boxplotsns.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列其实有很多组合可以分析。另外,本文不使用模型,而是以数据可视化的形式进行简要分析。本文由于图片较大,手机端浏览可能看不清楚,故代码开源,欢迎大家自行可视化尝试。