使用Python Pandas掌握分类数据操作的示例

2025年3月4日 | 阅读 13 分钟

分类数据简介

Pandas 中称为分类数据(Categorical Data)或简称 Categoricals 的数据类型,等同于统计学中的分类变量。分类变量的值通常在一个有限的范围内,并且相对固定。尽管可以指定分类数据的顺序,但不能对其进行数值运算。与普通变量相比,分类数据类型占用的内存更少。例如,血型、性别、患病国家和观察时间等都属于分类变量。

什么是分类数据?

Pandas 模块可以简化处理大量行和列的数据集,也就是所谓的 DataFrame。通常,Pandas 模块用于处理 CSV (Excel) 文件。

Pandas Python 库提供了广泛的数据结构和操作,使得对数值数据和时间序列进行操作(添加、更新和删除)变得简单。Pandas 包易于数据导入和易于数据分析的特性是其广泛应用的主要原因。Pandas 模块的高效率和高性能使其非常有用且相对快速。

Pandas 中,被称为“分类数据”或“Categoricals”的数据类型,等同于统计学中的分类变量。例如,观察时间、血型、患病国家、性别等都属于分类变量。分类变量的一个重要特点是其值在一个有限的范围内,并且相对固定。尽管分类数据可以指定顺序,但我们无法对其进行数值运算。

分类数据方法和属性

以下是 Pandas 提供的一些用于在 Python 中处理分类数据操作的方法和属性:

Pandas Series.astype() 方法

Pandas 的 `Series.astype()` 函数是一个强大的工具,用于将 Pandas Series 的数据类型转换为指定类型。当处理分类数据时,此函数特别有用,因为它允许您将 Series 转换为 `category` 数据类型,这可以减少内存使用并提高性能。该函数还可以用于确保数据一致性,例如,将数字字符串转换为整数或浮点数。通过使用 `astype()`,您可以有效地管理和操作 Pandas Series 中的数据类型,以满足您的分析需求。

示例

输出

 
0    1
1    2
2    3
3    4
dtype: int64   

说明

示例中的第一步是创建一个名为 `data` 的 Pandas Series,其中包含整数的字符串表示形式('1'、'2'、'3' 和 '4')。尽管这些值是数值型的,但它们被存储为字符串,这使得在数学运算中使用它们变得困难。

我们使用 `{astype(int)}` 函数将字符串值转换为整数。通过这样做,`{data}` Series 中的每个字符串成员都被转换为整数。由于结果 Series `{data_int}` 现在包含整数值,因此可以对其进行任何基于数字的计算,包括加法和减法。

这个简单的转换演示了 `Series.astype()` 如何用于确保数据格式正确以便进行分析,从而提高工作效率和准确性。

Pandas cat 访问器

Pandas 的 `categoricals.cat` 访问器提供了用于管理 Series 中分类数据的特定特性和技术。对于分类数据,它支持一系列操作,包括重命名、重新排序、添加和删除类别,以及验证顺序等属性。通过利用 `{cat}`,您可以更有效地快速地处理分类数据,并改善内存管理。借助这个访问器,您可以轻松地修改和优化数据分析任务中的各种数据类型,这在处理占有重要地位的分类数据的庞大数据集时尤其有用。

示例

输出

 
0    L
1    M
2    H
3    M
4    L
dtype: category
Categories (3, object): ['L' < 'M' < 'H']   

说明

这是一个创建名为 `{data}` 的 Pandas Series 的示例,其中包含三个类别值:'low'、'medium' 和 'high'。当数据类型定义为 `{category}` 时,可以更轻松地管理分类数据并优化内存消耗。

首先,我们使用 `cat.reorder_categories()` 函数按“low”到“high”的顺序排列类别。这对于具有有意义序列的分类数据(如评级级别)尤其有用。

然后,我们使用 `cat.rename_categories()}` 方法重命名类别,将“low”更改为“L”,“medium”更改为“M”,将“high”更改为“H”。因此,我们可以根据需要简化或标准化类别名称。

最后,显示修改后的 Series,其中包含重新排序和重命名的类别。此示例说明了如何使用 `categoricals.cat` 访问器来有效地自定义和管理分类数据。

Pandas cat.codes 属性

Pandas 中的 `categoricals.cat.codes` 属性返回分类 Series 中类别对应的整数代码。每个类别被分配一个唯一的整数,这使得对分类数据执行数值运算或分析变得容易。它是将类别编码为数值形式的便捷工具。

示例

输出

 
0    0
1    1
2    2
3    1
4    0
dtype: int8   

说明

为了说明这一点,让我们创建一个名为 `data}` 的 Pandas Series,其中包含分类值“apple”、“banana”和“cherry~”。使用 `category}` 数据类型,这些值被保留为类别。

