在数据分析和数据清洗的日常工作中,我们经常需要处理包含大量重复信息的数据集。为了真正理解数据的构成,最基本的一步就是识别数据中的不同元素。无论你是要分析分类数据的分布,还是要检测潜在的数据录入错误,从 Pandas DataFrame 的列中提取唯一值都是一项必不可少的技能。
例如,想象一下你正在处理一份包含用户反馈的调查数据。如果“满意度”列中包含了 INLINECODEd2519f3c,作为分析师,你首先想知道的并不是具体有多少人投票,而是有哪些不同的评价维度。这时,提取唯一值(即 INLINECODEafbc9dd7)就是你的第一步操作。
在这篇文章中,我们将深入探讨在 Pandas 中从列获取唯一值的多种方法。我们将逐一分析 INLINECODE802ffb72、INLINECODEfa27c461、INLINECODE6b31717e 以及 INLINECODE35ff6804 等核心函数,并通过实际案例帮助你理解它们的具体应用场景和性能差异。无论你是刚入门的数据科学新手,还是希望优化代码效率的资深开发者,这篇文章都能为你提供实用的见解。
目录
准备工作:构建示例数据
在开始之前,让我们先构建一个示例 DataFrame,以便我们可以在同一组数据上对比不同方法的效果。为了模拟真实场景,我们将创建一个包含重复项、部分唯一值和完全重复列的数据集。
import pandas as pd
# 定义数据字典,故意在 B、C、D、E 列中包含重复数据
data = {
‘A‘: [‘A1‘, ‘A2‘, ‘A3‘, ‘A4‘, ‘A5‘], # 全部唯一
‘B‘: [‘B1‘, ‘B2‘, ‘B3‘, ‘B4‘, ‘B4‘], # B4 重复
‘C‘: [‘C1‘, ‘C2‘, ‘C3‘, ‘C3‘, ‘C3‘], # C3 多次重复
‘D‘: [‘D1‘, ‘D2‘, ‘D2‘, ‘D2‘, ‘D2‘], # 只有 D1 和 D2
‘E‘: [‘E1‘, ‘E1‘, ‘E1‘, ‘E1‘, ‘E1‘] # 完全相同
}
# 创建 DataFrame
df = pd.DataFrame(data)
# 打印原始数据
print("原始 DataFrame:")
print(df)
输出结果:
原始 DataFrame:
A B C D E
0 A1 B1 C1 D1 E1
1 A2 B2 C2 D2 E1
2 A3 B3 C3 D2 E1
3 A4 B4 C3 D2 E1
4 A5 B4 C3 D2 E1
有了这份数据,我们就可以清晰地看到每种方法是如何处理这些不同模式的。
方法一:使用 unique() 获取唯一值数组
unique() 是 Pandas 中获取唯一值最直接的方法。当你想要知道某一列中究竟有哪些不同的值时,这是首选函数。
工作原理
unique() 方法会返回一个 NumPy 数组,其中包含了输入序列中去重后的元素。非常重要的一点是:它会保留这些值在原始数据中首次出现的顺序。这意味着如果你的数据是有序的(例如按时间排序),返回的唯一值也将保持这种逻辑顺序。
代码示例
让我们从 ‘B‘ 列中提取唯一值。根据我们上面的数据,‘B‘ 列包含 INLINECODEf2f95ee1,我们期待的结果是 INLINECODE7a739a5e。
# 从 ‘B‘ 列获取唯一值
unique_values_B = df[‘B‘].unique()
print("‘B‘ 列中的唯一值:")
print(unique_values_B)
# 验证数据类型
print("
返回的数据类型:", type(unique_values_B))
输出结果:
‘B‘ 列中的唯一值:
[‘B1‘ ‘B2‘ ‘B3‘ ‘B4‘]
返回的数据类型:
实用见解与注意事项
- 返回类型:注意它返回的是 NumPy 数组 (INLINECODE53af640d),而不是 Pandas Series。如果你需要将其转换回列表,可以简单地使用 INLINECODE78d9cd36 方法,例如
df[‘B‘].unique().tolist()。
- 排序问题:如前所述,INLINECODE60bd4c12 不对结果进行排序。它只负责去重并保留出现顺序。如果你需要按字母顺序排列唯一值,你需要结合 NumPy 的排序功能:INLINECODE95fb1bd3。
- 适用场景:这种方法最适合你需要枚举所有可能的类别(例如绘制图例时的标签)或者进行数据验证时。
方法二:使用 nunique() 统计唯一值数量
有时候,我们并不关心具体的值是什么,只关心有多少种不同的值。例如,在一个电商网站的用户表中,我们可能只想知道“有多少个不同的国家”,而不需要列出所有国家的名字。这时,nunique() 就派上用场了。
工作原理
INLINECODEec1dc04d 返回的是唯一值的计数(整数)。它会自动忽略 INLINECODEd9814396(空值),这在处理包含缺失数据的脏数据时非常有用。
代码示例
让我们统计一下每一列中到底有多少个不同的元素。
# 统计各列的唯一值数量
print("‘A‘ 列唯一值数量:", df[‘A‘].nunique()) # 预期: 5
print("‘B‘ 列唯一值数量:", df[‘B‘].nunique()) # 预期: 4 (B4重复)
print("‘C‘ 列唯一值数量:", df[‘C‘].nunique()) # 预期: 3
print("‘D‘ 列唯一值数量:", df[‘D‘].nunique()) # 预期: 2
print("‘E‘ 列唯一值数量:", df[‘E‘].nunique()) # 预期: 1 (全部相同)
输出结果:
‘A‘ 列唯一值数量: 5
‘B‘ 列唯一值数量: 4
‘C‘ 列唯一值数量: 3
‘D‘ 列唯一值数量: 2
‘E‘ 列唯一值数量: 1
实用见解与最佳实践
- 快速概览:你可以直接在整个 DataFrame 上调用
df.nunique(),这将返回一个 Series,显示每一列的基数。这对于初步数据探索(EDA)非常有帮助,可以快速识别哪些列是分类变量(唯一值少),哪些是连续变量或 ID(唯一值多)。
- 处理缺失值:默认情况下,INLINECODE0a264ae6 排除 INLINECODE5fe7a17f。如果你的业务逻辑认为“空值”也是一种独特的状态,你需要传递参数 INLINECODE38bd4d82。例如:INLINECODEe8ca116f。
方法三:使用 drop_duplicates() 获取唯一值 Series
drop_duplicates() 主要是用于 DataFrame 清洗的方法,但当我们将其应用于单列时,它也能有效地返回唯一值。
工作原理
与 INLINECODEa3c3b0a3 返回 NumPy 数组不同,INLINECODE4cf7209a 返回的是一个 Pandas Series。这意味着结果会保留原始的索引标签(Index),除非你重置了它。
代码示例
让我们看看 ‘C‘ 列的处理结果。
# 使用 drop_duplicates 获取唯一值
unique_C_series = df[‘C‘].drop_duplicates()
print("‘C‘ 列的唯一值 (保留索引):")
print(unique_C_series)
输出结果:
‘C‘ 列的唯一值 (保留索引):
0 C1
1 C2
2 C3
Name: C, dtype: object
何时选择它而不是 unique()?
- 保留索引:如果你需要知道这些唯一值最初出现在哪一行(例如,你需要提取每个唯一值对应的“首次出现时间”或其他列的信息),
drop_duplicates()会保留第一行的索引,这对后续的数据合并非常有用。 - 链式操作:因为它返回 Series,所以非常适合在方法链中使用。例如,如果你想在去重后直接计算均值或进行其他 Pandas 操作,而不需要中途转换回 DataFrame。
方法四:使用 value_counts() 分析分布
这是我在探索性数据分析中最常用的方法。它不仅告诉你有哪些唯一的值,还告诉你每个值出现了多少次。
工作原理
value_counts() 返回一个新的 Series,其中索引是唯一的值,值是对应的计数。默认情况下,结果会按计数降序排列,即最常见的值排在最前面。
代码示例
让我们分析 ‘D‘ 列的数据分布。同时,我们也可以从结果对象中提取出唯一值列表。
# 计算值频率
counts_D = df[‘D‘].value_counts()
# 提取唯一值(即索引)
unique_D_values = counts_D.index.tolist()
print("‘D‘ 列的值计数分布:")
print(counts_D)
print("
提取出的唯一值列表:", unique_D_values)
输出结果:
‘D‘ 列的值计数分布:
D2 4
D1 1
Name: count, dtype: int64
提取出的唯一值列表: [‘D2‘, ‘D1‘]
实用见解
- 异常检测:通过
value_counts(),你可以一眼看出数据是否不平衡。例如,在分类问题中,如果某个类别的数量远超其他类别,你就需要警惕模型可能出现的偏差。 - 提取唯一值:注意,这里提取出的唯一值顺序是基于频率的(最常见的前面),而不是基于出现的先后顺序。这与
unique()的行为不同。
方法五:使用 set() (Python 原生方法)
除了 Pandas 的内置方法,我们还可以利用 Python 原生的 set(集合)数据结构。集合在数学上定义就是无序且不重复元素的集合。
代码示例
# 将列转换为集合
unique_set_D = set(df[‘D‘])
print("使用 set() 获取的唯一值:")
print(unique_set_D)
输出结果:
使用 set() 获取的唯一值:
{‘D2‘, ‘D1‘}
性能和局限性
- 性能:对于小型到中型数据集,INLINECODE38bf36c2 的速度非常快。但是,对于非常大的 Pandas Series,INLINECODEf4382fc9 的初始化过程可能比 Pandas 优化过的 C 语言底层实现的
unique()稍慢。 - 无序性:注意,集合是无序的。你不能保证 INLINECODEfe41dd4b 中的 INLINECODE11f44817 一定在
D1前面,每次运行结果可能不同。如果你的业务逻辑依赖顺序,请不要使用这种方法。 - 数据类型限制:INLINECODE7509d1b4 要求数据必须是“可哈希”的。虽然数值和字符串没问题,但如果你的列中包含列表或字典(这在某些 JSON 数据中很常见),INLINECODEcf8ab584 会报错,而 Pandas 的
unique()方法通常能处理更复杂的情况(如对象类型)。
常见错误与解决方案
在实践中,你可能会遇到一些棘手的情况。让我们来看看两个常见的问题及其解决方法。
1. 包含空格的唯一值
有时候,数据看起来是唯一的,但实际上包含不可见的空格。
# 模拟包含空格的数据
df_dirty = pd.DataFrame({‘Status‘: [‘Open‘, ‘Closed‘, ‘Open ‘, ‘Open‘]})
# ‘Open ‘ 和 ‘Open‘ 会被视为不同的值
print("原始计数:", df_dirty[‘Status‘].nunique()) # 可能是 3 而不是 2
# 解决方法:先去除空格
df_dirty[‘Status_Cleaned‘] = df_dirty[‘Status‘].str.strip()
print("清洗后计数:", df_dirty[‘Status_Cleaned‘].nunique()) # 现在是 2
2. 大小写敏感问题
对于文本数据,‘Apple‘ 和 ‘apple‘ 通常被视为不同的值。
# 模拟大小写不一致
df_case = pd.DataFrame({‘Fruit‘: [‘Apple‘, ‘Banana‘, ‘apple‘, ‘Banana‘]})
# 解决方法:统一转换为小写后再计算唯一值
unique_normalized = df_case[‘Fruit‘].str.lower().unique()
print("规范化后的唯一值:", unique_normalized)
# 输出: [‘apple‘, ‘banana‘]
总结与最佳实践
我们探索了五种从 Pandas DataFrame 列中获取唯一值的不同方法。让我们回顾一下何时使用哪一种:
-
unique():默认首选。当你需要具体的唯一值列表,并且希望保留它们在数据中首次出现的顺序时使用。返回 NumPy 数组。 -
nunique():计数首选。当你只关心“有多少种”时使用。它能快速给出统计概览。 -
drop_duplicates():数据清洗首选。当你需要删除重复行,或者需要保留唯一值对应的原始索引以便后续操作时使用。 -
value_counts():分析首选。当你不仅想知道是什么,还想知道“有多少个”时使用。它是数据分布分析的神器。 -
set():快速原型首选。如果你在进行纯 Python 操作或处理小型列表,这是一个简单的技巧,但在大型数据分析中通常不如 Pandas 原生方法稳健。
给开发者的建议:
在真实的生产环境中,数据往往是杂乱的。在使用 INLINECODEb43c0c7c 或 INLINECODEcd44398b 之前,请务必先进行数据清洗(如处理空格、统一大小写、处理 NaN),这不仅能得到更准确的分析结果,还能避免许多难以调试的 Bug。
希望这篇指南能帮助你更高效地处理 Pandas 数据!你可以尝试修改文中的代码,看看不同参数下结果会有什么变化。