np.unique()本身不返回重复元素,只返回去重后的数组;需配合return_counts=True获取频次,再用counts>1布尔索引vals才能正确提取重复值。

np.unique() 怎么返回重复元素本身
直接说结论:np.unique() 本身不返回“哪些是重复的”,它只返回去重后的数组;要揪出重复元素,得靠 return_counts=True 配合布尔索引。常见错误是拿到 counts 后忘了和 unique 结果对齐,结果索引错位、查到的值完全不对。
- 先调用
np.unique(arr, return_counts=True),得到两个数组:vals(唯一值)和counts(对应频次) - 用
counts > 1筛出频次大于 1 的位置,再用这个布尔数组索引vals,才是真正的重复元素 - 别用原始数组做布尔索引——比如
arr[counts > 1]是错的,维度不匹配,会报IndexError: boolean index did not match indexed array
示例:
import numpy as np<br>arr = np.array([1, 2, 2, 3, 3, 3, 4])<br>vals, counts = np.unique(arr, return_counts=True)<br>repeats = vals[counts > 1] # → array([2, 3])
为什么不能直接用 np.where(arr == x) 找重复
手动遍历每个唯一值再用 np.where() 查位置,逻辑上可行,但效率低、代码冗长,且容易漏掉边界情况。真正的问题在于:你通常不需要所有重复位置,只需要知道“哪些值重复了”或“重复几次”。用 np.unique(..., return_counts=True) 一次搞定,底层是排序+遍历,O(n log n),比多次 np.where 快得多。
- 多次
np.where(arr == x)在大数组上会触发多次全量扫描,时间复杂度接近 O(n²) -
np.unique对浮点数默认使用近似相等判断(受equal_nan和精度影响),而==是严格比较,二者行为不一致,混用可能漏掉本该算重复的浮点值 - 如果只要判断“是否存在重复”,用
len(np.unique(arr)) 比循环加 <code>set更 NumPy 风格,也更省内存
return_counts=True 在不同 dtype 下的表现
return_counts=True 本身不改变数据类型,但输出的 counts 恒为 int64(除非输入为空),这点容易被忽略。尤其当原始数组是 uint8 或 float32 时,别误以为 counts 会跟着变类型。
- 对字符串数组、对象数组同样有效,但性能明显下降——因为要逐个做哈希/比较,不像数值型有快速排序路径
- 遇到
NaN:默认把所有NaN当作相等(即归为同一组),除非显式传equal_nan=False(NumPy ≥ 1.25) - 结构化数组不支持
return_counts=True,会报TypeError: cannot compute counts for structured arrays
想保留原始顺序找重复?np.unique 不行,换 np_index
np.unique() 默认排序输出,如果你需要按首次出现顺序列出重复元素(比如日志里最早重复的那个 ID),它做不到。这时候得绕开 np.unique,改用 np.searchsorted 或更直接的 np_index 类技巧,但最稳的方式其实是用 Python 原生 dict 计数再转回数组。
- 用
from collections import Counter+np.array(list(Counter(arr).items()))能保序,但失去向量化优势,适合中小数组( - 真要纯 NumPy 保序,得配合
np.argsort()和累计计数逻辑,代码变复杂,可读性差,多数场景没必要 - 一个隐藏坑:
np.unique(arr, return_index=True)返回的是每个唯一值**第一次出现的位置**,不是重复位置——别把它和“找重复”混淆
重复这件事,本质是统计问题。用对 return_counts=True 就省掉八成逻辑,但得盯住它的排序天性和类型契约,不然查出来的“重复”,可能是你没意识到的排序后结果。

















