- 条形图(Bar charts):用于显示不同类别之间的比较。
- 折线图(Line charts):用于显示一段时间内或不同类别之间的趋势。
- 饼状图(Pie charts):用于显示不同类别的比例或百分比。
- 直方图(Histograms):用于显示单个变量的分布。
- 热力图(Heatmaps):用于显示不同变量之间的相关性。
- 散点图(Scatter plots):用于表示两个连续变量之间的关系。
- 箱形图(Box plots):用于显示变量的分布和识别异常值。
使用 Python 创建数据可视化的一般步骤如下:
- 理解业务问题:这一步很重要,因为这关系到最后我们能否获得正确的可视化结果。
- 导入必要的库:如 Pandas, Seaborn, Matplotlib, Plotly。
- 加载数据集:加载需要分析和可视化的数据集。
- 数据清理和预处理:通过删除缺失值、重复值和异常值来对数据进行清洗和预处理。另外,将分类数据转换为数值数据。
- 统计汇总:计算描述性统计数据,如平均值、中位数、众数、标准差和相关系数,以便了解变量之间的关系。
- 数据可视化和解释:创建可视化来理解数据中的分布、关系和模式。然后解释可视化,从而获得关于数据的启发性见解和结论。
1. 理解业务问题
心血管疾病是全球人员死亡的主要原因。据世界卫生组织(WHO)统计,每年约有1790万人死于心脏病,其中85%的死亡是由心脏病发作和中风引起的。
在本文中,我们将探索心脏病发病数据集(获取方式见文末),利用 Python 为探索性数据分析创建数据可视化。
该数据集包含患者的各种变量数据,如年龄、性别、血压、胆固醇水平以及是否患有心脏病。我们的目标是根据患者的医疗属性来预测他们是否有心脏病发病的风险。
2. 加载必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
3. 加载数据集
heart = pd.read_csv('datasets/heart.csv')
现在我们已经加载了数据,让我们看一下 DataFrame 的前几行,对数据有一个基本的了解。
heart.head()
图片
我们一起来看看每列的含义:
- age:患者年龄
- sex:患者性别
- cp:胸痛类型(0-典型心绞痛;1-非典型心绞痛;2-非心绞痛;3-无症状)
- trbps:静息血压(单位:毫米汞柱)
- chol:胆固醇量(毫克/分)
- fbs:空腹血糖 > 120 mg/dl(1-true;0-false)
- restecg:静息心电图结果
0:正常
1:ST-T波异常(T 波反转和/或 ST 波升高或下降 > 0.05 mV)
2:根据埃斯蒂斯标准显示可能或明确的左心室肥厚
- thalachh:达到的最大心率
- exng:运动诱发心绞痛(1-是;0-否)
- oldpeak:前一个峰值
- slp:斜率
- caa:主要血管数量(0-3)
- thall:贫血率
- output:目标变量(0-更低的心脏病发病率;1-更高的心脏病发病率)
我们可以看到,数据集包含14列,包括目标列(output),它表示患者是否会心脏病发病。现在我们开始创建可视化。
4. 数据清洗和预处理
数据清洗的目的是为后面的分析和可视化做准备。比如检测缺失值:
heart.isnull().sum().sort_values(ascending=False).head(11)
图片
从输出中可以看出,该数据集中不存在缺失值。接下来,我们检测重复行:
heart.duplicated().sum()
输出:
1
我们直接删除重复值:
heart.drop_duplicates(keep='first', inplace=True)
输出:
0
到此,我们的清洗工作结束。接下来我们将会计算一些统计汇总信息。
5. 统计汇总信息
heart.describe().T
图片
从上面的统计信息摘要中我们可以得到的主要推论是,对于大多数列,其平均值与中位数相似(1/2百分位:50%)。
6. 数据可视化及解释
6.1 基于性别的数据可视化
条形图:
df = pd.crosstab(heart['output'], heart['sex'])
sns.set_style('white')
df.plot(kind='bar',
figsize=(6, 6),
color=['#c64343', '#e1d3c1'])
plt.title('Heart Attack Risk vs Sex ', fnotallow=16)
plt.xlabel('0 = Lower Risk 1 = Higher Risk', fnotallow=16)
plt.ylabel('Amount', fnotallow=16)
plt.legend(['Femal', 'Male'], fnotallow=14)
plt.xticks(rotatinotallow=0)
图片
饼图:
heart2 = heart.copy()
sex_mapping = {0: 'Female', 1: 'Male'}
heart2['sex'] = heart2['sex'].map(sex_mapping)
fig = px.pie(heart2,
names='sex',
template='presentation',
hole=0.6,
color_discrete_sequence=['#e1d3c1', '#c64343'])
# layout
fig.update_layout(title_text='Gender Distribution',
title_x=0.5,
fnotallow=dict(size=18),
autosize=False,
width=500,
height=500,
showlegend=False)
fig.add_annotation(dict(x=0.5, y=0.5, align='center',
xref='paper', yref='paper',
showarrow=False, font_size=22,
text="Gender
"))
fig.update_traces(textpositinotallow='outside', textinfo='percent+label', rotatinotallow=20)
fig.show()
图片
解释:男性患心脏病的风险比女性更高。
6.2 基于年龄的数据可视化
柱状图:
plt.figure(figsize=(14, 8))
sns.set(font_scale=1.2)
sns.set_style('white')
sns.countplot(x=heart['age'], palette='Reds')
plt.title('Count of Patients Age', fnotallow=20)
plt.xlabel('Age', fnotallow=16)
plt.ylabel('Count', fnotallow=16)
plt.show()
图片
直方图+核密度图:
sns.set(font_scale=1.3)
plt.figure(figsize=(8, 6))
sns.set_style('white')
sns.histplot(x=heart['age'], color='red', kde=True)
plt.title('Distribution of Patients Age', fnotallow=20)
plt.xlabel('Age', fnotallow=16)
plt.ylabel('Density', fnotallow=16)
plt.show()
图片
解释:大多数患者年龄在50-60岁之间,其中58岁的患者人数最多。
6.3 基于胆固醇水平的数据可视化
直方图+核密度图:
sns.set(font_scale=1.3)
sns.set_style('white')
plt.figure(figsize=(8, 6))
sns.histplot(x=heart[heart['output']==0]['chol'], color='blue', kde=True)
sns.histplot(x=heart[heart['output']==1]['chol'], color='red', kde=True)
plt.title('Heart Attack Risk vs Cholesterol', fnotallow=20)
plt.xlabel('Cholesterol Level', fnotallow=16)
plt.ylabel('Density', fnotallow=16)
plt.legend(['Lower Risk', 'Higher Risk'], fnotallow=14)
plt.show()
图片
折线图:
plt.figure(figsize=(8, 6))
sns.lineplot(y='chol', x='age', data=heart, color='red')
plt.title('Cholesterol with Age', fnotallow=20)
plt.xlabel('Age', fnotallow=16)
plt.ylabel('Cholesterol Level', fnotallow=16)
plt.show()
图片
解释:
- 大多数患者的胆固醇水平在200-300之间。
- 随着年龄的增长,体内的胆固醇水平很有可能增加。
6.4 基于胸痛类型的数据可视化
heart3 = heart.copy()
cp_mapping = {0: 'Typical angina', 1: 'Atypical angina',
2: 'Non-anginal pain', 3: 'Asymptomatic'}
heart3['cp'] = heart3['cp'].map(cp_mapping)
df = pd.crosstab(heart3['cp'], heart3['output'])
# Make the crosstab more visual
sns.set(font_scale=1.3)
sns.set_style('white')
df.plot(kind='bar',
figsize=(11, 7),
color=['#e1d3c1', '#c64343'])
plt.title('Heart Attack Risk vs. Chest Pain Type', fnotallow=20)
plt.xlabel('Chest Pain types', fnotallow=16)
plt.ylabel('Amount', fnotallow=16)
plt.legend(['Lower Risk', 'Higher Risk'], fnotallow=14)
plt.xticks(rotatinotallow=0)
图片
解释:
- 大多数患者为典型心绞痛类型。
- 非心绞痛患者心脏病发病的风险更高。
6.5 基于相关性的数据可视化
plt.figure(figsize=(12, 10))
sns.set(font_scale=0.9)
sns.heatmap(heart.corr(), annot=True, cmap='Reds')
plt.title('Correlation Between Variables', size=15)
plt.show()
图片
解释:
通过热力图我们可以看出以下变量之间存在强相关性:
- 胸痛类型(cp)和目标变量(output)
- 达到的最大心率(thalachh)和目标变量(output)
- 斜率(slp)和目标变量(output)
同时,我们也可以看出以下变量之间存在弱相关性:
- 前一个峰值(oldpeak)和目标变量(output)
- 主要血管数量(caa)和目标变量(output)
- 运动诱发心绞痛(exng)和目标变量(output)
7. 结论
在这篇文章中,我们使用数据可视化在数据集上做了一系列的实验和测试,基于各个变量对数据集做了一些分析,比如单变量分析和可视化(条形图、饼图、折线图、直方图);热力图可看作是双变量分析,因为它呈现了两两变量之间的相关性。
探索性分析(EDA)和数据可视化的主要目的是在做任何假设之前帮助我们更好的理解数据,它们能够让我们对数据分布、汇总统计、变量和异常值之间的关系有一个直观的理解。通过可视化,能够得出一些有价值的洞见,达到辅助策略决策的目的。