Как посчитать частоту элементов в неупорядоченном списке?


237

Мне нужно найти частоту элементов в неупорядоченном списке

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

output->

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

Также я хочу удалить дубликаты из

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

Они всегда заказаны как в этом примере?
Фаринья

@Питер. Да, вы отсортировали список для публикации. Будет ли список всегда сортироваться?
С.Лотт

2
Нет, список не будет отсортирован всегда. Это не домашняя работа.
Брюс

Я пытаюсь построить график распределения степени сети.
Брюс

5
@Peter: Пожалуйста, обновите ваш вопрос с полезной информацией. Пожалуйста, не добавляйте комментарии к своему вопросу - вы являетесь владельцем вопроса, вы можете исправить его, чтобы он был полным и понятным.
С.Лотт

Ответы:


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 groupby создает новые группы, когда значение, которое он видит, изменяется. В этом случае 1,1,1,2,1,1,1] вернется [3,1,3]. Если вы ожидали [6,1], то просто убедитесь, что отсортировали данные перед использованием groupby.
Эван

4
@CristianCiupitu: sum(1 for _ in group).
Мартин Питерс

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

@ Шриватсан: я не понимаю ситуацию. Пожалуйста, разместите новый вопрос, где вы можете уточнить.
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 для миллиона элементов в списке и т. Д.
Мартейн Питерс

3
@stenci: конечно, но ужас от использования a.count()полностью снижает эффективность использования набора.
Мартин Питерс

2
@MartijnPieters еще одна причина, чтобы использовать его меньше раз :)
stenci

48

Для подсчета количества появлений:

from collections import defaultdict

appearances = defaultdict(int)

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

Чтобы удалить дубликаты:

a = set(a) 

1
+1 для коллекций. Кроме того, в python 3.x ищите коллекции. Counter. Это то же самое, что collection.defaultdict (int).
hughdbrown

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

28

В Python 2.7+ вы можете использовать коллекции. Счетчик для подсчета предметов

>>> 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: Мой будет только чуть-чуть лучше, чем этот. Вряд ли стоит публиковать отдельный ответ, когда его можно улучшить с небольшими изменениями. Смысл SO в том, чтобы найти лучшие ответы. Я мог бы просто отредактировать это, но я предпочитаю дать первоначальному автору шанс внести свои собственные улучшения.
С.Лотт

1
@ S.Lott Код намного чище без необходимости импорта defaultdict.
bstrauch24

Почему не preinitialize б: b = {k:0 for k in a}?
DylanYoung

20

Вот еще одна альтернатива succint, 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 почему считать дорого?
Критика Раджайн

@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
Пожалуйста, не публикуйте ответы только для кода, а уточняйте код, особенно если на вопрос уже есть действительный ответ.
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]

Чтобы удалить дубликаты и сохранить порядок:

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

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.