小学期实习02

实验名称

作业 2 心血管疾病数据探索分析

实验目的

  • 掌握使用jupyter notebook工具结合matplotlib观察数据
  • 掌握使用numpy等工具进行数据预处理和数据分析
  • 了解真实的数据分析场景

实验背景

心血管疾病是一组心脏和血管疾患的名称,包括:高血压(血压升高)、冠心病(心脏病发作)、脑血 管疾病(中风)、周围血管疾病、心力衰竭、风湿性心脏病、先天性心脏病、心肌病。 心血管疾病是全球的头号死因:每年死于心血管疾病的人数多于其它任何病因。估计在2012年有1750万 人死于心血管疾病,占全球死亡总数的31%。这些死者中,估计740万人死于冠心病,670万人死于中 风。四分之三以上的心血管疾病死亡发生在低收入和中等收入国家。大多数心血管疾病可以通过面向全 民的战略解决诸如烟草使用、不健康饮食和肥胖、缺乏身体活动和有害使用酒精等危险因素而得到预 防。

实验原理

1、Seaborn介绍

Seaborn是基于matplotlib的图形可视化python包。它提供了一种高度交互式界面,便于用户能够做出 各种有吸引力的统计图表。
Seaborn是在matplotlib的基础上进行了更高级的API封装,从而使得作图更加容易,在大多数情况下使 用seaborn能做出很具有吸引力的图,而使用matplotlib就能制作具有更多特色的图。应该把Seaborn视 为matplotlib的补充,而不是替代物。同时它能高度兼容numpy与pandas数据结构以及scipy与 statsmodels等统计模式。

2、NumPy介绍

NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外 也针对数组运算提供大量的数学函数库。
NumPy 的前身 Numeric 最早是由 Jim Hugunin 与其它协作者共同开发,2005 年,Travis Oliphant 在 Numeric 中结合了另一个同性质的程序库 Numarray 的特色,并加入了其它扩展而开发了 NumPy。 NumPy 为开放源代码并且由许多协作者共同维护开发。
NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:
一个强大的N维数组对象 ndarray 广播功能函数 整合 C/C++/Fortran 代码的工具 线性代数、傅里叶变换、随机数生成等功能

3、pandas 介绍

pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库 和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便 捷地处理数据的函数和方法。你很快就会发现,它是使Python成为强大而高效的数据分析环境的重要因 素之一。

实验环境

  • Ubuntu 16.04.6 LTS
  • Python 3.6.5
  • pandas 0.25.0
  • numpy 1.18.3
  • seaborn 0.10.0
  • matplotlib 3.2.0

实验步骤

步骤一:

打开jupyter notebook。本实验使用python中的numpy、pandas、seaborn等库来进行数据 分析和数据可视化,使用的工具是试验机中的jupyter notebook。

步骤二:

加载本实验需要使用的python库。注意:本试验机的python库都已安装过,直接使用即可,不 需要再次安装。

import pandas as pd  #导入pandas,用于数据分析
import numpy as np  #导入numpy,用于数学计算
import seaborn as sns    # 导入seaborn,用于绘图
import matplotlib     # 导入matplotlib,用于绘图
import matplotlib.pyplot as plt
import matplotlib.ticker
from matplotlib import rcParams
import warnings
warnings.filterwarnings('ignore')      #设置warnings,用于忽略无用的警告信息
步骤三:

本次作业将优先选择 Seaborn 用于绘图,下面我们定义 Seaborn 全局绘图参数,保证后续图 像更加整洁美观。

sns.set()       #默认样式使用seaborn
sns.set_context(    #设置绘图参数
    "notebook",     # 设置上下文是notebook
    font_scale=1.5, # 设置字体大小
    rc={
        "figure.figsize": (11, 8),  # 设置图的大小
        "axes.titlesize": 18     #设置轴标题的大小
    }
)

rcParams['figure.figsize'] = 11, 8  #设置plt的图像大小
步骤四:

读取并预览数据集

df = pd.read_csv(
    'mlbootcamp5_train.csv', sep=';')  #使用pandas读取数据,设置分隔符为分号
print('Dataset size: ', df.shape)    # 打印出数据的大小
df.head() # 预览前5行
Dataset size:  (70000, 13)
idagegenderheightweightap_hiap_locholesterolglucsmokealcoactivecardio
0018393216862.011080110010
1120228115685.014090310011
2218857116564.013070310001
3317623216982.0150100110011
4417474115656.010060110000

