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 soignée?
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 soignée?
Réponses:
Si votre liste contient tous les entiers non négatifs, vous devriez jeter un œil à numpy.bincounts:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.bincount.html
puis utilisez probablement 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 souhaitez simplement travailler en python sans utiliser numpy, collections.Counter
c'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))
scipy.stats.mode
, bien que moins général.
Counter(array).most_common(1)[0][0]
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.
values[counts.argmax()]
renvoie la première valeur. Pour les obtenir tous, nous pouvons utiliser values[counts == counts.max()]
.
>>> # 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» pour les petits tableaux comme le problème.
Selon @David Sanders, si vous augmentez la taille du tableau à quelque chose comme 100 000 éléments, l'algorithme "max w / set" finit par être de loin le pire alors que la méthode "numpy bincount" est la meilleure.
a = (np.random.rand(100000) * 1000).round().astype('int'); a_list = list(a)
), votre algorithme "max w / set" finit par être de loin le pire alors que la méthode "numpy bincount" est la meilleure. J'ai effectué ce test en utilisant a_list
du code python natif et a
du code numpy pour éviter que les coûts de marshalling ne gâchent les résultats.
De plus, si vous souhaitez 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)))
max(set(lVals), key=lVals.count)
, qui fait un compte O (n) pour chaque élément unique de lVals
pour approximativement O (n ^ 2) (en supposant que O (n) unique éléments). L'utilisation collections.Counter(lVals).most_common(1)[0][0]
de la bibliothèque standard, comme suggéré par JoshAdel , n'est que O (n).
Bien que la plupart des réponses ci-dessus soient utiles, au cas où vous: 1) en auriez besoin pour prendre en charge des valeurs entières non positives (par exemple, des nombres flottants ou des entiers négatifs ;-)), et 2) ne sont pas sur Python 2.7 (quelles collections. requiert), 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]
Extension de cette méthode , appliquée à la recherche du mode des données pour lequel 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 de supprimer le mode lorsque len (np.argmax (count))> 1
Dans Python 3, les éléments suivants devraient fonctionner:
max(set(a), key=lambda x: a.count(x))
À partir de Python 3.4
, la bibliothèque standard inclut la statistics.mode
fonction pour renvoyer le point de données le plus courant.
from statistics import mode
mode([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1])
# 1
S'il existe plusieurs modes avec la même fréquence, statistics.mode
renvoie le premier rencontré.
À partir de Python 3.8
, la statistics.multimode
fonction renvoie une liste des valeurs les plus fréquentes dans l'ordre dans lequel elles ont été rencontrées pour la première fois:
from statistics import multimode
multimode([1, 2, 3, 1, 2])
# [1, 2]
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 trouvé que c'est beaucoup plus rapide que scipy.stats.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 j'utilise des collections.Counter (ce qui m'a torturé).
Le compteur dans les collections a une très très mauvaise performance à mon avis. C'est juste une classe enveloppant dict ().
Ce qui est pire, si vous utilisez cProfile pour profiler sa méthode, vous devriez voir beaucoup de choses '__missing__' et '__instancecheck__' gaspiller tout le temps.
Soyez prudent en utilisant son most_common (), car à chaque fois 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, bincount de numpy a aussi un problème: si vous utilisez np.bincount ([1,2,4000000]), vous obtiendrez un tableau avec 4000000 éléments.
np.bincount([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1]).argmax()