然后,使用 `cat.codes` 属性获取这些类别变量的对应整数代码。每个不同的类别都被赋予一个不同的整数:“apple”变为 0,“banana”变为 1,“cherry”变为 2。

生成的 `codes` Series 包含这些整数值,提供了分类数据的数值表示。当您需要执行数值运算或将数据输入需要数值输入的机器学习模型时,这种转换非常有用。

Pandas cat.remove_unused_categories 方法

Pandas 中的 `categoricals.cat.remove_unused_categories` 方法会从分类 Series 中删除未在数据中出现的任何类别。

示例

输出

 
0    apple
1   banana
2    apple
dtype: category
Categories (2, object): ['apple', 'banana']

Index(['apple', 'banana'], dtype='object')   

说明

在这里,我们创建一个 Pandas Series {data},其中包含分类值“apple”和“banana”,但我们将类别“cherry”也添加到类别列表中,尽管它没有被使用。“Cherry”被定义为类别;然而,它在实际数据中不存在。

我们使用 `cat.remove_unused_categories()` 方法来清理 Series 并删除这个不必要的类别。此过程会从类别列表中删除“cherry”,只留下“apple”和“banana”,它们是数据中实际存在的类别。Series 已被净化,其类别集合现在更精确、更有效,占用的内存比以前少。

Pandas get_dummies() 方法

`pandas.get_dummies()` 函数将分类数据转换为独热编码格式。它为每个类别创建一个新的二进制列,其中 1 表示该类别的存在,0 表示不存在。这种转换对于为机器学习模型准备分类变量至关重要。

示例

输出

 
   apple  banana  cherry
0      1       0       0
1      0       1       0
2      1       0       0
3      0       0       1   

说明

在此示例中,我们使用分类变量“apple”、“banana”、“apple”和“cherry”来创建一个 Pandas Series {data}。此分类数据使用 `pd.get_dummies()}` 为机器学习或其他数值研究做准备。此函数会将分类数据转换为独热编码格式。

最终 DataFrame {one_hot_encoded} 的每一列都代表一个不同的类别:“apple”、“banana”和“cherry”。二进制值(0 或 1)表示每个类别在 DataFrame 的每一行中是否存在。例如,对应“apple”的行在“apple”列中有一个 1,而在其他列中为 0。对于需要数值输入的算法,这种编码至关重要。

处理分类数据

分类数据的两个特征是顺序(ordered)和类别(categories)。可以通过将 dtype 设置为 category 来创建分类数据。使用 ordered 属性,我们还可以建立顺序。可以通过 s.cat.ordered 和 s.cat.categories 分别访问 ordered 和 categories 属性。

重命名类别

使用 `cat.rename_categories()` 方法,您可以重命名 Pandas 中的类别,以获得更标准化或与分类系列中已存在的类别相关的标签。

示例

输出

 
0    S
1    M
2    L
3    M
dtype: category
Categories (3, object): ['S', 'M', 'L']   

说明

在此示例中,我们使用 `cat.rename_categories()` 将 Pandas Series 中的类别从“small”、“medium”和“large”重命名为“S”、“M”和“L”。此方法有助于标准化或简化类别标签,使数据更简洁,更易于解释或用于分析。

添加新类别

在 Pandas 中添加新类别涉及使用 `cat.add_categories()` 方法向分类 Series 添加其他类别,从而允许在不更改现有数据的情况下扩展类别集。

示例

输出

 
0     apple
1    banana
dtype: category
Categories (3, object): ['apple', 'banana', 'cherry']   

说明

在此示例中,我们使用 `cat.add_categories()` 将新类别“cherry”添加到一个最初包含“apple”和“banana”的 Pandas Series 中。此方法扩展了类别列表,允许将来使用新类别的数据输入,而不会修改当前数据。

删除类别

在 Pandas 中删除类别涉及使用 `cat.remove_categories()` 方法从分类 Series 中删除指定的类别,通过消除不再需要的类别来简化类别集。

示例

输出

 
0     apple
1       NaN
2    cherry
dtype: category
Categories (2, object): ['apple', 'cherry']   

说明

在此示例中,我们使用 `cat.remove_categories(['banana'])` 从 Pandas Series 中删除了“banana”类别。此操作会更新 Series,将任何“banana”条目替换为 `NaN`,并调整类别列表,使其仅包含剩余的类别“apple”和“cherry”,从而简化了数据。

删除未使用的类别

Pandas 中删除未使用的类别是通过 `cat.remove_unused_categories()` 方法完成的。这会通过消除数据中不存在的类别来清理类别列表,从而优化内存使用。

示例

输出

 
0    apple
1   banana
dtype: category
Categories (2, object): ['apple', 'banana']

