Як порахувати частоту елементів у невпорядкованому списку?


237

Мені потрібно знайти частоту елементів у невпорядкованому списку

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

вихід->

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

Також я хочу видалити дублікати з

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

Чи завжди вони замовлені, як у тому прикладі?
Фарінья

@Peter. Так, ви відсортували список для опублікування. Чи завжди список буде відсортований?
S.Lott

2
Ні, список не буде сортований завжди. Це не домашнє завдання.
Брюс

Я намагаюся побудувати графік розподілу градусів мережі.
Брюс

5
@Peter: Будь ласка, оновіть своє запитання корисною інформацією. Будь ласка, не додайте коментарів до свого запитання - у вас є питання, ви можете виправити його як повне та зрозуміле.
S.Lott

Відповіді:


147

Примітка. Ви повинні сортувати список перед використанням groupby.

Ви можете використовувати groupbyз itertoolsпакету, якщо список є упорядкованим списком.

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

Вихід:

[4, 4, 2, 1, 2]

приємно, використовуючи groupby. Мене цікавить його ефективність та диктичний підхід, хоча
Елі Бендерський

32
Група python створює нові групи, коли значення, яке вона бачить, змінюється. У цьому випадку 1,1,1,2,1,1,1] повернеться [3,1,3]. Якщо ви очікували [6,1], тоді обов'язково відсортуйте дані перед використанням groupby.
Еван

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

6
Це не рішення. Результат не вказує, що було підраховано.
buhtz

8
[(key, len(list(group))) for key, group in groupby(a)]або {key: len(list(group)) for key, group in groupby(a)}@buhtz
Ерік

532

У Python 2.7 (або новіших версіях) ви можете використовувати 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 або новіші, ви можете завантажити його тут .


1
@unutbu: Що робити, якщо у мене є три списки, a, b, c, для яких a і b залишаються однаковими, але c змінюється? Як порахувати значення c, для яких a і c однакові?
ThePredator

@Srivatsan: Я не розумію ситуації. Будь ласка, опублікуйте нове запитання, де ви можете детально розглянути.
unutbu

1
Чи є спосіб вилучити словник {1: 4, 2: 4, 3: 2, 5: 2, 4: 1} з лічильника?
Паван

7
@Pavan: collections.Counterє підкласом dict. Ви можете використовувати його так само, як і звичайний дикт. Якщо ви дійсно хочете дикту, однак, ви можете перетворити його на дикт, використовуючи dict(counter).
unutbu

1
Працює в 3.6 також, тож припустимо що-небудь більше 2,7
kpierce8

108

Python 2.7+ впроваджує розуміння словника. Створення словника зі списку дозволить вам підрахувати, а також позбутися дублікатів.

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

Це дуже добре працює зі списками рядків на відміну від цілих чисел, як оригінальне запитання.
Глен Селле

15
Це швидше за допомогою набору:{x:a.count(x) for x in set(a)}
stenci

45
Це надзвичайно неефективно . a.count()робить повний обхід кожного елемента a, роблячи це квадратичним підходом O (N ^ 2). collections.Counter()є набагато більш ефективним , оскільки він розраховує лінійний час (O (N)). У числах це означає, що цей підхід виконає 1 мільйон кроків для списку довжиною 1000, проти всього 1000 кроків з Counter(), 10 ^ 12 кроків, коли лише 10 ^ 6 потрібно Counter для мільйона елементів у списку тощо.
Martijn Pieters

3
@ stenci: впевнений, але жах використання a.count()повністю карликів в ефективності використання набору там.
Martijn Pieters

2
@MartijnPieters - ще одна причина використовувати його менше разів :)
stenci

48

Щоб підрахувати кількість виступів:

from collections import defaultdict

appearances = defaultdict(int)

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

Щоб видалити дублікати:

a = set(a) 

1
+1 для collection.defaultdict. Також у python 3.x шукайте колекції.Counter. Це те саме, що і collection.defaultdict (int).
hughdbrown

2
@hughdbrown, насправді Counterможе використовувати кілька числових типів, включаючи floatабо Decimal, не тільки int.
Крістіан Цюпіту

28

У Python 2.7+ ви можете використовувати collection.Counter для підрахунку елементів

>>> 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
Лічильник набагато повільніше, ніж дікт за замовчуванням, а дикт за замовчуванням набагато повільніше, ніж використання диктату вручну.
Джонатан Рей

@JonathanRay, вже не, stackoverflow.com/a/27802189/1382487 .
wsaleem

25

Підрахунок частоти елементів, мабуть, найкраще зробити зі словником:

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

Щоб видалити дублікати, використовуйте набір:

a = list(set(a))

