Python Pandas - 分类数据
Pandas - 分类数据
Section titled “Pandas - 分类数据”现实世界的数据集通常包含具有重复文本值的列,这些值代表不同的组或类别(categories),例如 ‘Gender’(男性/女性)、‘Country’(美国/加拿大/墨西哥)或 ‘Status’(待处理/已完成/失败)。Pandas 提供了一个专门的 Categorical 数据类型(dtype)来高效处理这类数据。
分类变量(Categorical variables)只能取有限的、固定的可能值集合,称为 ‘categories’(类别)。它们可能具有有意义的顺序(例如 ‘Low’ < ‘Medium’ < ‘High’),但标准的数值运算(如加法)不适用。使用 Categorical dtype 提供了几个优点:
- 内存效率(Memory Efficiency): 如果一个字符串列有很多重复的少数几个独特值,将其转换为
Categorical可以显著减少内存使用。Pandas 只存储一次独特的类别,并使用整数代码(integer codes)表示值。 - 逻辑顺序(Logical Ordering): 你可以为类别定义自定义的逻辑顺序(例如 [‘Small’, ‘Medium’, ‘Large’])。排序或查找最小值/最大值将使用此逻辑顺序,而不是默认的字母(lexical)顺序。
- 向其他库传递信号(Signal to Other Libraries): 它清楚地向其他 Python 库(如可视化或统计建模库)表明某一列应被视为分类列,从而启用适当的图表类型或统计方法。
创建分类数据
Section titled “创建分类数据”分类数据可以通过几种方式创建:
使用 dtype='category'
Section titled “使用 dtype='category'”在创建 Series 或 DataFrame 时指定 dtype="category":
import pandas as pd
# 创建一个带有分类数据的 Seriess = pd.Series(["a", "b", "c", "a"], dtype="category")print(s)输出:
0 a1 b2 c3 adtype: categoryCategories (3, object): ['a', 'b', 'c']注意,尽管 Series 有四个元素,Pandas 仅识别出三个独特的类别:‘a’、‘b’ 和 ‘c’。
使用 pd.Categorical()
Section titled “使用 pd.Categorical()”你可以使用 pd.Categorical 构造函数显式地创建一个 Categorical 对象:
pd.Categorical(values, categories=None, ordered=False)示例 1:基本创建
import pandas as pd
cat_obj = pd.Categorical(['a', 'b', 'c', 'a', 'b', 'c'])print(cat_obj)输出:
['a', 'b', 'c', 'a', 'b', 'c']Categories (3, object): ['a', 'b', 'c']示例 2:指定类别
import pandas as pd
values = ['a', 'b', 'c', 'a', 'b', 'c', 'd'] # 'd' 不在指定的类别中defined_categories = ['c', 'b', 'a']cat_obj = pd.Categorical(values, categories=defined_categories)print(cat_obj)输出:
['a', 'b', 'c', 'a', 'b', 'c', NaN]Categories (3, object): ['c', 'b', 'a']这里,categories 参数显式定义了允许的类别。values 中未出现在 defined_categories 中的任何值(例如 ‘d’)都会变成 NaN(Not a Number)。
示例 3:指定顺序
import pandas as pd
values = ['a', 'b', 'c', 'a', 'b', 'c', 'd']defined_categories = ['c', 'b', 'a']# 创建一个有序分类cat_obj = pd.Categorical(values, categories=defined_categories, ordered=True)print(cat_obj)输出:
['a', 'b', 'c', 'a', 'b', 'c', NaN]Categories (3, object): ['c' < 'b' < 'a']设置 ordered=True 会根据 categories 中提供的顺序建立逻辑顺序。在这种情况下,‘c’ 被认为小于 ‘b’,‘b’ 被认为小于 ‘a’。
使用 astype('category')
Section titled “使用 astype('category')”你可以使用 .astype() 方法将现有的 Series 或列转换为分类类型。这是一种非常常用的方法。
import pandas as pd
s = pd.Series(["a", "b", "c", "a"])print("原始 Series:")print(s)
s_cat = s.astype('category')print("\n分类 Series:")print(s_cat)输出:
Original Series:0 a1 b2 c3 adtype: object
Categorical Series:0 a1 b2 c3 adtype: categoryCategories (3, object): ['a', 'b', 'c']处理分类数据
Section titled “处理分类数据”描述分类数据
Section titled “描述分类数据”.describe() 方法提供分类数据的摘要,包括计数 (count)、独特类别数 (unique)、最频繁的类别 (top) 及其频率 (freq)。
import pandas as pdimport numpy as np
cat = pd.Categorical(["a", "c", "c", np.nan], categories=["b", "a", "c"])df = pd.DataFrame({"cat_column": cat, "str_column": ["a", "c", "c", np.nan]})
print("描述 DataFrame (包含分类摘要):")print(df.describe(include=['category']))
print("\n直接描述分类列:")print(df["cat_column"].describe())输出:
Describe DataFrame (includes categorical summary): cat_columncount 3unique 2top cfreq 2
Describe the categorical column directly:count 3unique 2top cfreq 2Name: cat_column, dtype: object访问分类属性
Section titled “访问分类属性”使用 .cat 访问器来处理分类属性:
import pandas as pdimport numpy as np
s = pd.Series(["a", "c", "c", np.nan], dtype=pd.CategoricalDtype(categories=["b", "a", "c"], ordered=True))
# 获取类别print("Categories:", s.cat.categories)
# 检查是否有序print("Is ordered:", s.cat.ordered)输出:
Categories: Index(['b', 'a', 'c'], dtype='object')Is ordered: True使用 s.cat.rename_categories() 方法:
import pandas as pd
s = pd.Series(["a", "b", "c", "a"], dtype="category")print("原始类别:", s.cat.categories)
# 使用字典或函数重命名类别s_renamed = s.cat.rename_categories({"a": "Alpha", "b": "Beta", "c": "Gamma"})# 或者使用函数:s_renamed = s.cat.rename_categories(lambda c: f"Group {c.upper()}")
print("重命名后的类别:", s_renamed.cat.categories)print("\n重命名类别后的 Series:")print(s_renamed)输出:
Original categories: Index(['a', 'b', 'c'], dtype='object')Renamed categories: Index(['Alpha', 'Beta', 'Gamma'], dtype='object')
Series with renamed categories:0 Alpha1 Beta2 Gamma3 Alphadtype: categoryCategories (3, object): ['Alpha', 'Beta', 'Gamma']使用 s.cat.add_categories() 方法:
import pandas as pd
s = pd.Series(["a", "b", "c", "a"], dtype="category")print("原始类别:", s.cat.categories)
s_new_cats = s.cat.add_categories(["d", "e"])print("\n添加后的类别:", s_new_cats.cat.categories)输出:
Original categories: Index(['a', 'b', 'c'], dtype='object')
Categories after adding: Index(['a', 'b', 'c', 'd', 'e'], dtype='object')使用 s.cat.remove_categories() 方法。注意,任何属于被移除类别的现有数据点将变为 NaN。
import pandas as pd
s = pd.Series(["a", "b", "c", "a"], dtype="category")print("原始对象:")print(s)
# 移除类别 'a's_removed = s.cat.remove_categories(["a"])print("\n移除后:")print(s_removed)print("\n剩余类别:", s_removed.cat.categories)输出:
Original object:0 a1 b2 c3 adtype: categoryCategories (3, object): ['a', 'b', 'c']
After removal:0 NaN1 b2 c3 NaNdtype: categoryCategories (2, object): ['b', 'c']
Remaining categories: Index(['b', 'c'], dtype='object')移除未使用的类别
Section titled “移除未使用的类别”如果你过滤数据或移除类别,某些类别可能不再存在于数据中。使用 s.cat.remove_unused_categories() 从 .categories 属性中移除它们。
import pandas as pd
s = pd.Series(pd.Categorical(["a", "b", "a"], categories=['a', 'b', 'c']))print("原始 Series:")print(s)print("原始类别:", s.cat.categories)
# 移除未使用的类别 ('c')s_useful = s.cat.remove_unused_categories()print("\n移除未使用的类别后的 Series:")print(s_useful)print("更新后的类别:", s_useful.cat.categories)输出:
Original Series:0 a1 b2 adtype: categoryCategories (3, object): ['a', 'b', 'c']Original Categories: Index(['a', 'b', 'c'], dtype='object')
Series after removing unused:0 a1 b2 adtype: categoryCategories (2, object): ['a', 'b']Updated Categories: Index(['a', 'b'], dtype='object')分类数据的比较
Section titled “分类数据的比较”比较在特定条件下有效:
- 相等性 (==, !=): 可以将分类 Series 与长度相同的类似列表对象(list, Series, array)或标量值进行比较。
- 有序比较 (>, >=, <, <=): 仅当
ordered=True时才可能进行比较。你可以比较: -
- 一个有序的分类 Series 与另一个有序的分类 Series 进行比较,如果它们具有完全相同的类别和顺序。
-
- 一个有序的分类 Series 与一个属于其类别的标量值进行比较。
示例:比较有序分类
import pandas as pd
# 定义有序类别cat_dtype = pd.CategoricalDtype(categories=['low', 'medium', 'high'], ordered=True)
cat1 = pd.Series(['low', 'medium', 'high'], dtype=cat_dtype)cat2 = pd.Series(['medium', 'medium', 'medium'], dtype=cat_dtype)
print("cat1 > cat2:")print(cat1 > cat2)
print("\ncat1 == 'medium':")print(cat1 == 'medium')输出:
cat1 > cat2:0 False1 False2 Truedtype: bool
cat1 == 'medium':0 False1 True2 Falsedtype: bool