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 d'une manière soignée?

74
demandé sur MosteM 2011-06-06 16:51:40

10 réponses

Si votre liste contient tous les ints non négatifs, vous devriez jeter un oeil à numpy.bincounts:

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

Et ensuite 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 (qui contient peut-être des nombres négatifs ou des valeurs non entières), vous pouvez utiliser np.histogram de la même manière. Alternativement, si vous voulez juste travailler en python sans utiliser numpy, collections.Counter est un bon moyen de gérer ce genre 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)
140
répondu JoshAdel 2011-06-06 13:16:24

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 retournera que le premier élément.

46
répondu Apogentus 2015-02-26 07:37:36

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
répondu Fred Foo 2011-06-06 13:10:09

Performances (en utilisant 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 Meilleur est ' max 'avec' set '

16
répondu iuridiniz 2016-07-29 13:36:46

Alors que la plupart des réponses ci-dessus sont utiles, au cas où vous: 1) Besoin de prendre en charge des valeurs entières non positives (par exemple des nombres entiers flottants ou négatifs; -)), et 2) ne sont pas sur Python 2.7 (quelles collections.Compteur exige), et 3) préférez ne pas ajouter la dépendance de scipy (ou même numpy) à votre code, alors 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
répondu JJC 2015-01-08 16:26:22

Aussi, si vous voulez obtenir la valeur la plus fréquente (positive ou Négative) sans charger de modules, 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)))
1
répondu Artsiom Rudzenka 2011-06-06 13:25:09

J'aime la solution de JoshAdel.

Mais il n'y a qu'un seul hic.

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

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

1
répondu Vikas 2016-02-23 19:49:42

Expansion sur cette méthode , appliquée à trouver le mode des données où vous pouvez avoir besoin de l'index du tableau réel pour voir à quelle distance la valeur est 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 d'ignorer le mode lorsque len (np.argmax (compte)) > 1

1
répondu Lean Bravo 2017-05-23 11:55:03

Voici une solution générale qui peut être appliquée le long d'un axe, indépendamment des valeurs, en utilisant purement numpy. J'ai également trouvé que c'est beaucoup plus rapide que scipy.statistique.mode s'il y a beaucoup de 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
répondu Devin Cairns 2017-04-01 21:03:55

Je fais récemment un projet et utilise des collections.Compteur.(Qui m'a torturé).

Le compteur dans les collections a une très très mauvaise performance à mon avis. C'est juste un emballage de classe dict().

Ce qui est pire, si vous utilisez cProfile pour profiler sa méthode, vous devriez voir beaucoup de choses '__missing__' et '__instancecheck__' perdre tout le temps.

Soyez prudent en utilisant sa most_common (), car chaque fois qu'il invoquerait un tri qui le rend extrêmement lent. et si vous utilisez most_common( x), il invoquera un tri de tas, qui est également lent.

Btw, le compte bincount de numpy a également un problème: si vous utilisez np.bincount([1,2,4000000]), vous obtiendrez un tableau avec 4000000 éléments.

-1
répondu Weichu Liu 2013-01-06 17:42:33