Sırasız bir listedeki öğelerin sıklığı nasıl hesaplanır?


237

Sıralanmamış bir listedeki öğelerin sıklığını bulmam gerekiyor

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

output->

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

Ayrıca kopyaları bir

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

Her zaman bu örnekteki gibi sıralanıyorlar mı?
Farinha

@Peter. Evet, listeyi yayınlama amacıyla sıraladınız. Liste her zaman sıralanacak mı?
S.Lott

2
Hayır, liste her zaman sıralanmayacaktır. Bu ev ödevi değil.
Bruce

Bir ağın derece dağılım grafiğini çizmeye çalışıyorum.
Bruce

5
@Peter: Lütfen sorunuzu faydalı bilgilerle güncelleyin. Lütfen sorunuza yorum eklemeyin - sorunun sahibi sizsiniz, tam ve anlaşılır olmasını düzeltebilirsiniz.
S.Lott

Yanıtlar:


147

Not: Kullanmadan önce listeyi sıralamanız gerekir groupby.

Sen kullanabilirsiniz groupbygelen itertoolsliste sıralı liste ise paketin.

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

Çıktı:

[4, 4, 2, 1, 2]

güzel, kullanarak groupby. Verimlilik yaklaşımı karşısında dict yaklaşımı merak ediyorum
Eli Bendersky

32
Python groupby, gördüğü değer değiştiğinde yeni gruplar oluşturur. Bu durumda 1,1,1,2,1,1,1] geri dönecektir [3,1,3]. [6,1] bekleniyorsa groupby'yi kullanmadan önce verileri sıraladığınızdan emin olun.
Evan

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

6
Bu bir çözüm değil. Çıktı neyin sayıldığını söylemiyor.
buhtz

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

532

Python 2.7'de (veya daha yenisinde) şunları kullanabilirsiniz 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)]

Python 2.6 veya daha eski kullanıyorsanız, bunu indirebilirsiniz burada .


1
@unutbu: Ya a ve b'nin aynı kaldığı, ancak c'nin değiştiği üç listem varsa, a, b, c? A ve c'nin aynı olduğu c'nin değeri nasıl hesaplanır?
ThePredator

@Srivatsan: Durumu anlamıyorum. Lütfen ayrıntılı olarak açıklayabileceğiniz yeni bir soru gönderin.
unutbu

1
{1: 4, 2: 4, 3: 2, 5: 2, 4: 1} sözlüğünü sayaç nesnesinden çıkarmanın bir yolu var mı?
Pavan

7
@Pavan: collections.Counterbir alt sınıfıdır dict. Normal bir dikte gibi kullanabilirsiniz. Eğer gerçekten bir diksiyon istiyorsanız, bunu kullanarak bir diksiyona dönüştürebilirsiniz dict(counter).
unutbu

1
3.6 da çalışır, bu yüzden 2.7'den daha büyük bir şey varsayalım
kpierce8

108

Python 2.7+, Sözlük Anlama'yı sunar. Sözlüğü listeden oluşturmak, sayımın yanı sıra kopyalardan kurtulmanızı sağlar.

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

Bu, sorulan orijinal soru gibi tamsayıların aksine dizelerin listelerinde gerçekten iyi çalışır.
Glen Selle

15
Bir set kullanarak daha hızlı:{x:a.count(x) for x in set(a)}
stenci

45
Bu son derece verimsiz . her eleman için tam bir geçişa.count() yapar , bu da O (N ^ 2) kuadradik bir yaklaşım haline getirir. lineer zamanda (O (N)) sayıldığı için çok daha verimlidir . Sayılar, demek bu yaklaşım vs, uzunluğu 1000 bir listesi için 1.000.000 adımları çalıştırır sadece 1000 adım ile , sadece 10 ^ 6 vs. listesinde bir milyon öğeler için Sayacı tarafından ihtiyaç duyulan 10 ^ 12 adımacollections.Counter()Counter()
Martijn Pieters

3
@stenci: tabii, ama kullanmanın dehşeti a.count()orada bir set kullanmanın verimliliğini tamamen gölgede bırakıyor .
Martijn Pieters

2
@MartijnPieters daha az kullanmak için bir neden daha :)
stenci

48

Görünüş sayısını saymak için:

from collections import defaultdict

appearances = defaultdict(int)

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

Kopyaları kaldırmak için:

a = set(a) 

1
Koleksiyonlar için +1. Hata bildirimi. Ayrıca, python 3.x'te koleksiyonları arayın. Collections.defaultdict (int) ile aynıdır.
hughdbrown

2
@hughdbrown, aslında Counterbirden fazla sayısal türleri de dahil olmak üzere kullanabilir floatveya Decimalsadece, int.
Cristian Ciupitu

28

Python 2.7+, sen kullanabilirsiniz collections.Counter öğeleri saymak

>>> 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
Sayaç, varsayılan diksenden çok daha yavaştır ve varsayılan diks, bir diktenin manuel kullanımından çok daha yavaştır.
Jonathan Ray

@JonathanRay, artık değil, stackoverflow.com/a/27802189/1382487 .
wsaleem

25

Elemanların sıklığını saymak muhtemelen en iyi sözlükle yapılır:

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

Kopyaları kaldırmak için bir küme kullanın:

a = list(set(a))

