8.4 Categorical 类型的使用 8.4 Pandas Categorical 类型:性能优化与内存节约的利器 在 Pandas 中, 类型是一种表示分类数据的有效方式。它不仅可以显著减少内存占用,还能在某些操作中提高性能。本节将深入探讨 类型的使用,包括创建、操作、性能优势以及适用场景。 8.4.1 什么是 Categorical 类型? 类型用于表示只包含有限且通常是固定数量的可能值的列。这些值被称为“类别”(categories)。与直接存储字符串或数值相比, 类型将数据表示为整数代码,并将原始值存储在一个单独的类别列表中。 例如,一个表示衬衫尺寸的列可能包含 "S"、"M"、"L"、"XL" 这几个值。
在 Pandas 中,Categorical 类型是一种表示分类数据的有效方式。它不仅可以显著减少内存占用,还能在某些操作中提高性能。本节将深入探讨 Categorical 类型的使用,包括创建、操作、性能优势以及适用场景。
Categorical 类型用于表示只包含有限且通常是固定数量的可能值的列。这些值被称为“类别”(categories)。与直接存储字符串或数值相比,Categorical 类型将数据表示为整数代码,并将原始值存储在一个单独的类别列表中。
例如,一个表示衬衫尺寸的列可能包含 "S"、"M"、"L"、"XL" 这几个值。使用 Categorical 类型,Pandas 会将这些字符串映射到整数(如 0, 1, 2, 3),并在内部存储这些整数代码。原始字符串值只存储一次,从而节省了内存。
有几种方法可以创建 Categorical 类型的数据:
1. 使用 astype('category'):
这是最简单的方法,可以将现有的 Series 或 DataFrame 列转换为 Categorical 类型。
import pandas as pd # 创建一个示例 Series sizes = pd.Series(['S', 'M', 'L', 'XL', 'S', 'M', 'L']) # 转换为 Categorical 类型 categorical_sizes = sizes.astype('category') print(categorical_sizes) print(categorical_sizes.dtype) #category
2. 使用 pd.Categorical() 构造函数:
这种方法允许更精细的控制,可以指定类别的顺序和是否允许未知类别。
# 创建一个 Categorical 对象,并指定类别顺序 categories = ['S', 'M', 'L', 'XL'] categorical_sizes = pd.Categorical(sizes, categories=categories, ordered=True) #ordered=True 表示有序分类 print(categorical_sizes) print(categorical_sizes.dtype) #category
3. 在 DataFrame 中创建 Categorical 列:
df = pd.DataFrame({'size': ['S', 'M', 'L', 'XL', 'S', 'M', 'L']}) df['size'] = df['size'].astype('category') print(df) print(df['size'].dtype) #category
Categorical 对象有几个有用的属性:
.categories: 返回类别的列表。
.ordered: 指示类别是否具有定义的顺序(布尔值)。
.codes: 返回表示每个值的整数代码的 NumPy 数组。
print(categorical_sizes.categories) print(categorical_sizes.ordered) print(categorical_sizes.codes)
Categorical 类型支持许多与普通 Series 相同的操作,包括:
比较操作: 可以比较 Categorical 值,如果类别是有序的,则可以进行大小比较。
分组和聚合: 可以对 Categorical 列进行分组,并计算聚合统计信息。
绘图: Categorical 列可以用于创建各种图表。
替换操作: 可以替换 Categorical 中的类别,或者替换指定位置的值。
# 比较操作 print(categorical_sizes > 'M') # 分组和聚合 df = pd.DataFrame({'size': categorical_sizes, 'value': [1, 2, 3, 4, 5, 6, 7]}) print(df.groupby('size')['value'].sum()) # 替换类别 new_categories = ['Small', 'Medium', 'Large', 'Extra Large'] categorical_sizes = categorical_sizes.rename_categories(new_categories) print(categorical_sizes)
Categorical 类型的主要优势在于其性能。它通过以下方式提高性能:
减少内存占用: Categorical 类型将数据存储为整数代码,而不是原始字符串或数值,从而显著减少内存占用,尤其是在处理包含大量重复值的列时。
加速计算: 许多 Pandas 操作(如分组和排序)在 Categorical 数据上执行得更快,因为它们可以对整数代码进行操作,而不是对原始值进行操作。
为了演示内存节约,可以比较 Categorical 类型和普通 Series 的内存使用情况:
import numpy as np # 创建一个包含大量重复值的 Series n = 1000000 data = ['A', 'B', 'C', 'A', 'B', 'C'] * (n // 6) series = pd.Series(data) # 转换为 Categorical 类型 categorical_series = series.astype('category') # 比较内存使用情况 print(f"Series 内存使用量: {series.memory_usage(deep=True) / 1024**2:.2f} MB") print(f"Categorical Series 内存使用量: {categorical_series.memory_usage(deep=True) / 1024**2:.2f} MB")
在上面的例子中,Categorical 类型通常会比普通 Series 节省大量的内存。
Categorical 类型适用于以下场景:
具有有限数量的可能值的列: 例如,表示性别、国家、产品类别等的列。
需要节省内存的大型数据集: 如果数据集包含大量重复的字符串或数值,则使用 Categorical 类型可以显著减少内存占用。
需要加速计算的列: 如果需要对分类数据进行频繁的分组、排序或聚合,则使用 Categorical 类型可以提高性能。
有序分类数据: 当分类数据具有内在的顺序时,例如评级(好,中,差),使用 ordered=True 可以进行有意义的比较和排序。
类别必须是不可变的: Categorical 类型的类别必须是不可变的,例如字符串或数值。
谨慎使用 ordered=True: 只有当类别确实具有明确的顺序时,才应使用 ordered=True。否则,可能会导致意外的结果。
内存开销: 虽然 Categorical 通常能节省内存,但如果类别数量接近或等于数据点的数量,使用 Categorical 可能会适得其反,因为存储类别本身也会占用内存。
下面是一个使用 Mermaid 绘制的流程图,展示了 Categorical 类型的创建和使用过程:
Categorical 类型是 Pandas 中一个强大的工具,可以有效地表示分类数据,减少内存占用,并提高某些操作的性能。通过理解其创建、属性、操作和适用场景,可以更好地利用 Categorical 类型来优化 Pandas 数据处理流程。在处理大型数据集和需要频繁操作分类数据时,Categorical 类型是一个非常有价值的选择。