探索性數據分析(EDA)之數據可視化案例:附數據集和源碼
Python 提供了一組豐富的庫,使我們能夠快速有效地創建可視化。在使用 Python 進行探索性數據分析過程中有幾種常用的可視化類型,包括:
- 條形圖(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="<span style='font-size: 26px; color=#555; font-family: Arial'>Gender<br></span>"))
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)和數據可視化的主要目的是在做任何假設之前幫助我們更好的理解數據,它們能夠讓我們對數據分布、匯總統計、變量和異常值之間的關系有一個直觀的理解。通過可視化,能夠得出一些有價值的洞見,達到輔助策略決策的目的。