np.unique(..., return_counts=True) 是最直接的解法:它原生高效、返回 values 和 counts 一一对应,但需显式指定参数,对浮点数、NaN、多维数组及非连续内存等场景须谨慎处理。

np.unique(..., return_counts=True) 是最直接的解法
想快速统计 NumPy 数组中每个唯一值出现多少次,np.unique 加上 return_counts=True 就是标准答案。它不依赖循环或外部库,原生高效,且返回结果对齐——unique_values 和 counts 一一对应。
常见错误是只调用 np.unique(arr) 却忘了传参,结果只拿到去重后的数组,漏掉频次信息;或者误以为 return_counts 默认为 True(实际是 False)。
- 必须显式写
return_counts=True,不能省略 - 返回是两个数组:
values, counts = np.unique(arr, return_counts=True) - 若需按频次降序排列,得手动组合再排序:
sorted_idx = np.argsort(counts)[::-1]; values = values[sorted_idx]; counts = counts[sorted_idx] - 对浮点数组要小心:
np.unique默认使用精确相等比较,小数精度差异会导致本该合并的值被拆成多个条目
处理多维数组时得先展平
np.unique 默认把整个多维数组当作一维来处理,但它不会自动展平——你得自己调用 .flatten() 或 .ravel(),否则会报错或返回意外结构。
比如对 shape 为 (2, 3) 的二维数组直接传入,np.unique 会把它当做一个包含 2 个子数组的对象数组(除非 dtype 明确是数值型且连续),结果不可靠。
立即学习“Python免费学习笔记(深入)”;
- 安全做法:
np.unique(arr.flatten(), return_counts=True) -
.ravel()更轻量,但返回视图;.flatten()总是返回副本,更稳妥 - 如果只想按行或按列统计,得用
axis=参数配合np.apply_along_axis,但这时return_counts不适用,得换思路
和 Counter 对比:什么时候不该用 np.unique
虽然 np.unique 快,但它要求输入是 NumPy 数组,且输出是 NumPy 数组。如果你的数据来自列表、字典或需要保留字符串键名映射,collections.Counter 更灵活。
典型反例:统计含 NaN 的数组。NumPy 中 np.nan != np.nan,np.unique 会把所有 NaN 当作不同值(除非加 equal_nan=True,但该参数仅在 NumPy ≥ 1.25 才支持,旧版本无效)。
- 老版本 NumPy 统计含
NaN的数组?先用np.isnan()单独计数,再对非NaN部分调用np.unique -
Counter(list(arr))能天然处理NaN(转成字符串),但失去向量化优势 - 混合类型(如 int 和 str 混存)数组会强制转为
objectdtype,np.unique行为可能不符合直觉,此时Counter更稳
性能敏感场景要注意 dtype 和内存布局
在大数据量下,np.unique 的耗时主要花在排序上(它内部用排序去重)。如果你的数组已经排好序,可以传 return_index=False, return_inverse=False, return_counts=True 省掉部分开销,但无法跳过排序本身。
另一个易忽略点:输入数组若非 C-contiguous(比如是切片或转置结果),np.unique 内部会先拷贝一份连续内存,导致额外内存占用和延迟。
- 检查是否连续:
arr.flags.c_contiguous;不连续时可提前np.ascontiguousarray(arr) - 整数数组建议用
int32或int64,避免objectdtype;浮点数组若允许误差,可先np.round(arr, decimals=5)再统计 - 超大数组(>1e7 元素)慎用——考虑分块处理或改用
pd.value_counts()(Pandas 在底层做了优化)
NaN、是不是连续、维度要不要展平——这些细节比语法本身更容易卡住。


















