杰瑞科技汇

Python category 排序如何实现?

在 Python 中,对 category 类型的数据进行排序通常涉及两种情况:

Python category 排序如何实现?-图1
(图片来源网络,侵删)
  1. 按类别名称的字母顺序排序:这是最常见的需求,例如按 "A", "B", "C" 的顺序。
  2. 按自定义的业务逻辑顺序排序:例如按 "Low", "Medium", "High" 或 "Small", "Medium", "Large" 的特定顺序。

这两种情况的实现方法有所不同,下面我将详细解释,并提供使用 Pandas 和 Python 原生 enum 的示例。


按类别名称的字母顺序排序

这是 Pandas Categorical 类型的默认行为,当你创建一个 Categorical 对象时,如果未指定 categories 的顺序,它会自动按类别值的唯一值进行字典序(lexicographical order)排序。

使用 Pandas

import pandas as pd
import numpy as np
# 1. 创建数据
data = np.random.choice(['C', 'A', 'B', 'D'], size=10)
print("原始数据:")
print(data)
# 2. 创建 Categorical 对象 (默认按字母顺序排序)
# categories 会自动排序为 ['A', 'B', 'C', 'D']
cat_data = pd.Categorical(data, ordered=True)
print("\n默认创建的 Categorical (已排序):")
print(cat_data)
print("Categories:", cat_data.categories)
# 3. 如果你的数据已经是 Series,可以直接使用 .astype()
s = pd.Series(data)
cat_s = s.astype('category')
print("\n从 Series 转换的 Categorical (已排序):")
print(cat_s)
print("Categories:", cat_s.cat.categories)

输出:

原始数据:
['B' 'C' 'A' 'D' 'C' 'A' 'B' 'A' 'D' 'B']
默认创建的 Categorical (已排序):
['B', 'C', 'A', 'D', 'C', 'A', 'B', 'A', 'D', 'B']
Categories (4, object): ['A', 'B', 'C', 'D']
从 Series 转换的 Categorical (已排序):
0     B
1     C
2     A
3     D
4     C
5     A
6     B
7     A
8     D
9     B
dtype: category
Categories (4, object): ['A', 'B', 'C', 'D']

如何排序一个包含 Categorical 数据的 DataFrame?

Python category 排序如何实现?-图2
(图片来源网络,侵删)

当你对包含 Categorical 列的 DataFrame 进行排序时,Pandas 会智能地按照该列的 categories 顺序进行排序,而不是简单的字母顺序。

import pandas as pd
df = pd.DataFrame({
    'product': ['Apple', 'Banana', 'Cherry', 'Date', 'Apple'],
    'size': pd.Categorical(['M', 'S', 'L', 'M', 'S'], categories=['S', 'M', 'L'], ordered=True)
})
print("原始 DataFrame:")
print(df)
print("\n'size' 列的 categories:", df['size'].cat.categories)
# 按 'size' 列排序
# 排序顺序将是 S -> M -> L
df_sorted = df.sort_values('size')
print("\n按 'size' 列排序后的 DataFrame:")
print(df_sorted)

输出:

原始 DataFrame:
   product size
0   Apple    M
1  Banana    S
2  Cherry    L
3    Date    M
4   Apple    S
'size' 列的 categories: Index(['S', 'M', 'L'], dtype='object')
按 'size' 列排序后的 DataFrame:
   product size
1  Banana    S
4   Apple    S
0   Apple    M
3    Date    M
2  Cherry    L

按自定义的业务逻辑顺序排序

在很多实际应用中,我们需要自定义类别顺序,"Low, Medium, High" 或 "Small, Medium, Large",这时,我们必须在创建 Categorical 对象时显式地指定 categories 参数。

使用 Pandas

这是实现自定义排序的关键。

import pandas as pd
import numpy as np
# 1. 创建数据
data = np.random.choice(['High', 'Low', 'Medium'], size=10)
print("原始数据:")
print(data)
# 2. 创建 Categorical 对象,并指定自定义的 categories 顺序
# ordered=True 表示这是一个有序的分类,可以进行 <, >, <=, >= 等比较
custom_order = ['Low', 'Medium', 'High']
cat_data = pd.Categorical(data, categories=custom_order, ordered=True)
print("\n指定了自定义顺序的 Categorical:")
print(cat_data)
print("Categories:", cat_data.categories)
# 3. 在 DataFrame 中使用并排序
df = pd.DataFrame({
    'task_id': range(10),
    'priority': cat_data
})
print("\n原始 DataFrame:")
print(df)
# 按 'priority' 列排序
# 排序顺序将是 Low -> Medium -> High
df_sorted = df.sort_values('priority')
print("\n按自定义 'priority' 顺序排序后的 DataFrame:")
print(df_sorted)

输出:

