web-dev-qa-db-fra.com

Python - trouve l'élément avec un maximum d'occurrences dans une liste

En Python, j'ai une liste:

L = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]  

Je souhaite identifier l'élément qui s'est produit le plus grand nombre de fois. Je suis capable de le résoudre mais j'ai besoin du moyen le plus rapide de le faire. Je sais qu'il existe une bonne réponse pythonique à cette question. 

43
zubinmehta

Voici une solution defaultdict qui fonctionnera avec les versions 2.5 et supérieures de Python:

from collections import defaultdict

L = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67]
d = defaultdict(int)
for i in L:
    d[i] += 1
result = max(d.iteritems(), key=lambda x: x[1])
print result
# (4, 6)
# The number 4 occurs 6 times

Notez que si L = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 7, 7, 7, 7, 7, 56, 6, 7, 67].__, il y a six 4 et six 7. Cependant, le résultat sera (4, 6), c'est-à-dire six 4s.

12
Andrew Clark
from collections import Counter
most_common,num_most_common = Counter(L).most_common(1)[0] # 4, 6 times

Pour les anciennes versions de Python (<2.7), vous pouvez utiliser this reçu pour obtenir la classe Counter .

82
phihag

Je suis surpris que personne n'ait mentionné la solution la plus simple, max() avec la clé list.count:

max(lst,key=lst.count)

Exemple:

>>> lst = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]
>>> max(lst,key=lst.count)
4

Cela fonctionne en Python 3 ou 2, mais notez qu'il ne retourne que l'élément le plus fréquent et non la fréquence. De même, dans le cas d’un draw (c’est-à-dire l’élément le plus souvent associé), un seul élément est renvoyé.

Bien que la complexité temporelle de l’utilisation de max() soit pire que celle de Counter.most_common(1) comme PM 2Ring comments, l’approche bénéficie d’une implémentation rapide de C 3.6 timings montrés dans IPython 5.3):

In [1]: from collections import Counter
   ...: 
   ...: def f1(lst):
   ...:     return max(lst, key = lst.count)
   ...: 
   ...: def f2(lst):
   ...:     return Counter(lst).most_common(1)
   ...: 
   ...: lst0 = [1,2,3,4,3]
   ...: lst1 = lst0[:] * 100
   ...: 

In [2]: %timeit -n 10 f1(lst0)
10 loops, best of 3: 3.32 us per loop

In [3]: %timeit -n 10 f2(lst0)
10 loops, best of 3: 26 us per loop

In [4]: %timeit -n 10 f1(lst1)
10 loops, best of 3: 4.04 ms per loop

In [5]: %timeit -n 10 f2(lst1)
10 loops, best of 3: 75.6 us per loop
52
Chris_Rands

Dans votre question, vous avez demandé le moyen le plus rapide de le faire. Comme cela a été démontré à maintes reprises, en particulier avec Python, l'intuition n'est pas un guide fiable: vous devez mesurer. 

Voici un test simple de plusieurs implémentations différentes:

import sys
from collections import Counter, defaultdict
from itertools import groupby
from operator import itemgetter
from timeit import timeit

L = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67]

def max_occurrences_1a(seq=L):
    "dict iteritems"
    c = dict()
    for item in seq:
        c[item] = c.get(item, 0) + 1
    return max(c.iteritems(), key=itemgetter(1))

def max_occurrences_1b(seq=L):
    "dict items"
    c = dict()
    for item in seq:
        c[item] = c.get(item, 0) + 1
    return max(c.items(), key=itemgetter(1))

def max_occurrences_2(seq=L):
    "defaultdict iteritems"
    c = defaultdict(int)
    for item in seq:
        c[item] += 1
    return max(c.iteritems(), key=itemgetter(1))

def max_occurrences_3a(seq=L):
    "sort groupby generator expression"
    return max(((k, sum(1 for i in g)) for k, g in groupby(sorted(seq))), key=itemgetter(1))

def max_occurrences_3b(seq=L):
    "sort groupby list comprehension"
    return max([(k, sum(1 for i in g)) for k, g in groupby(sorted(seq))], key=itemgetter(1))

def max_occurrences_4(seq=L):
    "counter"
    return Counter(L).most_common(1)[0]

versions = [max_occurrences_1a, max_occurrences_1b, max_occurrences_2, max_occurrences_3a, max_occurrences_3b, max_occurrences_4]

print sys.version, "\n"

for vers in versions:
    print vers.__doc__, vers(), timeit(vers, number=20000)

Les résultats sur ma machine:

2.7.2 (v2.7.2:8527427914a2, Jun 11 2011, 15:22:34) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] 

dict iteritems (4, 6) 0.202214956284
dict items (4, 6) 0.208412885666
defaultdict iteritems (4, 6) 0.221301078796
sort groupby generator expression (4, 6) 0.383440971375
sort groupby list comprehension (4, 6) 0.402786016464
counter (4, 6) 0.564319133759

Il semble donc que la solution Counter n’est pas la plus rapide. Et, dans ce cas au moins, groupby est plus rapide. defaultdict est bon mais vous payez un peu pour sa commodité; il est légèrement plus rapide d'utiliser une dict régulière avec une get.

Qu'advient-il si la liste est beaucoup plus grande? Ajouter L *= 10000 au test ci-dessus et réduire le nombre de répétitions à 200:

dict iteritems (4, 60000) 10.3451900482
dict items (4, 60000) 10.2988479137
defaultdict iteritems (4, 60000) 5.52838587761
sort groupby generator expression (4, 60000) 11.9538850784
sort groupby list comprehension (4, 60000) 12.1327362061
counter (4, 60000) 14.7495789528

