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

Jus*_*ime 103 python statistics numpy

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

a = [1,2,3,1,2,1,1,1,3,2,2,1]
Run Code Online (Sandbox Code Playgroud)

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

Jos*_*del 170

如果你的列表包含所有非负的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)
Run Code Online (Sandbox Code Playgroud)

对于更复杂的列表(可能包含负数或非整数值),您可以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)
Run Code Online (Sandbox Code Playgroud)

  • +1.可能只是`np.bincount([1,2,3,1,2,1,1,1,3,2,2,1]).argmax()` (51认同)
  • 对于我们这些在2016年之后访问的人:我不喜欢这个答案,因为bincount(arr)返回一个与arr中最大元素一样大的数组,因此一个范围较大的小数组会创建一个过大的数组.Apoengtus的答案下面的答案要好得多,虽然我认为numpy.unique()不存在于2011年,当时这个答案已经创建了. (16认同)
  • ** Python 3 **:`Counter(array).most_common(1)[0] [0]` (2认同)

Apo*_*tus 67

你可以用

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

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

  • 如果我们有多个最频繁的值,`values[counts.argmax()]` 将返回第一个值。要获得所有这些,我们可以使用 `values[counts == counts.max()]`。 (5认同)
  • 我发现这是最有用的,因为它是通用的,简短的,并允许通过某些派生索引从值或计数中提取元素。 (4认同)

Fre*_*Foo 38

如果您愿意使用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
Run Code Online (Sandbox Code Playgroud)


iur*_*niz 24

在这里找到的一些解决方案的性能(使用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
>>> 
Run Code Online (Sandbox Code Playgroud)

'set'的最佳价格是'max'

  • 如果你将测试列表大小增加到100000(`a =(np.random.rand(100000)*1000).round().astype('int'); a_list = list(a)`),你的"max w"/set"算法到目前为止最差,而"numpy bincount"方法是最好的.我使用`a_list`进行本地python代码和`a`进行numpy代码的测试,以避免编组成本搞砸了结果. (7认同)
  • `collections.Counter`看起来是一个很好的权衡 (5认同)
  • 在您的方法中,仅使用一个小阵列,不能很好地区分不同的算法. (2认同)

Xav*_*hot 6

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

from statistics import mode

mode([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1])
# 1
Run Code Online (Sandbox Code Playgroud)

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


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

from statistics import multimode

multimode([1, 2, 3, 1, 2])
# [1, 2]
Run Code Online (Sandbox Code Playgroud)


Art*_*nka 5

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

lVals = [1,2,3,1,2,1,1,1,3,2,2,1]
print max(map(lambda val: (lVals.count(val), val), set(lVals)))
Run Code Online (Sandbox Code Playgroud)

  • 这是前一段时间,但对于后代:这等效于更易于阅读的`max(set(lVals), key=lVals.count)`,它对每个唯一元素进行 O(n) 计数`lVals` 大约为 O(n^2)(假设 O(n) 唯一元素)。使用标准库中的`collections.Counter(lVals).most_common(1)[0][0]`,正如[JoshAdel 建议的](http://stackoverflow.com/a/6252400/344821),只是O (n)。 (2认同)