pandas中Series.unique()保留首次出现顺序,np.unique()强制升序;nunique()默认忽略NaN计数;value_counts()可统计频次并支持排序、归一化及分箱;多列去重应使用drop_duplicates()而非嵌套unique()。

unique() 返回去重后的数组,但不保留原始顺序
unique() 是 NumPy 的函数,pandas 中 Series 也提供了同名方法。它返回的是一个 numpy.ndarray,**默认会排序**(升序),哪怕原始数据是时间序列或带业务含义的乱序。比如:
import pandas as pd s = pd.Series(['c', 'a', 'b', 'a']) s.unique() # 返回 array(['c', 'a', 'b'], dtype=object) —— 顺序按首次出现?错!实际是 ['a' 'b' 'c']注意:pandas 1.5+ 版本中,
Series.unique() **确实保留首次出现顺序**,但 NumPy 的 np.unique() 仍强制排序。容易混淆的点在于——你调用的是哪个 unique。实操建议:
- 明确用
s.unique()(pandas Series 方法),它保持首次出现顺序,且不排序 - 避免直接用
np.unique(s),除非你真需要排序结果或处理缺失值的特定逻辑 -
unique()会把NaN当作一个有效值返回(即NaN出现在结果中)
nunique() 只返回唯一值个数,天然忽略 NaN
nunique() 是 pandas Series/DataFrame 的专属方法,只计数,不返回具体值。nunique() 默认参数 dropna=True,所以 NaN 不参与计数——这点和 len(s.unique()) 不同(后者会把 NaN 算进去)。常见错误:
s = pd.Series([1, 2, 2, None]) print(len(s.unique())) # 4 → [1, 2, nan] + nan?其实是 3 个元素,但 len(s.unique()) == 3(nan 算 1 个) print(s.nunique()) # 2 → 正确忽略 NaN使用场景:
- 做数据质量检查时,用
s.nunique() / len(s)快速算重复率 - 在
groupby().agg()中统计每组不同值数量,直接写'nunique'字符串即可 - 若需包含
NaN计数,显式传参s.nunique(dropna=False)
想同时看唯一值和频次?别硬套 unique + count —— 直接用 value_counts()
很多人想“先取唯一值,再逐个统计频次”,结果写一堆循环或 map(s.value_counts().get),既慢又易错。value_counts() 一步到位,返回 Series,索引是唯一值,值是对应频次。它默认降序排列,且默认 dropna=True。关键细节:
-
value_counts(sort=False)可关闭排序,此时顺序按首次出现(类似unique()行为) -
value_counts(normalize=True)直接得比例,不用自己除总数 - 对数值型列,
value_counts(bins=5)还能自动分箱统计 - 注意:空 Series 调用
value_counts()返回空Series,不是0或None
DataFrame 多列组合去重,别用 unique() 套嵌套 —— 用 drop_duplicates()
面对多列联合去重(比如找“用户ID+日期”组合的唯一记录),别试图对多列分别调 unique() 再交叉验证。drop_duplicates() 才是正解,它作用于整行:
df = pd.DataFrame({'user': [1,1,2], 'day': ['2023-01-01', '2023-01-01', '2023-01-02']})
df.drop_duplicates(subset=['user', 'day']) # 返回前两行去重后结果注意:
-
subset参数指定列名列表,不传则全列参与判断 -
keep='first'(默认)保留首次出现;keep=False则只留完全不重复的行 - 若只要知道有多少组唯一组合,用
df.drop_duplicates(subset=[...]).shape[0],比df.groupby([...]).ngroups更轻量
drop_duplicates() 对含 NaN 的列行为和 == 一致——即两行都含 NaN 在同一列,会被视为相等(即去重掉),这点和 SQL 的 GROUP BY 一致,但容易被忽略。


