可以看到数据共70000行,13列。

再来看一下数据集的特征:

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 70000 entries, 0 to 69999
Data columns (total 13 columns):
id             70000 non-null int64
age            70000 non-null int64
gender         70000 non-null int64
height         70000 non-null int64
weight         70000 non-null float64
ap_hi          70000 non-null int64
ap_lo          70000 non-null int64
cholesterol    70000 non-null int64
gluc           70000 non-null int64
smoke          70000 non-null int64
alco           70000 non-null int64
active         70000 non-null int64
cardio         70000 non-null int64
dtypes: float64(1), int64(12)
memory usage: 6.9 MB

所以数据均为医学检查时收集,主要包含 3 种类别的特征:

  • Objective Feature: 基础事实数据。
  • Examination Feature: 体检结果。
  • Subjective Feature: 患者给出的主观信息。

每列的含义:age-年龄 height-身高 weight-体重 gender-性别 ap_hi-收缩压 ap_lo-舒张压 cholesterol胆固醇 gluc-葡萄糖 smoke-吸烟 alco-饮酒量 active-体育活动 cardio-是否存在心血管疾病

步骤五:

接下来,我们探索数据值分布情况。这里使用 catplot() 绘制出变量特征的计数条形图。

# melt把宽数据--->>长数据,value_vars是需要转换的列名
df_uniques = pd.melt(frame=df, value_vars=['gender', 'cholesterol',
                                           'gluc', 'smoke', 'alco',
                                           'active', 'cardio'])
# 根据variable和value分组,统计value的数量
df_uniques = pd.DataFrame(df_uniques.groupby(['variable',
                                              'value'])['value'].count()) \
    .sort_index(level=[0, 1]) \
    .rename(columns={'value': 'count'}) \
    .reset_index()
# catplot:用分类型数据(categorical data)绘图
#  hue='value':根据value 用不同颜色区分
# kind='bar':条形图
sns.catplot(x='variable', y='count', hue='value',
    data=df_uniques, kind='bar', height=12)
<seaborn.axisgrid.FacetGrid at 0x29717c63748>

在这里插入图片描述

步骤六:

接下来,让我们按目标值分割数据集,这样往往可以通过绘图结果快速找出相对重要的特征。

# melt把宽数据--->>长数据,value_vars是需要转换的列名df_uniques = pd.melt(frame=df, value_vars=['gender', 'cholesterol',                                           'gluc', 'smoke', 'alco',                                           'active'], id_vars=['cardio'])# # 根据variable和value分组,统计value的数量df_uniques = pd.DataFrame(df_uniques.groupby(['variable', 'value',                                              'cardio'])['value'].count()) \    .sort_index(level=[0, 1]) \    .rename(columns={'value': 'count'}) \    .reset_index()# catplot:用分类型数据(categorical data)绘图#  hue='value':根据value 用不同颜色区分# kind='bar':条形图sns.catplot(x='variable', y='count', hue='value',            col='cardio', data=df_uniques, kind='bar', height=9)
<seaborn.axisgrid.FacetGrid at 0x297298b66d8>

在这里插入图片描述

可以看到胆固醇和葡萄糖水平对目标变量影响明显较大。这是巧合吗?

步骤七:

接下来,我们一起来挑战几个问题。

1、数据集中有多少男性和女性?由于 gender 特征没有说明男女,需要通过分析身高计算得出

# 通过gender分组,求height的平均值df.groupby('gender')['height'].mean()
gender1    161.3556122    169.947895Name: height, dtype: float64

2、数据集中男性和女性,哪个群体饮酒的频次更高?

# 通过gender分组,求alco的平均值df.groupby('gender')['alco'].mean()
gender1    0.0255002    0.106375Name: alco, dtype: float64

3、数据集中男性和女性吸烟者所占百分比的差值是多少?

# 通过gender分组,求smoke的平均值df.groupby('gender')['smoke'].mean()# 计算百分比的差值round(100 * (df.loc[df['gender'] == 2, 'smoke'].mean() - df.loc[df['gender'] == 1, 'smoke'].mean()))
20

4、数据集中吸烟者和非吸烟者的年龄中位数之间的差值(以月计)近似是多少?需要尝试确定出数据集中 age 合理的表示单位,规定 1 年为 365.25 天。

