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?
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)
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.
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 '
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]
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)))
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.
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
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]
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.