Comment compter la fréquence des éléments dans une liste non ordonnée?


237

J'ai besoin de trouver la fréquence des éléments dans une liste non ordonnée

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

sortie->

b = [4,4,2,1,2]

Je souhaite également supprimer les doublons d'un

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

Sont-ils toujours commandés comme dans cet exemple?
Farinha

@Peter. Oui, vous avez trié la liste aux fins de publication. La liste sera-t-elle toujours triée?
S.Lott

2
Non, la liste ne sera pas toujours triée. Ce ne sont pas des devoirs.
Bruce

J'essaie de tracer le graphique de la distribution des degrés d'un réseau.
Bruce

5
@Peter: Veuillez mettre à jour votre question avec les informations utiles. Veuillez ne pas ajouter de commentaires à votre question - vous êtes propriétaire de la question, vous pouvez la corriger pour qu'elle soit complète et claire.
S.Lott

Réponses:


147

Remarque: vous devez trier la liste avant de l'utiliser groupby.

Vous pouvez utiliser à groupbypartir du itertoolspackage si la liste est une liste ordonnée.

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
from itertools import groupby
[len(list(group)) for key, group in groupby(a)]

Production:

[4, 4, 2, 1, 2]

agréable, en utilisant groupby. Je m'interroge sur son efficacité par rapport à l'approche dictée, cependant
Eli Bendersky

32
Le groupe python crée de nouveaux groupes lorsque la valeur qu'il voit change. Dans ce cas, 1,1,1,2,1,1,1] renverrait [3,1,3]. Si vous vous attendiez à [6,1], assurez-vous simplement de trier les données avant d'utiliser groupby.
Evan

4
@CristianCiupitu: sum(1 for _ in group).
Martijn Pieters

6
Ce n'est pas une solution. La sortie ne dit pas ce qui a été compté.
buhtz

8
[(key, len(list(group))) for key, group in groupby(a)]ou {key: len(list(group)) for key, group in groupby(a)}@buhtz
Eric Pauley

532

Dans Python 2.7 (ou plus récent), vous pouvez utiliser collections.Counter:

import collections
a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
counter=collections.Counter(a)
print(counter)
# Counter({1: 4, 2: 4, 3: 2, 5: 2, 4: 1})
print(counter.values())
# [4, 4, 2, 1, 2]
print(counter.keys())
# [1, 2, 3, 4, 5]
print(counter.most_common(3))
# [(1, 4), (2, 4), (3, 2)]

Si vous utilisez Python 2.6 ou une version antérieure, vous pouvez le télécharger ici .


1
@unutbu: Et si j'ai trois listes, a, b, c pour lesquelles a et b restent les mêmes, mais c change? Comment compter la valeur de c pour laquelle a et c sont identiques?
ThePredator

@Srivatsan: Je ne comprends pas la situation. Veuillez poster une nouvelle question où vous pouvez élaborer.
unutbu

1
Existe-t-il un moyen d'extraire le dictionnaire {1: 4, 2: 4, 3: 2, 5: 2, 4: 1} de l'objet compteur?
Pavan

7
@Pavan: collections.Counterest une sous-classe de dict. Vous pouvez l'utiliser de la même manière qu'un dicton normal. Cependant, si vous voulez vraiment un dict, vous pouvez le convertir en dict dict(counter).
unutbu

1
Fonctionne également en 3.6, supposez donc tout ce qui est supérieur à 2,7
kpierce8

108

Python 2.7+ introduit la compréhension de dictionnaire. Construire le dictionnaire à partir de la liste vous permettra d'obtenir le décompte et de vous débarrasser des doublons.

>>> a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
>>> d = {x:a.count(x) for x in a}
>>> d
{1: 4, 2: 4, 3: 2, 4: 1, 5: 2}
>>> a, b = d.keys(), d.values()
>>> a
[1, 2, 3, 4, 5]
>>> b
[4, 4, 2, 1, 2]

Cela fonctionne très bien avec des listes de chaînes par opposition aux entiers comme la question d'origine posée.
Glen Selle

15
C'est plus rapide en utilisant un set:{x:a.count(x) for x in set(a)}
stenci