# 通过smoke分组,求age的中位数,并除以一年的天数df.groupby('smoke')['age'].median() / 365.25 # 求中位数的差值(df[df['smoke'] == 0]['age'].median() - df[df['smoke'] == 1]['age'].median()) / 365.25 * 12
19.613963039014372

5、欧洲心脏病学会的网站上给出了 SCORE scale 量表。它可以用于计算未来 10 年心血管疾病死亡的风险。

在这里插入图片描述

让我们来看看最右上角的矩形,也就是 60 到 65 岁的吸烟男性的子集。其中,矩形的左下角看到一个值 9,在右上角看到 47。量表意味着对于收缩压(纵坐标)低于 120 (正常血压)的性别年龄组的人来说,心血管疾病的风险估计比收缩压为 [160,180)[160,180) 的患者(高血压)低 5 倍(47/9)。

接下来,让我们结合量表,并利用挑战数据集进行计算。这里需要注意的是,量表中胆固醇(Cholesterol)水平和挑战数据单位不太一样,我们使用对应关系为:4 mmol/l →→ 1, 5-7 mmol/l →→ 2, 8 mmol/l →→ 3

计算 [60,65)[60,65) 年龄区间下,较健康人群(胆固醇类别 1,收缩压低于 120)与高风险人群(胆固醇类别为 3,收缩压 [160,180)[160,180))各自心血管病患所占比例。并最终求得二者比例的近似倍数。

df['age_years'] = (df['age'] / 365.25).round().astype('int') # 最大有65岁df['age_years'].max()# 选择 [60,65)年龄区间:smoking_old_men = df[(df['gender'] == 2) & (df['age_years'] >= 60)                     & (df['age_years'] < 65) & (df['smoke'] == 1)]# 胆固醇类别为 1,收缩压低于 120,心血管疾病患者的比例为 26%。smoking_old_men[(smoking_old_men['cholesterol'] == 1) &                (smoking_old_men['ap_hi'] < 120)]['cardio'].mean()# 胆固醇类别为 3,收缩压 [160,180),心血管疾病患者的比例为 86%。smoking_old_men[(smoking_old_men['cholesterol'] == 3) &                (smoking_old_men['ap_hi'] >= 160) &                (smoking_old_men['ap_hi'] < 180)]['cardio'].mean()
0.8636363636363636

所以,挑战数据给出的比例大约是 3 倍,而量表给出的是 5 倍。当然,这依赖与给定年龄组中的病人比例。

6、BMI 指数分析,挑战将需要创建一个新的特征 BMI,BMI 为身高体重指数,其可以反映体重的标准情况,计算公式为:

在这里插入图片描述

正常 BMI 指数一般在 18.5 到 25 之间。

请选择下面叙述正确的有:

  • [ A ] 数据集样本中 BMI 中位数在正常范围内。
  • [ B ] 女性的平均 BMI 指数高于男性。
  • [ C ] 健康人群的 BMI 平均高于患病人群。
  • [ D ] 健康和不饮酒男性中,BMI 比健康不饮酒女性更接近正常值
# 根据公式计算BMI指数df['BMI'] = df['weight'] / (df['height'] / 100) ** 2 # 求中位数df['BMI'].median() # 根据gender分组,求不同性别的BMI中位数df.groupby('gender')['BMI'].median() # 根据性别、是否饮酒、是否健康分组,分别求BMI指数对它的影响df.groupby(['gender', 'alco', 'cardio'])['BMI'].median().to_frame()
BMI
genderalcocardio
10025.654372
127.885187
1027.885187
130.110991
20025.102391
126.674874
1025.351541
127.530797

7、数据清理:你可能会注意到给出的数据并不够完美,在进一步可视化之前,我们需要对数据进行清洗。

*问题:*请按照以下列举的项目,过滤掉数据中统计有误的部分:

  • 血压特征中,舒张压高于收缩压的样本。
  • 身高特征中,低于 2.5% 分位数的样本。
  • 身高特征中,高于 97.5% 分位数的样本。
  • 体重特征中,低于 2.5% 分位数的样本。
  • 体重特征中,高于 97.5% 分位数的样本。
# quantile 求分位数filtered_df = df[(df['ap_lo'] <= df['ap_hi']) &                 	(df['height'] >= df['height'].quantile(0.025)) &                 	(df['height'] <= df['height'].quantile(0.975)) &                 	(df['weight'] >= df['weight'].quantile(0.025)) &                 	(df['weight'] <= df['weight'].quantile(0.975))]