3
@phkahler: Моя була б лише крихітною кращою, ніж ця. Навряд чи варто надсилати окрему відповідь, коли це можна покращити невеликою зміною. Сенс ТА полягає в тому, щоб отримати найкращі відповіді. Я міг би просто відредагувати це, але я вважаю за краще дозволити оригінальному автору можливість зробити власні вдосконалення.
S.Lott

1
@ S.Lott Код набагато чистіший, без імпорту defaultdict.
bstrauch24

Чому б не попередньо ініціалізувати b b = {k:0 for k in a}:?
DylanYoung

20

Ось ще одна альтернатива використання, itertools.groupbyяка також працює для невпорядкованого введення:

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

результати

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

16

Ви можете зробити це:

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

Вихід:

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

Перший масив - це значення, а другий масив - кількість елементів з цими значеннями.

Отже, якщо ви хочете отримати просто масив з числами, вам слід скористатися цим:

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

Хоча цей фрагмент коду може бути вирішенням, включаючи пояснення, справді допомагає покращити якість вашої публікації. Пам’ятайте, що ви відповідаєте на запитання читачів у майбутньому, і ці люди можуть не знати причини вашої пропозиції коду
Рахул Гупта

Так, зроблять це Рахул Гупта
Анірбан Лахірі

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

4
використання списків countє смішно дорогим і не вимагається в цьому сценарії.
Ідан К

@IdanK чому рахувати дорого?
Kritika Rajain

@KritikaRajain Для кожного унікального елемента у списку ви повторюєте весь список, щоб створити підрахунок (квадратична кількість унікальних елементів у списку). Натомість ви можете повторити перелік списку один раз і підрахувати кількість кожного унікального елемента (лінійний за розміром списку). Якщо у вашому списку є лише один унікальний елемент, результат буде однаковим. Більше того, такий підхід вимагає додаткового проміжного набору.
DylanYoung


4

Для вашого першого питання перегляньте список і використовуйте словник, щоб відстежувати наявність елементів.

Для вашого другого питання просто скористайтеся оператором set.


4
Чи можете ви, будь ласка, детальніше зупинитися на першій відповіді
Брюс

3

Ця відповідь більш чітка

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

Я запізнююсь, але це теж спрацює, і я допоможу іншим:

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

буде виробляти це ..

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 () дасть ітерабельність абсолютно унікальних об'єктів. count () функція повертає ціле число, коли об'єкт, який знаходиться у списку, передається. При цьому обчислюються унікальні об'єкти, і кожне значення підрахунку зберігається шляхом додавання до виходу порожнього списку
  2. конструктор list () використовується для перетворення множини (a) у список і посилається на ту саму змінну a

Вихідні дані

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

2

Просте рішення за допомогою словника.

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())не зміниться в останньому циклі. Не обчислюйте його в циклі, обчислюйте його перед циклом.
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
Будь ласка, не публікуйте відповіді, що стосуються лише коду, але уточнюйте свій код, особливо коли запитання вже має дійсну відповідь.
Ерік А

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]

Щоб видалити дублікати та підтримувати порядок:

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

1

Я використовую Counter для створення частоти. dict з текстового файлу слова в 1 рядку коду

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

Інший підхід зробити це, хоча і за допомогою більш важкої, але потужної бібліотеки - NLTK.

import nltk

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

0

Ще одне рішення з іншим алгоритмом без використання колекцій:

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

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

Вищевказаний код автоматично видаляє дублікати зі списку, а також друкує частоту кожного елемента в оригінальному списку та списку без дублікатів.

Дві птахи за один постріл! XD


0

Цей підхід можна спробувати, якщо ви не хочете користуватися будь-якою бібліотекою, а зберігати її просто та коротко!

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)

о / п

[4, 4, 2, 1, 2]

0

Для запису функціональна відповідь:

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

Чистіше, якщо ви також порахуєте нулі:

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

Пояснення:

  • ми починаємо з порожнього accсписку;
  • якщо наступний елемент eз Lнижче , ніж розмір acc, ми просто оновити цей елемент: v+(i==e)кошти , v+1якщо індекс iв accце поточний елемент e, в іншому випадку попереднє значення v;
  • якщо наступний елемент eвеличини Lбільший або дорівнює розміру acc, ми повинні розгорнути, accщоб розмістити новий 1.

Елементи не потрібно сортувати ( itertools.groupby). Ви отримаєте дивні результати, якщо будете мати від’ємні цифри.


0

Знайшов інший спосіб зробити це, використовуючи набори.

#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

Щоб знайти унікальні елементи у списку

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

Щоб знайти кількість унікальних елементів у відсортованому масиві за допомогою словника

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)

Довідкові GeeksforGeeks


-1

Ще одним способом є використання словника та list.count, нижче наївного способу зробити це.

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)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.