Index(['apple', 'banana'], dtype='object')   

说明

在此示例中,Series 数据最初包含“apple”、“banana”和“cherry”作为可能的类别。在使用 `cat.remove_unused_categories()` 后,“cherry”类别被删除,因为它不存在于实际数据中,只剩下“apple”和“banana”。

对分类数据进行排序和排序

现在我们来看看如何排列和排序分类数据。鉴于 order 属性可以设置为 True,该类别被认为是已排序的。我们可以在已排序的数据上执行数学运算;但是,在未排序的数据上,像 min() 和 max() 这样的数学运算会返回一个错误,即 TypeError。

重新排序

Categorical.set_categories() 和 Categorical.reorder_categories() 函数都允许我们重新排列类别。如果使用 Categorical.reorder_categories() 函数,则不允许添加新类别,并且必须将旧类别包含在新类别中。有关进一步说明,请参阅下面的示例。

示例

输出

 
Reordered categories:
 0      low
1    medium
2     high
3    medium
dtype: category
Categories (3, object): ['high' < 'medium' < 'low']   

说明

在此示例中,数据 Series 包含类别“low”、“medium”和“high”。使用 `cat.reorder_categories()`,我们将这些类别重新排序为“high”、“medium”和“low”,使“high”成为最高优先级,“low”成为最低优先级。

多列排序

Pandas 中的多列排序允许您使用 `sort_values()` 方法根据多个列对 DataFrame 进行排序。您可以指定要排序的列,并设置 `ascending` 参数来定义每列的排序顺序,从而实现复杂、分层的数据库排序。

示例

输出

 
Original DataFrame:
    X  Y
6  z  2
3  z  3
7  z  3
0  x  1
4  x  2
5  x  1
2  y  2
1  y  1

New DataFrame:
    X  Y
3  x  1
5  x  1
4  x  2
1  y  1
2  y  2
0  z  3
6  z  2
7  z  3   

说明

在此示例中,DataFrame df 在“X”列中包含分类数据,其类别为“z”、“x”和“y”,在“Y”列中包含数值数据。DataFrame 首先按“X”和“Y”列排序。在将“X”中的类别重新排序为“x”、“y”和“z”之后,DataFrame 会再次排序,演示了类别重新排序如何影响最终的排序 DataFrame。

Pandas 中的分类索引是什么?

如果我们的数据中有重复项,我们可以使用 CategoricalIndex 来索引这些值。当存在许多重复项时,CategoricalIndex 是一种充当分类数据容器的索引,有助于有效的数据存储和索引。有关进一步说明,请参阅下面的示例。

示例

输出

 
CategoricalIndex([10, 20, 30, 40], categories=[40, 20, 30, 10], ordered=False, dtype='category')
   labels  numbers
10      x       40
20      y       20
30      z       30
40      w       10   

说明

在此示例中,DataFrame 是使用分类索引创建的,其中索引由 `categories` 定义,值为 `[10, 20, 30, 40]`,类别顺序为 `[40, 20, 30, 10]`。“labels”和“numbers”列包含字符串标签和相应的数值。DataFrame 的索引是 `CategoricalIndex`,反映了定义的分类值。但是,DataFrame 中的行按原始数据输入的顺序出现,而不是按照类别顺序,因为 `ordered` 参数设置为 `False`。只有在明确用于排序或重新排序 DataFrame 时,分类顺序才变得相关。

分类类型的性能

与常规 DataFrame 相比,分类形式的数据运行速度更快,占用的内存空间也更少。因此,如果我们处理的是大数据或大量数据,将数据转换为分类数据可能是有利的。

示例

输出

 
Normal data memory usage: 400048
Categorical data memory usage: 50072   

说明

  • 常规数据内存使用:类别 Series,它将字符串标签存储为常规对象,消耗大约 400,048 字节的内存。
  • 分类数据内存使用: `categorical_data` Series,其中标签被转换为分类数据,将内存使用量显著减少到约 50,072 字节。

这说明了 Pandas 中使用分类数据类型的效率,尤其是在处理重复字符串值时,因为它们通过引用每个类别的单个实例来压缩数据,而不是多次存储整个字符串。

结论

通过各种示例对常规数据和分类数据之间的内存使用进行的比较,一致地证明了 Pandas 中分类数据类型的效率。常规数据类型(如字符串或整数)通常由于反复存储完整值而需要更多内存。相比之下,分类数据类型通过一次存储唯一值并使用整数代码引用它们来优化内存。这在大类别重复次数很多的大型数据集中尤其明显,分类数据可以显著减少内存消耗。总的来说,利用分类数据类型可以提高性能和可扩展性,使其成为高效处理大规模数据的宝贵选择。