45
C'est extrêmement inefficace . a.count()effectue une traversée complète pour chaque élément a, ce qui en fait une approche quadradique O (N ^ 2). collections.Counter()est beaucoup plus efficace car il compte en temps linéaire (O (N)). En chiffres, cela signifie que cette approche exécutera 1 million d'étapes pour une liste de longueur 1000, contre seulement 1000 étapes avec Counter(), 10 ^ 12 étapes où seulement 10 ^ 6 sont nécessaires par Counter pour un million d'éléments dans une liste, etc.
Martijn Pieters

3
@stenci: bien sûr, mais l'horreur d'utiliser a.count()complètement éclipse l'efficacité d'avoir utilisé un ensemble là-bas.
Martijn Pieters

2
@MartijnPieters une raison de plus de l'utiliser moins de fois :)
stenci

48

Pour compter le nombre d'apparitions:

from collections import defaultdict

appearances = defaultdict(int)

for curr in a:
    appearances[curr] += 1

Pour supprimer les doublons:

a = set(a) 

1
+1 pour collections.defaultdict. En outre, dans python 3.x, recherchez les collections. C'est la même chose que collections.defaultdict (int).
hughdbrown

2
@hughdbrown, Counterpeut en fait utiliser plusieurs types numériques, y compris floatou Decimalpas seulement int.
Cristian Ciupitu

28

Dans Python 2.7+, vous pouvez utiliser des collections. Compteur pour compter les éléments

>>> a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
>>>
>>> from collections import Counter
>>> c=Counter(a)
>>>
>>> c.values()
[4, 4, 2, 1, 2]
>>>
>>> c.keys()
[1, 2, 3, 4, 5]

1
Le compteur est beaucoup plus lent que le dict par défaut, et le dict par défaut est beaucoup plus lent que l'utilisation manuelle d'un dict.
Jonathan Ray

@JonathanRay, plus maintenant, stackoverflow.com/a/27802189/1382487 .
wsaleem

25

Il est probablement préférable de compter la fréquence des éléments avec un dictionnaire:

b = {}
for item in a:
    b[item] = b.get(item, 0) + 1

Pour supprimer les doublons, utilisez un ensemble:

a = list(set(a))

3
@phkahler: Le mien ne serait qu'un tout petit peu mieux que ça. Cela ne vaut pas la peine que je poste une réponse distincte lorsque cela peut être amélioré avec un petit changement. Le but de SO est d'arriver aux meilleures réponses. Je pourrais simplement modifier cela, mais je préfère laisser à l'auteur d'origine la possibilité d'apporter ses propres améliorations.
S.Lott

1
@ S.Lott Le code est beaucoup plus propre sans avoir à importer defaultdict.
bstrauch24

Pourquoi ne pas preinitialize b: b = {k:0 for k in a}?
DylanYoung, le

20

Voici une autre alternative succint utilisant itertools.groupbyqui fonctionne également pour une entrée non ordonnée:

from itertools import groupby

items = [5, 1, 1, 2, 2, 1, 1, 2, 2, 3, 4, 3, 5]

results = {value: len(list(freq)) for value, freq in groupby(sorted(items))}

résultats

{1: 4, 2: 4, 3: 2, 4: 1, 5: 2}

16

Tu peux le faire:

import numpy as np
a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
np.unique(a, return_counts=True)

Production:

(array([1, 2, 3, 4, 5]), array([4, 4, 2, 1, 2], dtype=int64))

Le premier tableau est des valeurs et le second tableau est le nombre d'éléments avec ces valeurs.

Donc, si vous voulez obtenir simplement un tableau avec les nombres, vous devez utiliser ceci:

np.unique(a, return_counts=True)[1]

8
from collections import Counter
a=["E","D","C","G","B","A","B","F","D","D","C","A","G","A","C","B","F","C","B"]

counter=Counter(a)

kk=[list(counter.keys()),list(counter.values())]

pd.DataFrame(np.array(kk).T, columns=['Letter','Count'])

Bien que cet extrait de code puisse être la solution, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question des lecteurs à l'avenir, et que ces personnes ne connaissent peut-être pas les raisons de votre suggestion de code
Rahul Gupta

Oui le fera Rahul Gupta
Anirban Lahiri

7
seta = set(a)
b = [a.count(el) for el in seta]
a = list(seta) #Only if you really want it.

4
l'utilisation de listes countest ridiculement coûteuse et inutile dans ce scénario.
Idan K

@IdanK pourquoi compter coûte cher?
Kritika Rajain

