如何高效统计numpy数组列表中各元素的重复出现次数
高效实现NumPy数组列表去重计数的方案
针对你遇到的numpy数组不可哈希,无法直接使用集合、列表count方法去重计数、暴力比对复杂度太高的问题,有两种兼顾效率和简洁性的实现方案,时间复杂度远低于O(n²)的暴力逐对比对:
方案1:NumPy原生向量化实现(最优适配场景)
这是速度最快的方案,底层基于NumPy的C层实现,没有Python层的嵌套循环,时间复杂度为O(N*M)(N为列表中的数组总个数,M为单个numpy数组的长度),比O(n²)的暴力方法快几个数量级。
实现前提
列表中所有numpy数组的形状完全一致,从你给出的排列结果结构来看,所有数组都是长度为4的一维向量,完全满足该前提。
代码实现
import numpy as np # 1. 将列表中的一维numpy数组堆叠为二维矩阵 stacked_arrs = np.stack(permutations, axis=0) # 2. 直接提取唯一行,同时返回每个唯一行的出现次数 unique_arrs, repeat_counts = np.unique(stacked_arrs, axis=0, return_counts=True) # 3. 拼接为要求的元组列表格式 neat_perm = [(arr, cnt) for arr, cnt in zip(unique_arrs, repeat_counts)]
方案2:字典哈希计数(兼容任意形状数组)
如果列表中的numpy数组存在长度不一致的情况,无法堆叠为二维矩阵,可以通过将不可哈希的numpy数组转换为可哈希的元组作为字典键,实现线性时间复杂度的计数,整体时间复杂度同样为O(N*M)。
代码实现
from collections import defaultdict count_dict = defaultdict(int) # 遍历一次列表完成计数,无嵌套比对 for arr in permutations: # 将numpy数组转为元组作为可哈希的字典键,不修改原数组内容 hashable_key = tuple(arr.tolist()) count_dict[hashable_key] += 1 # 还原为带原numpy数组的元组列表 neat_perm = [(np.array(key), cnt) for key, cnt in count_dict.items()]
方案优劣对比
- 两种方案都避免了逐对比对的O(n²)复杂度,哪怕列表规模到10万条以上,运行速度也不会出现明显卡顿
- 方案1在数组同形状的场景下,运行速度远快于纯Python实现的字典计数,是优先选择
- 方案2灵活性更高,能兼容数组形状不一致的特殊场景,同时天然保留原列表中元素的首次出现顺序
注:numpy数组作为可变对象,本身没有实现哈希接口,这就是为什么无法直接将数组丢入集合、作为字典键、使用list.count()方法的核心原因。另外,
np.unique默认会对提取出的唯一行做字典序排序,如果需要严格保留数组在原列表中第一次出现的顺序,优先使用方案2的字典计数实现(Python 3.7+的字典会自动保留键的插入顺序,和原列表遍历顺序一致)。
内容的提问来源于stack exchange,提问作者bad_chemist
相关产品推荐
相关产品推荐

