第四章:Seaborn分类图 (Categorical Plots) 第四章:Seaborn 分类图 (Categorical Plots) 详解 引言 在数据可视化领域,理解不同类型数据的特点至关重要。数据通常可以分为数值型数据和类别型数据。数值型数据可以进行数学运算和排序,例如年龄、收入、温度等;而类别型数据则代表不同的类别或分组,例如性别、城市、产品类型等。针对类别型数据的可视化,Seaborn 提供了强大的分类图 (Categorical Plots) 工具,帮助我们深入探索类别变量与数值变量之间的关系,以及类别变量内部的分布情况。 1. Seaborn 分类图概览 Seaborn 的分类图旨在可视化一个或多个类别变量与一个数值变量之间的关系。
引言
在数据可视化领域,理解不同类型数据的特点至关重要。数据通常可以分为数值型数据和类别型数据。数值型数据可以进行数学运算和排序,例如年龄、收入、温度等;而类别型数据则代表不同的类别或分组,例如性别、城市、产品类型等。针对类别型数据的可视化,Seaborn 提供了强大的分类图 (Categorical Plots) 工具,帮助我们深入探索类别变量与数值变量之间的关系,以及类别变量内部的分布情况。
1. Seaborn 分类图概览
Seaborn 的分类图旨在可视化一个或多个类别变量与一个数值变量之间的关系。它们能够有效地展示不同类别之间数值变量的分布、集中趋势、离散程度以及类别之间的比较。
Seaborn 提供了两种创建分类图的主要方式:
catplot() 函数 (Figure-level interface): catplot() 是一个图形级别的函数,它建立在 FacetGrid 之上,可以绘制多种类型的分类图,并方便地进行分面 (faceting) 操作,将数据按照额外的类别变量进行分组,绘制子图矩阵。
Axes-level 函数 (轴级别函数): Seaborn 还提供了一系列基于轴级别 (axes-level) 的函数,例如 boxplot(), violinplot(), stripplot() 等。这些函数直接在 Matplotlib 轴对象上绘图,更加灵活,可以与其他 Matplotlib 图表元素自由组合。
1.1 catplot() 函数:强大的分类图入口
catplot() 函数是 Seaborn 中创建分类图的首选方法。它通过 kind 参数来指定具体的图表类型,并提供了丰富的参数来控制图表的外观和布局。
catplot() 函数的语法结构:
seaborn.catplot( data=None, *, x=None, y=None, hue=None, col=None, row=None, col_wrap=None, kind='strip', height=3.5, aspect=1, palette=None, hue_order=None, col_order=None, row_order=None, margin_titles=False, sharex=True, sharey=True, facet_kws=None, **kwargs )
核心参数解释:
data: DataFrame, array, 或 lists 等数据输入。
x, y, hue: 指定用于绘图的变量名称。x 通常是类别变量 (横轴),y 通常是数值变量 (纵轴), hue 是用于颜色编码的类别变量。
col, row: 用于分面 (faceting) 的类别变量。col 将类别变量的不同水平放置在列上,row 将类别变量的不同水平放置在行上,从而创建子图矩阵。
kind: 指定要绘制的分类图类型。可选值包括:
"strip" (默认): 散点图
"swarm": 分簇散点图
"box": 箱线图
"violin": 小提琴图
"boxen": 分箱线图
"point": 点图
"bar": 条形图
"count": 计数图
height, aspect: 控制子图的高度和宽高比。
palette: 指定调色板。
hue_order, col_order, row_order: 指定类别变量的显示顺序。
sharex, sharey: 控制子图之间是否共享 x 轴和 y 轴。
facet_kws: 传递给 FacetGrid 的其他参数。
**kwargs: 传递给底层绘图函数的其他参数 (例如,传递给 matplotlib.pyplot.scatter() 的参数)。
catplot() 工作原理 Mermaid 图:
图表解释:
catplot() 函数接收数据和绘图参数。
根据 kind 参数选择具体的分类图类型 (例如 stripplot, boxplot 等)。
根据 col 和 row 参数判断是否需要进行分面。
如果需要分面,则使用 FacetGrid 创建子图网格。
如果不需要分面,则直接在当前的 Matplotlib Axes 对象上绘图。
根据选择的图表类型,调用相应的轴级别函数 (例如 sns.stripplot(), sns.boxplot() 等) 进行绘制。
返回 FacetGrid 对象 (分面情况) 或 Axes 对象 (单图情况)。
图表最终展示。
1.2 Axes-level 分类图函数
Seaborn 还提供了一系列直接在 Matplotlib 轴对象上绘图的分类图函数。这些函数更加灵活,可以与 Matplotlib 的其他绘图元素自由组合。
常用的 Axes-level 分类图函数包括:
boxplot(): 箱线图
violinplot(): 小提琴图
stripplot(): 散点图
swarmplot(): 分簇散点图
countplot(): 计数图
barplot(): 条形图
pointplot(): 点图
这些 Axes-level 函数的参数和用法与 catplot() 函数类似,主要的区别在于它们直接在轴对象上绘图,而不是通过 catplot() 统一管理。
2. 常用分类图类型详解与代码实践
接下来,我们将详细介绍 Seaborn 中常用的分类图类型,并结合代码示例进行实践。我们将使用 Seaborn 内置的 iris 数据集作为示例数据。
import seaborn as sns import matplotlib.pyplot as plt # 加载 iris 数据集 iris = sns.load_dataset('iris')
2.1 散点图 (stripplot() 和 catplot(kind='strip'))
散点图 (stripplot()) 是最基础的分类图之一。它将每个数据点绘制成散点,并按照类别变量在横轴上排列。散点图可以直观地展示每个类别的数据分布情况,但当数据点重叠较多时,可能会难以区分。
代码示例:
# 使用 stripplot() sns.stripplot(x='species', y='sepal_length', data=iris) plt.title('Stripplot of Sepal Length by Species') plt.show() # 使用 catplot(kind='strip') sns.catplot(x='species', y='sepal_length', data=iris, kind='strip') plt.suptitle('Catplot (kind=strip) of Sepal Length by Species', y=1.02) # 调整标题位置 plt.show()
代码解释:
sns.stripplot(x='species', y='sepal_length', data=iris): 使用 stripplot() 函数,指定 x 轴为 'species' (鸢尾花种类),y 轴为 'sepal_length' (花萼长度),数据来源为 iris 数据集。
sns.catplot(x='species', y='sepal_length', data=iris, kind='strip'): 使用 catplot() 函数,并设置 kind='strip',效果与 stripplot() 相同。
plt.title() 和 plt.suptitle(): 设置图表标题。plt.suptitle() 用于 catplot() 生成的图形级别标题。
散点图的优点:
直观展示每个数据点。
易于理解和解释。
散点图的缺点:
数据点重叠时,难以区分密度。
不适合展示数据的分布形状。
2.2 分簇散点图 (swarmplot() 和 catplot(kind='swarm'))
分簇散点图 (swarmplot()) 是散点图的改进版本。它使用一种避免点重叠的算法,将每个类别的数据点分散排列,形成类似蜂群的效果。分簇散点图可以更好地展示每个类别的数据分布,并避免散点图的点重叠问题。
代码示例:
# 使用 swarmplot() sns.swarmplot(x='species', y='sepal_length', data=iris) plt.title('Swarmplot of Sepal Length by Species') plt.show() # 使用 catplot(kind='swarm') sns.catplot(x='species', y='sepal_length', data=iris, kind='swarm') plt.suptitle('Catplot (kind=swarm) of Sepal Length by Species', y=1.02) plt.show()
代码解释:
stripplot() 示例类似,只是将函数替换为 swarmplot() 或 catplot(kind='swarm')。分簇散点图的优点:
避免点重叠,清晰展示数据分布。
比散点图更易于比较不同类别的数据密度。
分簇散点图的缺点:
数据量较大时,绘制速度较慢。
不适合展示数据的分布形状 (更侧重于展示每个数据点)。
2.3 箱线图 (boxplot() 和 catplot(kind='box'))
箱线图 (boxplot()) 是一种常用的统计图表,用于展示数据的分布概况,包括中位数、四分位数、上下边缘以及异常值。箱线图能够清晰地展示不同类别数据的中心位置、离散程度和异常值情况。
代码示例:
# 使用 boxplot() sns.boxplot(x='species', y='sepal_length', data=iris) plt.title('Boxplot of Sepal Length by Species') plt.show() # 使用 catplot(kind='box') sns.catplot(x='species', y='sepal_length', data=iris, kind='box') plt.suptitle('Catplot (kind=box) of Sepal Length by Species', y=1.02) plt.show()
代码解释:
boxplot() 或 catplot(kind='box')。箱线图的组成部分:
箱体 (Box): 箱体的上下边缘分别代表数据的上四分位数 (Q3) 和下四分位数 (Q1),箱体内部包含 50% 的数据。箱体中间的线代表数据的中位数 (Q2)。
须 (Whiskers): 须从箱体的上下边缘延伸出来,通常延伸到距离箱体边缘 1.5 倍四分位距 (IQR = Q3 - Q1) 的位置,或者延伸到数据中的最大值和最小值 (在 1.5 倍 IQR 范围内)。
异常值 (Outliers): 超出须范围的数据点被认为是异常值,通常用点或圆圈表示。
箱线图的优点:
简洁明了地展示数据的分布概况 (中位数、四分位数、离散程度、异常值)。
易于比较不同类别数据的分布差异。
对异常值敏感。
箱线图的缺点:
无法展示数据的具体分布形状 (例如,是否是正态分布)。
对于多峰分布的数据,箱线图可能无法充分展示数据的复杂性。
2.4 小提琴图 (violinplot() 和 catplot(kind='violin'))
小提琴图 (violinplot()) 结合了箱线图和核密度估计 (Kernel Density Estimation, KDE) 的特点。它在箱线图的基础上,使用 KDE 估计数据的分布形状,并将分布形状对称地绘制在箱线图的两侧,形成类似小提琴的形状。小提琴图比箱线图更详细地展示了数据的分布形状,能够更好地比较不同类别数据的分布差异。
代码示例:
# 使用 violinplot() sns.violinplot(x='species', y='sepal_length', data=iris) plt.title('Violinplot of Sepal Length by Species') plt.show() # 使用 catplot(kind='violin') sns.catplot(x='species', y='sepal_length', data=iris, kind='violin') plt.suptitle('Catplot (kind=violin) of Sepal Length by Species', y=1.02) plt.show()
代码解释:
violinplot() 或 catplot(kind='violin')。小提琴图的组成部分:
小提琴形状: 小提琴的宽度表示数据在该取值范围内的密度,越宽表示数据越集中。小提琴的形状反映了数据的分布形状。
内部箱线图 (可选): 小提琴图内部可以叠加箱线图,以便同时展示数据的分布形状和箱线图统计信息。
小提琴图的优点:
详细展示数据的分布形状。
比箱线图更易于比较不同类别数据的分布差异。
结合了箱线图的统计信息和 KDE 的分布形状信息。
小提琴图的缺点:
比箱线图更复杂,可能需要一些时间来理解。
对于数据量较小的情况,KDE 估计可能不够稳定。
2.5 分箱线图 (boxenplot() 和 catplot(kind='boxen'))
分箱线图 (boxenplot()),也被称为 letter-value plot,是一种增强的箱线图。它通过绘制多个嵌套的箱体来更详细地展示数据的分布尾部信息。分箱线图能够更有效地展示数据的离群值和尾部分布情况,特别适合于展示重尾分布的数据。
代码示例:
# 使用 boxenplot() sns.boxenplot(x='species', y='sepal_length', data=iris) plt.title('Boxenplot of Sepal Length by Species') plt.show() # 使用 catplot(kind='boxen') sns.catplot(x='species', y='sepal_length', data=iris, kind='boxen') plt.suptitle('Catplot (kind=boxen) of Sepal Length by Species', y=1.02) plt.show()
代码解释:
boxenplot() 或 catplot(kind='boxen')。分箱线图的特点:
绘制多个嵌套的箱体,每个箱体代表不同的百分位数范围。
更详细地展示数据的尾部分布和离群值。
适合展示重尾分布的数据。
分箱线图的优点:
详细展示数据的尾部分布信息。
更好地识别离群值。
适合展示重尾分布的数据。
分箱线图的缺点:
比箱线图更复杂,可能需要一些时间来理解。
对于数据量较小的情况,分箱线图可能不够稳定。
2.6 条形图 (barplot() 和 catplot(kind='bar'))
条形图 (barplot()) 用于展示每个类别变量的平均值或其他统计量。条形图的高度代表统计量的值,误差线 (error bar) 通常表示数据的置信区间或标准差。条形图适用于比较不同类别变量的平均水平。
代码示例:
# 使用 barplot() sns.barplot(x='species', y='sepal_length', data=iris) plt.title('Barplot of Sepal Length by Species') plt.show() # 使用 catplot(kind='bar') sns.catplot(x='species', y='sepal_length', data=iris, kind='bar') plt.suptitle('Catplot (kind=bar) of Sepal Length by Species', y=1.02) plt.show()
代码解释:
barplot() 或 catplot(kind='bar')。条形图的特点:
展示每个类别变量的平均值 (默认)。
可以自定义统计量函数 (例如,中位数、总和等)。
误差线表示数据的置信区间或标准差。
条形图的优点:
简洁明了地比较不同类别变量的平均水平。
误差线可以展示数据的变异性。
条形图的缺点:
仅展示平均值等统计量,无法展示数据的完整分布信息。
对于类别较多的情况,条形图可能显得拥挤。
2.7 计数图 (countplot() 和 catplot(kind='count'))
计数图 (countplot()) 用于展示每个类别变量的计数 (频数)。计数图实际上是条形图的一种特殊形式,它自动计算每个类别变量的频数,并绘制条形图。计数图适用于展示类别变量的分布情况。
代码示例:
# 使用 countplot() sns.countplot(x='species', data=iris) plt.title('Countplot of Species') plt.show() # 使用 catplot(kind='count') sns.catplot(x='species', data=iris, kind='count') plt.suptitle('Catplot (kind=count) of Species', y=1.02) plt.show()
代码解释:
sns.countplot(x='species', data=iris): 使用 countplot() 函数,指定 x 轴为 'species',数据来源为 iris 数据集。注意 countplot() 只需要指定一个类别变量 x,不需要指定 y 轴变量。
sns.catplot(x='species', data=iris, kind='count'): 使用 catplot() 函数,并设置 kind='count',效果与 countplot() 相同。
计数图的特点:
展示每个类别变量的频数。
适用于展示类别变量的分布情况。
计数图的优点:
简洁明了地展示类别变量的分布。
易于比较不同类别变量的频数。
计数图的缺点:
2.8 点图 (pointplot() 和 catplot(kind='point'))
点图 (pointplot()) 用于展示每个类别变量的平均值,并用线条连接不同类别的平均值点。点图类似于条形图,但它更侧重于展示不同类别之间的趋势和比较,而不是具体的数值大小。点图也通常会显示误差线。
代码示例:
# 使用 pointplot() sns.pointplot(x='species', y='sepal_length', data=iris) plt.title('Pointplot of Sepal Length by Species') plt.show() # 使用 catplot(kind='point') sns.catplot(x='species', y='sepal_length', data=iris, kind='point') plt.suptitle('Catplot (kind=point) of Sepal Length by Species', y=1.02) plt.show()
代码解释:
pointplot() 或 catplot(kind='point')。点图的特点:
展示每个类别变量的平均值。
用线条连接不同类别的平均值点,展示趋势。
误差线表示数据的置信区间或标准差。
点图的优点:
侧重于展示不同类别之间的趋势和比较。
线条连接可以更清晰地展示趋势变化。
点图的缺点:
不如条形图直观展示具体的数值大小。
对于类别较多的情况,点图可能显得线条复杂。
3. 分面 (Faceting) 与 catplot()
catplot() 函数最强大的功能之一是分面 (Faceting)。通过 col 和 row 参数,我们可以将数据按照额外的类别变量进行分组,并在不同的子图中绘制分类图。分面可以帮助我们更深入地探索多变量之间的关系。
代码示例:使用 col 参数进行列分面
sns.catplot(x='species', y='sepal_length', hue='petal_length', col='petal_width', data=iris, kind='violin', col_wrap=2) plt.suptitle('Violinplot of Sepal Length by Species, Faceted by Petal Width', y=1.02) plt.show()
代码解释:
col='petal_width': 指定使用 'petal_width' (花瓣宽度) 变量进行列分面。catplot() 会根据 'petal_width' 的不同取值,创建多个子图,每个子图对应一个 'petal_width' 的取值范围。
hue='petal_length': 在每个子图中,使用 'petal_length' (花瓣长度) 变量进行颜色编码,进一步展示多变量关系。
col_wrap=2: 指定每行最多显示 2 个子图,超出部分换行显示。
代码示例:使用 row 和 col 参数进行行列分面
sns.catplot(x='species', y='sepal_length', row='petal_length', col='petal_width', data=iris, kind='box', height=3, aspect=0.8) plt.suptitle('Boxplot of Sepal Length by Species, Faceted by Petal Length and Petal Width', y=1.02) plt.show()
代码解释:
row='petal_length', col='petal_width': 指定使用 'petal_length' 进行行分面,'petal_width' 进行列分面,创建行列子图矩阵。
height=3, aspect=0.8: 调整子图的高度和宽高比,使图表更紧凑。
分面的优点:
可以同时探索多个类别变量之间的关系。
将复杂的多变量关系分解成多个简单的子图,易于理解。
方便进行跨类别比较。
4. 分类图的定制与美化
Seaborn 分类图提供了丰富的参数来定制图表的外观,使其更美观、更易于理解。
常用的定制参数包括:
palette: 指定调色板,例如 'muted', 'viridis', 'Set1' 等。可以使用 Matplotlib 的颜色名称、RGB 值、Hex 值等。
hue_order, order: 指定类别变量的显示顺序。
linewidth, edgecolor: 设置箱线图、条形图等元素的线条宽度和边缘颜色。
color: 设置单色图的颜色。
marker, linestyle: 设置散点图和点图的标记形状和线条样式。
alpha: 设置透明度。
jitter: 在散点图和分簇散点图中添加抖动,避免点重叠。
dodge: 在分组条形图和点图中,控制不同 hue 组的元素是否并排显示。
orient: 强制指定图表的方向 (水平或垂直)。
ax: 将图表绘制到指定的 Matplotlib 轴对象上。
代码示例:定制箱线图的外观
sns.boxplot(x='species', y='sepal_length', data=iris, palette='Set2', # 使用 Set2 调色板 linewidth=1.5, # 设置线条宽度 edgecolor='0.2', # 设置边缘颜色 (灰色) flierprops={'marker': 'o', 'markersize': 5, 'markerfacecolor': '0.5'}) # 设置异常值样式 plt.title('Customized Boxplot of Sepal Length by Species') plt.show()
代码解释:
palette='Set2': 使用 'Set2' 调色板。
linewidth=1.5, edgecolor='0.2': 设置箱体和须的线条宽度和边缘颜色。
flierprops={'marker': 'o', 'markersize': 5, 'markerfacecolor': '0.5'}: 定制异常值的样式。flierprops 参数接受一个字典,用于设置异常值的属性,例如 marker (标记形状), markersize (标记大小), markerfacecolor (标记填充颜色) 等。
5. 总结与最佳实践
最佳实践建议:
根据数据类型和分析目的选择合适的分类图类型。 例如,要展示数据分布形状,可以选择小提琴图或分箱线图;要比较平均水平,可以选择条形图或点图;要展示每个数据点,可以选择散点图或分簇散点图。
充分利用 catplot() 函数的分面功能,探索多变量之间的关系。
合理定制图表外观,使其更美观、更易于理解。 例如,选择合适的调色板,调整线条宽度和颜色,设置标题和标签等。
结合其他 Seaborn 和 Matplotlib 功能,创建更复杂的图表。 例如,可以叠加多个图层,添加注释和图例,调整坐标轴范围等。
掌握 Seaborn 分类图,可以帮助我们更有效地进行数据探索和可视化分析,从类别型数据中挖掘有价值的信息。希望本章内容能够帮助读者更好地理解和应用 Seaborn 分类图,提升数据可视化技能。