本文介绍如何在不使用显式 python 循环的前提下,高效提取 numpy 二维数组中每一行的众数(即出现次数最多的全部值),适用于大规模数据场景,并提供简洁、可扩展的解决方案。
本文介绍如何在不使用显式 python 循环的前提下,高效提取 numpy 二维数组中每一行的众数(即出现次数最多的全部值),适用于大规模数据场景,并提供简洁、可扩展的解决方案。
在科学计算和数据预处理中,常需对二维数组按行统计频次并提取众数(mode)。与单值众数不同,一行中可能存在多个值并列最高频次(如 [2,7,7,2,1] 中 2 和 7 均出现 2 次),此时需返回所有最大频次对应的值,而非仅第一个。np.unique 虽支持逐行调用,但原生不支持跨行向量化求众数;而 scipy.stats.mode 默认只返回首个众数且不支持多众数模式,易造成结果丢失。
推荐使用 Python 标准库中的 statistics.multimode —— 它专为处理“多众数”场景设计,输入任意可迭代对象,返回出现频次严格最高的所有元素(列表形式),且保证顺序稳定(按首次出现顺序)。
以下为完整实现:
import numpy as np
from statistics import multimode
# 示例数据:(3, 5) 二维数组
a = np.asarray([[2, 7, 7, 2, 1],
[1, 2, 3, 5, 5],
[6, 6, 6, 6, 6]])
# 向量化应用 multimode(本质是 map,但无显式 for 循环)
result = list(map(multimode, a))
print(result)
# 输出:[[2, 7], [5], [6]]✅ 优势说明:
- 零循环依赖:map(multimode, a) 利用 NumPy 数组的可迭代性(按行迭代),底层由 C 实现,性能远优于手写 for 循环;
- 天然支持多众数:multimode 明确定义为“返回所有最大频次元素”,无需额外逻辑判断;
- 类型安全 & 兼容性强:支持整数、浮点数、字符串等可哈希类型,与 NumPy dtype 无缝衔接;
- 内存友好:不构造中间频次表(如 np.unique(..., return_counts=True) 的双数组输出),避免冗余存储。
⚠️ 注意事项:
- 若某行所有元素频次均为 1(如 [1,2,3,4]),multimode 将返回全部元素(因它们并列最高频次),这是符合统计定义的正确行为;若业务要求“仅当频次 > 1 时才返回”,需后置过滤:
result = [modes if len(modes) > 1 or np.bincount(modes)[modes[0]] > 1 else [] for modes in map(multimode, a)]
- multimode 自 Python 3.8 起引入,确保运行环境满足版本要求;旧版本可降级使用 collections.Counter 手动实现(见附录);
- 对超大规模数组(千万级行),map + list 仍会生成 Python 列表,若需进一步优化内存,可结合生成器表达式或分块处理。
? 总结:面对“每行多众数提取”这一高频需求,statistics.multimode 是兼顾简洁性、正确性与性能的最优解。它规避了 np.unique 的维度局限与 scipy.stats.mode 的单值限制,是 NumPy 生态中值得纳入工具箱的标准方案。










