web-dev-qa-db-fra.com

Trouver le nombre le plus fréquent dans un vecteur numpy

Supposons que j'ai la liste suivante en python: 

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

Comment trouver le numéro le plus fréquent dans cette liste de manière ordonnée?

84
JustInTime

Si votre liste contient tous les éléments non négatifs, consultez numpy.bincounts:

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

et puis probablement utiliser 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)

Pour une liste plus compliquée (pouvant contenir des nombres négatifs ou des valeurs non entières), vous pouvez utiliser np.histogram de la même manière. Si vous voulez simplement travailler en python sans utiliser numpy, collections.Counter est un bon moyen de gérer ce type de données.

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)
150
JoshAdel

Vous pouvez utiliser

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

Si un élément est aussi fréquent qu'un autre, ce code ne renverra que le premier élément.

56
Apogentus

Si vous êtes prêt à utiliser 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
31
Fred Foo

Performances (avec iPython) pour certaines solutions trouvées ici:

>>> # 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
>>> 

Le mieux est "max" avec "set" 

20
iuridiniz

Bien que la plupart des réponses ci-dessus soient utiles, dans le cas où vous: 1) en avez besoin pour prendre en charge les valeurs d'entier non positif (par exemple, les nombres entiers négatifs ou négatifs ;-)), et 2) ne sont pas en Python. 2.7 (que collections.Counter nécessite), et 3) préfèrent ne pas ajouter la dépendance de scipy (ou même numpy) à votre code, puis à une solution purement python 2.6 qui est O(nlogn) (c'est-à-dire , efficace) est juste ceci:

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]
2
JJC

De plus, si vous voulez obtenir la valeur la plus fréquente (positive ou négative) sans charger de module, vous pouvez utiliser le code suivant:

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

J'aime la solution de JoshAdel.

Mais il n'y a qu'une seule prise. 

La solution np.bincount() ne fonctionne que sur les chiffres.

Si vous avez des chaînes, la solution collections.Counter fonctionnera pour vous.

1
Vikas

Développer sur cette méthode , appliquée à la recherche du mode des données où vous pouvez avoir besoin de l'index du tableau réel pour voir à quelle distance se trouve la valeur du centre de la distribution. 

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

N'oubliez pas de jeter le mode quand len (np.argmax (count))> 1

1
Lean Bravo

Dans Python 3, les éléments suivants devraient fonctionner:

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

Voici une solution générale qui peut être appliquée le long d’un axe, quelles que soient les valeurs, en utilisant purement numpy. J'ai également constaté que cela est beaucoup plus rapide que scipy.stats.mode s'il existe de nombreuses valeurs uniques.

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]
0
Devin Cairns