原始数据:
['High' 'Low' 'Medium' 'High' 'Medium' 'Low' 'High' 'Medium' 'Low' 'Medium']
指定了自定义顺序的 Categorical:
['High', 'Low', 'Medium', 'High', 'Medium', 'Low', 'High', 'Medium', 'Low', 'Medium']
Categories (3, object): ['Low' < 'Medium' < 'High']
原始 DataFrame:
   task_id priority
0        0     High
1        1      Low
2        2  Medium
3        3     High
4        4  Medium
5        5      Low
6        6     High
7        7  Medium
8        8      Low
9        9  Medium
按自定义 'priority' 顺序排序后的 DataFrame:
   task_id priority
1        1      Low
5        5      Low
8        8      Low
2        2  Medium
4        4  Medium
7        7  Medium
9        9  Medium
0        0     High
3        3     High
6        6     High

高级技巧:使用 pd.CategoricalDtype

为了使代码更清晰、更具可重用性,推荐使用 pd.CategoricalDtype 来定义分类类型。

import pandas as pd
# 1. 定义分类类型
# 这样做的好处是可以重用这个类型定义
size_dtype = pd.CategoricalDtype(categories=['XS', 'S', 'M', 'L', 'XL'], ordered=True)
# 2. 创建数据
data = {'product': ['T-Shirt', 'Jeans', 'Socks', 'Jacket'],
        'size': ['M', 'L', 'S', 'XL']}
df = pd.DataFrame(data)
# 3. 使用 .astype() 应用分类类型
df['size'] = df['size'].astype(size_dtype)
print("DataFrame with CategoricalDtype:")
print(df)
print("\n'size' 列的 dtype:", df['size'].dtype)
# 4. 排序
df_sorted = df.sort_values('size')
print("\n按 'size' 排序后的 DataFrame:")
print(df_sorted)

输出:

DataFrame with CategoricalDtype:
   product size
0  T-Shirt    M
1    Jeans    L
2    Socks    S
3   Jacket   XL
'size' 列的 dtype: category
Categories (5, object): ['XS' < 'S' < 'M' < 'L' < 'XL']
按 'size' 排序后的 DataFrame:
   product size
2    Socks    S
0  T-Shirt    M
1    Jeans    L
3   Jacket   XL

使用 Python enum 进行排序

如果你的类别是固定的、有限的集合,并且希望它们在代码层面就有明确的顺序,使用 Python 的 Enum 是一个非常好的选择。Enum 成员本身就有定义顺序。

from enum import Enum
import pandas as pd
# 1. 定义一个枚举类,成员的顺序就是它们的排序顺序
class Priority(Enum):
    LOW = 1
    MEDIUM = 2
    HIGH = 3
# 2. 创建数据
data = {'task': ['Task A', 'Task B', 'Task C', 'Task D'],
        'priority': [Priority.HIGH, Priority.LOW, Priority.MEDIUM, Priority.HIGH]}
df = pd.DataFrame(data)
print("DataFrame with Enum:")
print(df)
print("\n'priority' 列的类型:", df['priority'].dtype)
# 3. 排序
# Pandas 可以直接按 Enum 的值进行排序
df_sorted = df.sort_values('priority', key=lambda x: x.map(lambda e: e.value))
print("\n按 'priority' 的 Enum 值排序后的 DataFrame:")
print(df_sorted)

输出:

DataFrame with Enum:
      task priority
0  Task A   HIGH
1  Task B    LOW
2  Task C MEDIUM
3  Task D   HIGH
'priority' 列的类型: object
按 'priority' 的 Enum 值排序后的 DataFrame:
      task priority
1  Task B    LOW
2  Task C MEDIUM
0  Task A   HIGH
3  Task D   HIGH

这里我们使用了 sort_valueskey 参数,它允许我们提供一个函数来在排序之前转换值。lambda x: x.map(lambda e: e.value) 的意思是:对于 'priority' 列中的每一个元素 e,获取其 .value (即 1, 2, 或 3),然后根据这些值进行排序。

需求 推荐方法 示例代码
按字母顺序排序 使用 Pandas Categorical,不指定 categories,让其自动排序。 pd.Categorical(data)s.astype('category')
按自定义顺序排序 使用 Pandas Categorical,并在创建时显式指定 categories 参数。 pd.Categorical(data, categories=['Low', 'High', 'Medium'])
代码清晰、可重用 使用 pd.CategoricalDtype 定义类型,然后通过 .astype() 应用。 dtype = pd.CategoricalDtype(...), df['col'] = df['col'].astype(dtype)
类别固定且代表状态 使用 Python Enum,利用其成员的天然顺序。 class Priority(Enum): ..., df.sort_values('col', key=lambda x: x.map(lambda e: e.value))

选择哪种方法取决于你的具体需求和代码风格,对于数据分析,Pandas 的 Categorical 类型是处理此类问题的标准且最强大的工具。

分享:
扫描分享到社交APP
上一篇
下一篇