Maintenant, defaultdict est le gagnant clair. Alors peut-être que le coût de la méthode 'get' et de la perte de la place en place s’additionne (un examen du code généré est laissé comme un exercice).

Mais avec les données de test modifiées, le nombre de valeurs d’élément uniques n’ayant pas changé, on suppose que dict et defaultdict y ont un avantage par rapport aux autres implémentations. Alors que se passe-t-il si nous utilisons la liste la plus longue en augmentant considérablement le nombre d'articles uniques? Remplacer l'initialisation de L par:

LL = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67]
L = []
for i in xrange(1,10001):
    L.extend(l * i for l in LL)

dict iteritems (2520, 13) 17.9935798645
dict items (2520, 13) 21.8974409103
defaultdict iteritems (2520, 13) 16.8289561272
sort groupby generator expression (2520, 13) 33.853593111
sort groupby list comprehension (2520, 13) 36.1303369999
counter (2520, 13) 22.626899004

Alors maintenant, Counter est clairement plus rapide que les solutions groupby mais reste plus lent que les versions iteritems de dict et defaultdict.

Le but de ces exemples n'est pas de produire une solution optimale. Le fait est qu’il n’existe souvent pas une solution générale optimale. De plus, il existe d'autres critères de performance. Les besoins en mémoire varieront considérablement entre les solutions et, à mesure que la taille de l'entrée augmentera, les besoins en mémoire pourraient devenir le facteur déterminant dans la sélection de l'algorithme.

En bout de ligne: tout dépend et il faut mesurer.

25
Ned Deily

Peut-être la most_common () method

2
Danny

J'ai obtenu les meilleurs résultats avec le module groupby de itertools avec cette fonction utilisant Python 3.5.2:

from itertools import groupby

a = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]

def occurrence():
    occurrence, num_times = 0, 0
    for key, values in groupby(a, lambda x : x):
        val = len(list(values))
        if val >= occurrence:
            occurrence, num_times =  key, val
    return occurrence, num_times

occurrence, num_times = occurrence()
print("%d occurred %d times which is the highest number of times" % (occurrence, num_times))

Sortie:

4 occurred 6 times which is the highest number of times

Testez avec le module timeit du module timeit.

J'ai utilisé ce script pour mon test avec number= 20000:

from itertools import groupby

def occurrence():
    a = [1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]
    occurrence, num_times = 0, 0
    for key, values in groupby(a, lambda x : x):
        val = len(list(values))
        if val >= occurrence:
            occurrence, num_times =  key, val
    return occurrence, num_times

if __== '__main__':
    from timeit import timeit
    print(timeit("occurrence()", setup = "from __main__ import occurrence",  number = 20000))

Sortie (le meilleur):

0.1893607140000313
1
Chiheb Nexus

Un moyen simple sans bibliothèques ni ensembles

def mcount(l):
  n = []                  #To store count of each elements
  for x in l:
      count = 0
      for i in range(len(l)):
          if x == l[i]:
              count+=1
      n.append(count)
  a = max(n)              #largest in counts list
  for i in range(len(n)):
      if n[i] == a:
          return(l[i],a)  #element,frequency
  return                  #if something goes wrong
1
Prashanth ram

Je veux ajouter une autre solution qui a l'air bien et qui est rapide pour short listes.

def mc(seq=L):
    "max/count"
    max_element = max(seq, key=seq.count)
    return (max_element, seq.count(max_element))

Vous pouvez comparer cela avec le code fourni par Ned Deily qui vous donnera ces résultats pour le plus petit scénario de test:

3.5.2 (default, Nov  7 2016, 11:31:36) 
[GCC 6.2.1 20160830] 

dict iteritems (4, 6) 0.2069783889998289
dict items (4, 6) 0.20462976200065896
defaultdict iteritems (4, 6) 0.2095775119996688
sort groupby generator expression (4, 6) 0.4473949929997616
sort groupby list comprehension (4, 6) 0.4367636879997008
counter (4, 6) 0.3618192010007988
max/count (4, 6) 0.20328268999946886

Mais méfiez-vous, il est inefficace et devient donc vraiment lent pour les grandes listes!

0
dd23

peut quelque chose comme ceci:

testList = [1, 2, 3, 4, 2, 2, 1, 4, 4] print(max(set(testList), key = testList.count))

0
BreakBadSP

Voici la solution que j'ai trouvée s'il y a plusieurs caractères dans la chaîne ayant tous la fréquence la plus élevée.

mystr = input("enter string: ")
#define dictionary to store characters and their frequencies
mydict = {}
#get the unique characters
unique_chars = sorted(set(mystr),key = mystr.index)
#store the characters and their respective frequencies in the dictionary
for c in unique_chars:
    ctr = 0
    for d in mystr:
        if d != " " and d == c:
            ctr = ctr + 1
    mydict[c] = ctr
print(mydict)
#store the maximum frequency
max_freq = max(mydict.values())
print("the highest frequency of occurence: ",max_freq)
#print all characters with highest frequency
print("the characters are:")
for k,v in mydict.items():
    if v == max_freq:
        print(k)

Entrée: "Bonjour les gens"

Sortie:

{'o': 2, 'p': 2, 'h': 1, ' ': 0, 'e': 3, 'l': 3}

la plus haute fréquence d'occurrence: 3

les personnages sont:

e

l
0
Arko

Code simple et meilleur: 

def max_occ(lst,x):
    count=0
    for i in lst:
        if (i==x):
            count=count+1
    return count

lst=[1, 2, 45, 55, 5, 4, 4, 4, 4, 4, 4, 5456, 56, 6, 7, 67]
x=max(lst,key=lst.count)
print(x,"occurs ",max_occ(lst,x),"times")

Sortie: 4 se produit 6 fois 

0
Ranjith M