在numpy向量中找到最常见的数字

时间:2011-06-06 12:51:40

标签: python numpy statistics

假设我在python中有以下列表:

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

如何以整洁的方式找到此列表中最常用的号码?

13 个答案:

答案 0 :(得分:160)

如果你的列表包含所有非负的int,你应该看一下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。或者,如果您只想在不使用numpy的情况下使用python,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)

答案 1 :(得分:61)

您可以使用

(values,counts) = np.unique(a,return_counts=True)
ind=np.argmax(counts)
print values[ind]  # prints the most frequent element

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

答案 2 :(得分:32)

如果您愿意使用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

答案 3 :(得分:22)

性能(使用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'

答案 4 :(得分:4)

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]

答案 5 :(得分:2)

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

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

答案 6 :(得分:2)

虽然上面的大部分答案都很有用,但如果您: 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]

答案 7 :(得分:1)

我喜欢JoshAdel的解决方案。

但只有一个问题。

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

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

答案 8 :(得分:1)

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

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

当len(np.argmax(计数))>时,请记住放弃模式。 1

答案 9 :(得分:1)

在Python 3中,以下方法应该起作用:

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

答案 10 :(得分:0)

这是一个可以沿着轴应用的一般解决方案,无论值如何,都使用纯粹的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 :(得分:-1)

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

我认为收藏中的柜台表现非常糟糕。它只是一个包装dict()的类。

更糟糕的是,如果你使用cProfile来描述它的方法,你应该会看到很多'__missing__'和'__instancecheck__'这些东西一直在浪费。

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

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

答案 12 :(得分:-1)

您可以使用以下方法:

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])