Como contar a frequência dos elementos em uma lista não ordenada?


237

Preciso encontrar a frequência dos elementos em uma lista não ordenada

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

saída->

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

Também quero remover as duplicatas de um

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

Eles são sempre ordenados como nesse exemplo?
Farinha

@Peter. Sim, você classificou a lista para fins de postagem. A lista será sempre classificada?
precisa saber é o seguinte

2
Não, a lista nem sempre será classificada. Isso não é lição de casa.
Bruce

Estou tentando traçar o gráfico da distribuição de graus de uma rede.
Bruce Bruce

5
@ Peter: Por favor, atualize sua pergunta com as informações úteis. Não adicione comentários à sua pergunta - você é o proprietário da pergunta, pode corrigi-la para ser completa e clara.
precisa saber é o seguinte

Respostas:


147

Nota: Você deve classificar a lista antes de usar groupby.

Você pode usar groupbydo itertoolspacote se a lista for uma lista ordenada.

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)]

Resultado:

[4, 4, 2, 1, 2]

bom, usando groupby. Eu me pergunto sobre a sua eficiência vs. a abordagem dict, embora
Eli Bendersky

32
O python groupby cria novos grupos quando o valor que vê é alterado. Nesse caso, 1,1,1,2,1,1,1] retornaria [3,1,3]. Se você esperava [6,1], apenas certifique-se de classificar os dados antes de usar o groupby.
Evan

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

6
Esta não é uma solução. A saída não diz o que foi contado.
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

No Python 2.7 (ou mais recente), você pode usar 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)]

Se você estiver usando o Python 2.6 ou mais antigo, faça o download aqui .


1
@unutbu: E se eu tiver três listas, a, b, c para as quais aeb permanecem os mesmos, mas c muda? Como contar o valor de c para o qual a e c são iguais?
ThePredator

@Srivatsan: Eu não entendo a situação. Por favor, poste uma nova pergunta onde você pode elaborar.
Unutbu

1
Existe uma maneira de extrair o dicionário {1: 4, 2: 4, 3: 2, 5: 2, 4: 1} do objeto contador?
Pavan

7
@Pavan: collections.Counteré uma subclasse de dict. Você pode usá-lo da mesma maneira que faria com um ditado normal. Se você realmente quer um ditado, no entanto, você pode convertê-lo em um ditado usando dict(counter).
unutbu 22/03/2015

1
Obras em 3.6 também, por isso, assumir nada maior do que 2,7
kpierce8

108

O Python 2.7+ apresenta a Compreensão do Dicionário. Criar o dicionário a partir da lista fará com que você obtenha a contagem e se livre de duplicatas.

>>> 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]

Isso funciona muito bem com listas de strings em oposição a números inteiros, como a pergunta original.
Glen Selle

15
É mais rápido usando um conjunto:{x:a.count(x) for x in set(a)}
stenci 17/02

45
Isso é extremamente ineficiente . a.count()faz uma travessia completa para cada elemento a, tornando essa uma abordagem quadrática O (N ^ 2). collections.Counter()é muito mais eficiente porque conta em tempo linear (O (N)). Em números, isso significa que essa abordagem executará 1 milhão de etapas para uma lista de 1000, contra apenas 1000 etapas com Counter(), 10 ^ 12 etapas em que apenas 10 ^ 6 são necessárias pelo contador para um milhão de itens em uma lista etc.
Martijn Pieters

3
@stenci: claro, mas o horror de usar a.count()completamente diminui a eficiência de ter usado um conjunto lá.
Martijn Pieters

2
@MartijnPieters mais uma razão para usá-lo menos vezes :)
stenci

48

Para contar o número de aparências:

from collections import defaultdict

appearances = defaultdict(int)

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

Para remover duplicatas:

a = set(a) 

1
+1 para collections.defaultdict. Além disso, no python 3.x, procure collections.Counter. É o mesmo que collections.defaultdict (int).
precisa saber é o seguinte

2
@hughdbrown, na verdade, Counterpode usar vários tipos numéricos, incluindo floatou Decimalnão apenas int.
Cristian Ciupitu 29/07

28

No Python 2.7+, você pode usar coleções. Contador para contar itens

>>> 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
O contador é muito mais lento que o ditado padrão e o ditado padrão é muito mais lento que o uso manual de um ditado.
Jonathan Ray

@JonathanRay, não mais, stackoverflow.com/a/27802189/1382487 .
wsaleem

25

Contar a frequência dos elementos é provavelmente o melhor feito com um dicionário:

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

Para remover as duplicatas, use um conjunto:

