查找 NumPy 数组中出现频率最高的数字

2025-03-18 08:55:00
admin
原创
37
摘要:问题描述:假设我有以下 NumPy 数组:a = np.array([1,2,3,1,2,1,1,1,3,2,2,1]) 我怎样才能找到这个数组中出现频率最高的数字?解决方案 1:如果您的列表包含所有非负整数,您应该查看numpy.bincounts:http://docs.scipy.org/doc/num...

问题描述:

假设我有以下 NumPy 数组:

a = np.array([1,2,3,1,2,1,1,1,3,2,2,1])

我怎样才能找到这个数组中出现频率最高的数字?


解决方案 1:

如果您的列表包含所有非负整数,您应该查看numpy.bincounts:

http://docs.scipy.org/doc/numpy/reference/ generated/numpy.bincount.html

然后可能使用 np.argmax:

a = np.array([1,2,3,1,2,1,1,1,3,2,2,1])
counts = np.bincount(a)
print(np.argmax(counts))

对于更复杂的列表(可能包含负数或非整数值),您可以np.histogram以类似的方式使用。或者,如果您只想使用 python 而不使用 numpy,collections.Counter这是一种处理此类数据的好方法。

from collections import Counter
a = [1,2,3,1,2,1,1,1,3,2,2,1]
b = Counter(a)
print(b.most_common(1))

解决方案 2:

您可以使用

values, counts = np.unique(a, return_counts=True)

ind = np.argmax(counts)
print(values[ind])  # prints the most frequent element

ind = np.argpartition(-counts, kth=10)[:10]
print(values[ind])  # prints the 10 most frequent elements

如果某个元素与另一个元素一样频繁,则此代码将仅返回第一个元素。

解决方案 3:

如果您愿意使用SciPy:

>>> from scipy.stats import mode
>>> mode([1,2,3,1,2,1,1,1,3,2,2,1])
(array([ 1.]), array([ 6.]))
>>> most_frequent = mode([1,2,3,1,2,1,1,1,3,2,2,1])[0][0]
>>> most_frequent
1.0

解决方案 4:

一些解决方案的性能(使用 iPython)在这里找到:

>>> # small array
>>> a = [12,3,65,33,12,3,123,888000]
>>> 
>>> import collections
>>> collections.Counter(a).most_common()[0][0]
3
>>> %timeit collections.Counter(a).most_common()[0][0]
100000 loops, best of 3: 11.3 µs per loop
>>> 
>>> import numpy
>>> numpy.bincount(a).argmax()
3
>>> %timeit numpy.bincount(a).argmax()
100 loops, best of 3: 2.84 ms per loop
>>> 
>>> import scipy.stats
>>> scipy.stats.mode(a)[0][0]
3.0
>>> %timeit scipy.stats.mode(a)[0][0]
10000 loops, best of 3: 172 µs per loop
>>> 
>>> from collections import defaultdict
>>> def jjc(l):
...     d = defaultdict(int)
...     for i in a:
...         d[i] += 1
...     return sorted(d.iteritems(), key=lambda x: x[1], reverse=True)[0]
... 
>>> jjc(a)[0]
3
>>> %timeit jjc(a)[0]
100000 loops, best of 3: 5.58 µs per loop
>>> 
>>> max(map(lambda val: (a.count(val), val), set(a)))[1]
12
>>> %timeit max(map(lambda val: (a.count(val), val), set(a)))[1]
100000 loops, best of 3: 4.11 µs per loop
>>> 

对于像这个问题一样的小数组,最好的方法是将“max”与“set”结合起来。

根据@David Sanders 的说法,如果将数组大小增加到 100,000 个元素左右,那么“max w/set”算法最终会成为最差的算法,而“numpy bincount”方法则是最好的。

解决方案 5:

从 开始Python 3.4,标准库包含statistics.mode返回单个最常见数据点的函数。

from statistics import mode

mode([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1])
# 1

如果有多个具有相同频率的模式,statistics.mode则返回遇到的第一个模式。


从 开始Python 3.8,该statistics.multimode函数按首次遇到的顺序返回最常出现的值的列表:

from statistics import multimode

multimode([1, 2, 3, 1, 2])
# [1, 2]

解决方案 6:

此外,如果您想在不加载任何模块的情况下获取最常见的值(正值或负值),您可以使用以下代码:

lVals = [1,2,3,1,2,1,1,1,3,2,2,1]
print max(map(lambda val: (lVals.count(val), val), set(lVals)))

解决方案 7:

虽然上述大多数答案都很有用,但如果:1)需要它支持非正整数值(例如浮点数或负整数;-)),并且2)不在 Python 2.7 上(collections.Counter 需要),并且3)不想在代码中添加 scipy(甚至 numpy)的依赖项,那么纯 python 2.6 解决方案即 O(nlogn)(即高效)就是这样:

from collections import defaultdict

a = [1,2,3,1,2,1,1,1,3,2,2,1]

d = defaultdict(int)
for i in a:
  d[i] += 1
most_frequent = sorted(d.iteritems(), key=lambda x: x[1], reverse=True)[0]

解决方案 8:

在 Python 3 中,以下操作应该可以工作:

max(set(a), key=lambda x: a.count(x))

解决方案 9:

我喜欢 JoshAdel 的解决方案。

但只有一个问题。

np.bincount()解决方案仅适用于数字。

如果您有字符串,collections.Counter解决方案将适合您。

解决方案 10:

这是一个通用解决方案,可以沿轴应用,无论值如何,仅使用 numpy。我还发现,如果有很多唯一值,这比 scipy.stats.mode 快得多。

import numpy

def mode(ndarray, axis=0):
    # Check inputs
    ndarray = numpy.asarray(ndarray)
    ndim = ndarray.ndim
    if ndarray.size == 1:
        return (ndarray[0], 1)
    elif ndarray.size == 0:
        raise Exception('Cannot compute mode on empty array')
    try:
        axis = range(ndarray.ndim)[axis]
    except:
        raise Exception('Axis "{}" incompatible with the {}-dimension array'.format(axis, ndim))

    # If array is 1-D and numpy version is > 1.9 numpy.unique will suffice
    if all([ndim == 1,
            int(numpy.__version__.split('.')[0]) >= 1,
            int(numpy.__version__.split('.')[1]) >= 9]):
        modals, counts = numpy.unique(ndarray, return_counts=True)
        index = numpy.argmax(counts)
        return modals[index], counts[index]

    # Sort array
    sort = numpy.sort(ndarray, axis=axis)
    # Create array to transpose along the axis and get padding shape
    transpose = numpy.roll(numpy.arange(ndim)[::-1], axis)
    shape = list(sort.shape)
    shape[axis] = 1
    # Create a boolean array along strides of unique values
    strides = numpy.concatenate([numpy.zeros(shape=shape, dtype='bool'),
                                 numpy.diff(sort, axis=axis) == 0,
                                 numpy.zeros(shape=shape, dtype='bool')],
                                axis=axis).transpose(transpose).ravel()
    # Count the stride lengths
    counts = numpy.cumsum(strides)
    counts[~strides] = numpy.concatenate([[0], numpy.diff(counts[~strides])])
    counts[strides] = 0
    # Get shape of padded counts and slice to return to the original shape
    shape = numpy.array(sort.shape)
    shape[axis] += 1
    shape = shape[transpose]
    slices = [slice(None)] * ndim
    slices[axis] = slice(1, None)
    # Reshape and compute final counts
    counts = counts.reshape(shape).transpose(transpose)[slices] + 1

    # Find maximum counts and return modals/counts
    slices = [slice(None, i) for i in sort.shape]
    del slices[axis]
    index = numpy.ogrid[slices]
    index.insert(axis, numpy.argmax(counts, axis=axis))
    return sort[index], counts[index]

解决方案 11:

扩展此方法,用于查找数据的模式,您可能需要实际数组的索引来查看该值与分布中心的距离。

(_, idx, counts) = np.unique(a, return_index=True, return_counts=True)
index = idx[np.argmax(counts)]
mode = a[index]

当 len(np.argmax(counts)) > 1 时,记得丢弃模式

解决方案 12:

您可以使用以下方法:

x = np.array([[2, 5, 5, 2], [2, 7, 8, 5], [2, 5, 7, 9]])
u, c = np.unique(x, return_counts=True)
print(u[c == np.amax(c)])

这将给出答案:array([2, 5])

解决方案 13:

使用np.bincountnp.argmax方法可以获取 numpy 数组中最常见的值。如果您的数组是图像数组,请使用np.ravelnp.flatten()方法将 ndarray 转换为一维数组。

解决方案 14:

我最近正在做一个项目,使用了 collections.Counter。(这让我很折磨)。

我认为集合中的 Counter 性能非常非常差。它只是一个包装 dict() 的类。

更糟糕的是,如果您使用 cProfile 来分析其方法,您会看到很多“__missing__”和“__instancecheck__”的东西浪费了整个时间。

要小心使用其 most_common(),因为每次它都会调用排序,这会使速度非常慢。如果使用 most_common(x),它将调用堆排序,这也会很慢。

顺便说一句,numpy 的 bincount 也有一个问题:如果你使用 np.bincount([1,2,4000000]),你将得到一个包含 4000000 个元素的数组。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用