@KritikaRajain Pour chaque élément unique de la liste, vous parcourez la liste entière pour générer un décompte (quadratique en nombre d'éléments uniques dans la liste). Au lieu de cela, vous pouvez parcourir la liste une fois et compter le nombre de chaque élément unique (linéaire dans la taille de la liste). Si votre liste ne contient qu'un seul élément unique, le résultat sera le même. De plus, cette approche nécessite un ensemble intermédiaire supplémentaire.
DylanYoung


4

Pour votre première question, parcourez la liste et utilisez un dictionnaire pour garder une trace de l'existence des éléments.

Pour votre deuxième question, utilisez simplement l'opérateur set.


4
Pouvez-vous développer la première réponse
Bruce

3

Cette réponse est plus explicite

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

d = {}
for item in a:
    if item in d:
        d[item] = d.get(item)+1
    else:
        d[item] = 1

for k,v in d.items():
    print(str(k)+':'+str(v))

# output
#1:4
#2:4
#3:3
#4:2

#remove dups
d = set(a)
print(d)
#{1, 2, 3, 4}

3
def frequencyDistribution(data):
    return {i: data.count(i) for i in data}   

print frequencyDistribution([1,2,3,4])

...

 {1: 1, 2: 1, 3: 1, 4: 1}   # originalNumber: count

3

Je suis assez en retard, mais cela fonctionnera aussi et aidera les autres:

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
freq_list = []
a_l = list(set(a))

for x in a_l:
    freq_list.append(a.count(x))


print 'Freq',freq_list
print 'number',a_l

va produire cela ..

Freq  [4, 4, 2, 1, 2]
number[1, 2, 3, 4, 5]

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

# 1. Get counts and store in another list
output = []
for i in set(a):
    output.append(a.count(i))
print(output)

# 2. Remove duplicates using set constructor
a = list(set(a))
print(a)
  1. La collection d'ensemble ne permet pas les doublons, passer une liste au constructeur set () donnera un itérable d'objets totalement uniques. La fonction count () renvoie un nombre entier lorsqu'un objet qui se trouve dans une liste est passé. Avec cela, les objets uniques sont comptés et chaque valeur de comptage est stockée en l'ajoutant à une sortie de liste vide
  2. Le constructeur list () est utilisé pour convertir l'ensemble (a) en liste et référencé par la même variable a

Production

D:\MLrec\venv\Scripts\python.exe D:/MLrec/listgroup.py
[4, 4, 2, 1, 2]
[1, 2, 3, 4, 5]

2

Solution simple à l'aide d'un dictionnaire.

def frequency(l):
     d = {}
     for i in l:
        if i in d.keys():
           d[i] += 1
        else:
           d[i] = 1

     for k, v in d.iteritems():
        if v ==max (d.values()):
           return k,d.keys()

print(frequency([10,10,10,10,20,20,20,20,40,40,50,50,30]))

max(d.values())ne changera pas dans la dernière boucle. Ne le calculez pas dans la boucle, calculez-le avant la boucle.
DylanYoung

1
#!usr/bin/python
def frq(words):
    freq = {}
    for w in words:
            if w in freq:
                    freq[w] = freq.get(w)+1
            else:
                    freq[w] =1
    return freq

fp = open("poem","r")
list = fp.read()
fp.close()
input = list.split()
print input
d = frq(input)
print "frequency of input\n: "
print d
fp1 = open("output.txt","w+")
for k,v in d.items():
fp1.write(str(k)+':'+str(v)+"\n")
fp1.close()

1
num=[3,2,3,5,5,3,7,6,4,6,7,2]
print ('\nelements are:\t',num)
count_dict={}
for elements in num:
    count_dict[elements]=num.count(elements)
print ('\nfrequency:\t',count_dict)

2
Veuillez ne pas publier de réponses uniquement en code, mais clarifiez votre code, surtout lorsqu'une question a déjà une réponse valide.
Erik A

1
from collections import OrderedDict
a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
def get_count(lists):
    dictionary = OrderedDict()
    for val in lists:
        dictionary.setdefault(val,[]).append(1)
    return [sum(val) for val in dictionary.values()]
print(get_count(a))
>>>[4, 4, 2, 1, 2]

Pour supprimer les doublons et maintenir l'ordre:

list(dict.fromkeys(get_count(a)))
>>>[4, 2, 1]

1

j'utilise Counter pour générer une fréquence. dicter des mots d'un fichier texte sur 1 ligne de code

def _fileIndex(fh):
''' create a dict using Counter of a
flat list of words (re.findall(re.compile(r"[a-zA-Z]+"), lines)) in (lines in file->for lines in fh)
'''
return Counter(
    [wrd.lower() for wrdList in
     [words for words in
      [re.findall(re.compile(r'[a-zA-Z]+'), lines) for lines in fh]]
     for wrd in wrdList])

1

Une autre approche pour ce faire, bien qu'en utilisant une bibliothèque plus lourde mais puissante - NLTK.

import nltk

fdist = nltk.FreqDist(a)
fdist.values()
fdist.most_common()

0

Encore une autre solution avec un autre algorithme sans utiliser de collections:

def countFreq(A):
   n=len(A)
   count=[0]*n                     # Create a new list initialized with '0'
   for i in range(n):
      count[A[i]]+= 1              # increase occurrence for value A[i]
   return [x for x in count if x]  # return non-zero count

0

Vous pouvez utiliser la fonction intégrée fournie en python

l.count(l[i])


  d=[]
  for i in range(len(l)):
        if l[i] not in d:
             d.append(l[i])
             print(l.count(l[i])

Le code ci-dessus supprime automatiquement les doublons dans une liste et imprime également la fréquence de chaque élément dans la liste d'origine et la liste sans doublons.

Deux oiseaux pour un coup! XD


0

Cette approche peut être essayée si vous ne voulez utiliser aucune bibliothèque et la garder simple et courte!

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
marked = []
b = [(a.count(i), marked.append(i))[0] for i in a if i not in marked]
print(b)

o / p

[4, 4, 2, 1, 2]

0

Pour mémoire, une réponse fonctionnelle:

>>> L = [1,1,1,1,2,2,2,2,3,3,4,5,5]
>>> import functools
>>> >>> functools.reduce(lambda acc, e: [v+(i==e) for i, v in enumerate(acc,1)] if e<=len(acc) else acc+[0 for _ in range(e-len(acc)-1)]+[1], L, [])
[4, 4, 2, 1, 2]

C'est plus propre si vous comptez aussi les zéros:

>>> functools.reduce(lambda acc, e: [v+(i==e) for i, v in enumerate(acc)] if e<len(acc) else acc+[0 for _ in range(e-len(acc))]+[1], L, [])
[0, 4, 4, 2, 1, 2]

Une explication:

  • nous commençons avec une accliste vide ;
  • si l'élément suivant ede Lest inférieur à la taille de acc, nous mettons simplement à jour cet élément: v+(i==e)signifie v+1si l'index ide accest l'élément courant e, sinon la valeur précédente v;
  • si l'élément suivant ede Lest supérieur ou égal à la taille de acc, nous devons développer accpour héberger le nouveau 1.

Les éléments n'ont pas besoin d'être triés ( itertools.groupby). Vous obtiendrez des résultats étranges si vous avez des nombres négatifs.


0

J'ai trouvé une autre façon de procéder en utilisant des ensembles.

#ar is the list of elements
#convert ar to set to get unique elements
sock_set = set(ar)

#create dictionary of frequency of socks
sock_dict = {}

for sock in sock_set:
    sock_dict[sock] = ar.count(sock)

0

Pour rechercher des éléments uniques dans la liste

a = [1,1,1,1,2,2,2,2,3,3,4,5,5]
a = list(set(a))

Pour trouver le nombre d'éléments uniques dans un tableau trié à l'aide du dictionnaire

def CountFrequency(my_list): 
# Creating an empty dictionary  
freq = {} 
for item in my_list: 
    if (item in freq): 
        freq[item] += 1
    else: 
        freq[item] = 1

for key, value in freq.items(): 
    print ("% d : % d"%(key, value))

# Driver function 
if __name__ == "__main__":  
my_list =[1, 1, 1, 5, 5, 3, 1, 3, 3, 1, 4, 4, 4, 2, 2, 2, 2] 

CountFrequency(my_list)

Référence GeeksforGeeks


-1

Une autre façon consiste à utiliser un dictionnaire et le list.count, ci-dessous une manière naïve de le faire.

dicio = dict()

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

b = list()

c = list()

for i in a:

   if i in dicio: continue 

   else:

      dicio[i] = a.count(i)

      b.append(a.count(i))

      c.append(i)

print (b)

print (c)

-1
a=[1,2,3,4,5,1,2,3]
b=[0,0,0,0,0,0,0]
for i in range(0,len(a)):
    b[a[i]]+=1
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.