清洗掉的数据占原数据总量的近似百分比?

1 - filtered_df.shape[0] / df.shape[0]
0.09630000000000005

8、要更好地理解数据集特征,接下来使用过滤之后的数据创建特征之间相关系数的矩阵。 使用 heatmap() 绘制特征之间的皮尔逊相关性系数矩阵。

# 计算相关性系数矩阵 df = filtered_df.copy() corr = df.corr(method='pearson') # 创建一个 Mask 来隐藏相关矩阵的上三角形 mask = np.zeros_like(corr, dtype=np.bool) mask[np.triu_indices_from(mask)] = True # 绘制图像 f, ax = plt.subplots(figsize=(12, 9)) sns.heatmap(corr, mask=mask, vmax=1, center=0, annot=True, fmt='.1f',            						square=True, linewidths=.5, cbar_kws={"shrink": .5})
<matplotlib.axes._subplots.AxesSubplot at 0x29729fa9ef0>

在这里插入图片描述

9、前面的探索中,我们知道性别对应 1 和 2,虽然不知道不同性别对应哪个值,但可以通过平均身高和体重来确定。问题:绘制身高和性别之间的小提琴图 violinplot()。

这里建议通过 hue 参数按性别划分,并通过 scale 参数来计算性别对应的具体数量。

# melt把宽数据--->>长数据,value_vars是需要转换的列名,id_vars是不需要转换的列名df_melt = pd.melt(frame=df, value_vars=['height'], id_vars=['gender'])plt.figure(figsize=(12, 10))ax = sns.violinplot(    x='variable',      # X轴    y='value',         # Y轴    hue='gender',    # 指定按照性别区分颜色    palette="muted",   # 柔和调色    split=True,    data=df_melt,    scale='count',    scale_hue=False)

在这里插入图片描述

10、绘制身高和性别之间的核密度图 kdeplot。

通过核密度图可以更清楚地看到性别之间的差异,但却无法得到每个性别对应的具体人数。

# FacetGrid 结构化多绘图网格# kdeplot 核密度估计图sns.FacetGrid(df, hue="gender", height=12) \   .map(sns.kdeplot, "height").add_legend()
<seaborn.axisgrid.FacetGrid at 0x2972b7bf390>

在这里插入图片描述

11、大多数情况下,皮尔逊相关性指数可以看出特征之间的相关程度。不过,这里我们进一步绘制 Spearman’s rank correlation coefficient 斯皮尔曼等级相关系数对应的图像。它利用单调方程评价两个统计变量的相关性,是用于衡量两个变量的依赖性的非参数指标。

问题:使用 heatmap() 绘制特征之间的斯皮尔曼等级相关系数矩阵。

# 计算斯皮尔曼等级相关系数corr = df[['id', 'age', 'height', 'weight',           'ap_hi', 'ap_lo', 'cholesterol',           'gluc']].corr(method='spearman')# 创建一个 Mask 来隐藏相关矩阵的上三角形mask = np.zeros_like(corr, dtype=np.bool)mask[np.triu_indices_from(mask)] = Truef, ax = plt.subplots(figsize=(12, 10))# 绘制图像sns.heatmap(corr, mask=mask, vmax=1, center=0, annot=True, fmt='.2f',            square=True, linewidths=.5, cbar_kws={"shrink": .5})
<matplotlib.axes._subplots.AxesSubplot at 0x2972cbe1748>

在这里插入图片描述

12、上面,我们已经计算过受访者的年龄。接下来,我们对其进行可视化。

问题:请使用 countplot() 绘制年龄分布计数图,横坐标为年龄,纵坐标为对应的人群数量。

# countplot:以bar的形式展示每个类别的数量sns.countplot(x="age_years", hue='cardio', data=df)
<matplotlib.axes._subplots.AxesSubplot at 0x2972cbf5ac8>

在这里插入图片描述

实验总结

本实验主要基于心血管疾病数据进行探索分析,结合jupyter notebook,先利用pandas导入数据并预览,了解每个特征的意义,通过绘制条形统计图,大致分析哪些特征对目标变量的影响大,后面利用挑战问题的形式对数据进行分析,从易到难,从分析男性女性比例到男性和女性吸烟者所占百分比的差值,再到BMI指数分析,然后进行数据预处理,最后进行数据可视化,绘制年龄分布计数图斯皮尔曼等级相关系数矩阵等。

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值