a = list(set(a))

3
@phkahler: O meu seria apenas um pouquinho melhor do que isso. Não vale a pena postar uma resposta separada quando isso puder ser melhorado com uma pequena alteração. O objetivo do SO é obter as melhores respostas. Eu poderia simplesmente editar isso, mas prefiro permitir ao autor original a chance de fazer suas próprias melhorias.
precisa saber é o seguinte

1
@ S.Lott O código é muito mais limpo sem ter que importar defaultdict.
bstrauch24

Por que não pré-inicializar b b = {k:0 for k in a}:?
DylanYoung

20

Aqui está outra alternativa succint itertools.groupbyque também funciona para entrada não ordenada:

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))}

resultados

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

16

Você consegue fazer isso:

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

Resultado:

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

A primeira matriz é valores e a segunda matriz é o número de elementos com esses valores.

Portanto, se você deseja obter apenas uma matriz com os números, use este:

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

Embora esse snippet de código possa ser a solução, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se que você está respondendo a pergunta para os leitores no futuro, e essas pessoas podem não saber as razões para a sua sugestão de código
Rahul Gupta

Sim fará isso 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
o uso de listas counté ridiculamente caro e desnecessário nesse cenário.
Idan K

@IdanK por que contar é caro?
Kritika Rajain

@KritikaRajain Para cada elemento exclusivo da lista, você itera sobre a lista inteira para gerar uma contagem (quadrático no número de elementos exclusivos da lista). Em vez disso, você pode percorrer a lista uma vez e contar o número de cada elemento exclusivo (linear no tamanho da lista). Se sua lista tiver apenas um elemento exclusivo, o resultado será o mesmo. Além disso, essa abordagem requer um conjunto intermediário adicional.
DylanYoung


4

Para sua primeira pergunta, itere a lista e use um dicionário para acompanhar a existência de um elemento.

Para sua segunda pergunta, basta usar o operador set.


4
Você pode por favor elaborar sobre a primeira resposta
Bruce

3

Esta resposta é mais explícita

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

Estou muito atrasado, mas isso também funcionará e ajudará outros:

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

irá produzir isso ..

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. A coleção de conjuntos não permite duplicatas, passar uma lista para o construtor set () fornecerá uma iterabilidade de objetos totalmente exclusivos. A função count () retorna uma contagem inteira quando um objeto que está em uma lista é passado. Com isso, os objetos exclusivos são contados e cada valor de contagem é armazenado anexando a uma saída de lista vazia
  2. O construtor list () é usado para converter o conjunto (a) em lista e referido pela mesma variável a

Resultado

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

2

Solução simples usando um dicionário.

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())não será alterado no último loop. Não o calcule no loop, antes do loop.
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
Não poste respostas somente de código, mas esclareça seu código, especialmente quando uma pergunta já tiver uma resposta válida.
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]

Para remover duplicatas e manter ordem:

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

1

Estou usando o contador para gerar um freq. ditar palavras de arquivo de texto em 1 linha de código

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

Outra abordagem para fazer isso, embora usando uma biblioteca mais pesada, porém poderosa - o NLTK.

import nltk

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

0

Mais uma solução com outro algoritmo sem usar coleções:

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

Você pode usar a função interna fornecida em 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])

O código acima remove automaticamente duplicatas em uma lista e também imprime a frequência de cada elemento na lista original e na lista sem duplicatas.

Dois pássaros por um tiro! XD


0

Essa abordagem pode ser tentada se você não quiser usar nenhuma biblioteca e mantê-la simples e curta!

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

Para o registro, uma resposta funcional:

>>> 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]

É mais limpo se você contar zeros também:

>>> 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]

Uma explicação:

  • começamos com um vazio acc lista ;
  • se o próximo elemento ede Lfor menor que o tamanho de acc, basta atualizar esse elemento: v+(i==e)significa v+1se o índice ide accé o elemento atual e, caso contrário, o valor anterior v;
  • se o próximo elemento ede Lfor maior ou igual ao tamanho de acc, teremos que expandir accpara hospedar o novo 1.

Os elementos não precisam ser classificados ( itertools.groupby). Você obterá resultados estranhos se tiver números negativos.


0

Encontrou outra maneira de fazer isso, usando conjuntos.

#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

Para encontrar elementos exclusivos na lista

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

Para encontrar a contagem de elementos exclusivos em uma matriz classificada usando o dicionário

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)

Referência GeeksforGeeks


-1

Mais uma maneira é usar um dicionário e o list.count, abaixo de uma maneira ingênua de fazê-lo.

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.