3
@phkahler: Benimki bundan biraz daha iyi olurdu. Bu, küçük bir değişiklikle iyileştirilebildiğinde ayrı bir cevap göndermeme değmez. SO'nun amacı en iyi cevaplara ulaşmaktır. Bunu basitçe düzenleyebilirim, ancak orijinal yazara kendi geliştirmelerini yapma şansı vermeyi tercih ederim.
S.Lott

1
@ S.Lott Kod, içe aktarmak zorunda kalmadan çok daha temiz defaultdict.
bstrauch24

Neden b: 'yi önceden başlatmıyorsunuz b = {k:0 for k in a}?
DylanYoung

20

itertools.groupbySırasız girdi için de çalışan başka bir kısa alternatif :

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

Sonuçlar

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

16

Bunu yapabilirsiniz:

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

Çıktı:

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

İlk dizi değerlerdir ve ikinci dizi bu değerlere sahip öğe sayısıdır.

Yani sadece sayılarla dizi almak istiyorsanız bunu kullanmalısınız:

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

Bu kod snippet'i çözüm olsa da, bir açıklama da dahil olmak üzere mesajınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı unutmayın ve bu insanlar kod önerinizin nedenlerini bilmiyor olabilir
Rahul Gupta

Evet şunu yapacağım 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
listelerin countkullanılması gülünç derecede pahalıdır ve bu senaryoda bilinmemektedir.
Idan K

@IdanK neden sayım pahalı?
Kritika Rajain

@KritikaRajain Listedeki her benzersiz öğe için, bir sayım oluşturmak üzere tüm listeyi yinelersiniz (listedeki benzersiz öğelerin sayısında ikinci dereceden). Bunun yerine, listeyi bir kez yineleyebilir ve her bir benzersiz öğenin sayısını sayabilirsiniz (listenin boyutunda doğrusal). Listenizde yalnızca bir benzersiz öğe varsa, sonuç aynı olur. Ayrıca, bu yaklaşım ek bir ara küme gerektirir.
DylanYoung


4

İlk sorunuz için, listeyi tekrarlayın ve bir öğenin varlığını takip etmek için bir sözlük kullanın.

İkinci sorunuz için sadece set operatörünü kullanın.


4
İlk cevabı biraz açıklayabilir misiniz
Bruce

3

Bu cevap daha açık

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

Oldukça geç kaldım, ama bu da işe yarayacak ve başkalarına yardımcı olacak:

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

bunu üretecek ..

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. Set koleksiyonu yinelemelere izin vermez, set () yapıcısına bir liste iletmek, tamamen benzersiz nesnelerin yinelenmesini sağlar. count () işlevi, listedeki bir nesne iletildiğinde bir tamsayı sayısı döndürür. Böylece benzersiz nesneler sayılır ve her sayım değeri boş bir liste çıktısına eklenerek saklanır
  2. list () yapıcısı set (a) 'yı listeye dönüştürmek ve aynı değişken a

Çıktı

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

2

Bir sözlük kullanarak basit bir çözüm.

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())son döngüde değişmez. Döngüde hesaplamayın, döngüden önce hesaplayın .
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
Lütfen yalnızca kod yanıtları yayınlamayın, özellikle de bir sorunun zaten geçerli bir cevabı varsa kodunuzu netleştirin.
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]

Yinelenenleri kaldırmak ve siparişi korumak için:

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

1

Sayaç bir frekans oluşturmak için kullanıyorum. 1 satır koddaki metin dosyası kelimelerinden alıntı

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

Bunu yapmak için başka bir yaklaşım da, daha ağır ama güçlü bir kütüphane kullanarak - NLTK.

import nltk

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

0

Koleksiyon kullanmadan başka bir algoritmaya sahip başka bir çözüm:

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

Python'da sağlanan yerleşik işlevi kullanabilirsiniz

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

Yukarıdaki kod, bir listedeki yinelemeleri otomatik olarak kaldırır ve ayrıca orijinal listedeki her bir öğenin ve yinelemesiz listenin sıklığını yazdırır.

Bir atış için iki kuş! XD


0

Herhangi bir kütüphane kullanmak ve basit ve kısa tutmak istemiyorsanız bu yaklaşım denenebilir!

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

Kayıt için işlevsel bir cevap:

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

Sıfırları da sayarsanız daha temiz:

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

Bir açıklama:

  • boş bir acclisteyle başlıyoruz ;
  • Bir sonraki eleman eğer ebir Lboyutundan daha düşüktür acc, biz sadece bu eleman güncelleyin: v+(i==e)araçları v+1endeksi ise ibir accakım unsurudur e, aksi önceki değeri v;
  • Bir sonraki eleman eğer ebir Lbüyüktür ya büyüklüğüne eşittir acc, biz genişletmek zorunda accyeni barındırması 1.

Öğelerin sıralanması ( itertools.groupby) gerekmez . Negatif sayılarınız varsa tuhaf sonuçlar alırsınız.


0

Setleri kullanarak bunu yapmanın başka bir yolunu buldum.

#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

Listedeki benzersiz öğeleri bulmak için

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

Sözlük kullanarak sıralanmış bir dizideki benzersiz öğelerin sayısını bulmak için

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)

Referans GeeksforGeeks


-1

Bir başka yol da bir sözlük ve list.count, bunu yapmak için naif bir yol kullanmaktır.

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.