2009-05-21 2 views
49

Я новичок в python, поэтому, возможно, мой вопрос очень нуб. Предположим, у меня есть список слов, и я хочу найти количество раз, когда каждое слово появляется в этом списке. Очевидный способ сделать это:значение частоты элементов в python

words = "apple banana apple strawberry banana lemon" 
uniques = set(words.split()) 
freqs = [(item, words.split.count(item)) for item in uniques] 
print(freqs) 

Но я нахожу этот код не очень хорошо, потому что таким образом программа работает через слова список дважды, один раз построить множество, и второй раз подсчета числа появлений. Конечно, я мог бы написать функцию для запуска списка и выполнить подсчет, но это было бы не так pythonic. Итак, есть ли более эффективный и питонический путь? (. Зацикливание по списку увеличивающимся правильный Dict ключ)

+0

Не в два раза, это выглядит как сложность O (N * N) – Drakosha

+0

@ Drakosha: Согласитесь, я тоже это видел. –

+1

Да, сложность O (n^2), но сам список запускается дважды. – Daniyar

ответ

89

defaultdict на помощь!

from collections import defaultdict 

words = "apple banana apple strawberry banana lemon" 

d = defaultdict(int) 
for word in words.split(): 
    d[word] += 1 

Это работает в O (n).

+7

+1, collections.defaultdict - один из моих любимых контейнеров! –

+1

Я бы сказал O (NlogN), если коллекция является деревом, или O (N) в среднем, если это хеш. – Drakosha

+7

dict - хэш. –

7

Если вы не хотите использовать стандартный метод словаря, вы можете попробовать это:

>>> from itertools import groupby 
>>> myList = words.split() # ['apple', 'banana', 'apple', 'strawberry', 'banana', 'lemon'] 
>>> [(k, len(list(g))) for k, g in groupby(sorted(myList))] 
[('apple', 2), ('banana', 2), ('lemon', 1), ('strawberry', 1)] 

Он работает в O (N журнал N) время.

11

Стандартный подход:

from collections import defaultdict 

words = "apple banana apple strawberry banana lemon" 
words = words.split() 
result = collections.defaultdict(int) 
for word in words: 
    result[word] += 1 

print result 

GroupBy Oneliner:

from itertools import groupby 

words = "apple banana apple strawberry banana lemon" 
words = words.split() 

result = dict((key, len(list(group))) for key, group in groupby(sorted(words))) 
print result 
+0

Есть ли разница в сложности? Использует ли groupby сортировку? Тогда, похоже, нужно время O (nlogn)? – Daniyar

+0

Упс, кажется, что Ник Преста ниже указал, что для подхода groupby используется O (nlogn). – Daniyar

118

Если вы используете питон 2,7 +/3,1 +, есть в модуле коллекции, которая является специально построенным для решения это Counter Class тип проблемы:

>>> from collections import Counter 
>>> words = "apple banana apple strawberry banana lemon" 
>>> freqs = Counter(words.split()) 
>>> print(freqs) 
Counter({'apple': 2, 'banana': 2, 'strawberry': 1, 'lemon': 1}) 
>>> 

Поскольку и 2.7, и 3.1 все еще находятся в стадии бета-тестирования, маловероятно, что вы используете его, поэтому просто имейте в виду, что стандартный способ выполнения такого рода работ скоро будет легко доступен.

+4

Ничего себе! Это питонический путь. Спасибо, что поделились этим. – Daniyar

+0

довольно круто! * Возвращается к Python 2.5 :(* – Triptych

+0

Это также в python 2.7. – nosklo

3

Без defaultdict:

words = "apple banana apple strawberry banana lemon" 
my_count = {} 
for word in words.split(): 
    try: my_count[word] += 1 
    except KeyError: my_count[word] = 1 
+0

Похоже, медленнее, чем defaultdict в моих тестах. – nosklo

+0

Расщепление по пробелу является избыточным. Кроме того, вы должны использовать метод dict.set_default вместо try/except. – Triptych

+2

Это намного медленнее, потому что вы используете Исключения. Исключения очень дорогостоящие практически на любом языке Избегайте использования их для логических ветвей. Посмотрите на мое решение практически для того же метода, но без нас Исключения: http://stackoverflow.com/questions/893417/item-frequency-count-in-python/983434#983434 – hopla

7
freqs = {} 
for word in words: 
    freqs[word] = freqs.get(word, 0) + 1 # fetch and increment OR initialize 

Я думаю, что это приводит к тому же, как решение триптиха, но без импорта коллекции. Также немного похоже на решение Selinap, но более читаемое имхо. Почти идентичен решению Томаса Вейгеля, но без использования Исключений.

Это может быть медленнее, чем использование defaultdict() из библиотеки коллекций. Поскольку значение извлекается, увеличивается, а затем назначается снова. Вместо того, чтобы просто увеличивать. Однако использование + = может сделать то же самое внутренне.

+0

Nice. Я нашел это же решение здесь: http://openbookproject.net/thinkcs/python/english3e/dictionaries.html#counting-letters. –

+0

Прохладный, следует ли просить об атрибуции? : p;) – hopla

0

Не можете ли вы использовать счет?

words = 'the quick brown fox jumps over the lazy gray dog' 
words.count('z') 
#output: 1 
+1

Вопрос уже использует «счет» и запрашивает лучшие альтернативы. – Daniyar

0

Ответ ниже имеет некоторые дополнительные циклы, но это еще один метод

def func(tup): 
    return tup[-1] 


def print_words(filename): 
    f = open("small.txt",'r') 
    whole_content = (f.read()).lower() 
    print whole_content 
    list_content = whole_content.split() 
    dict = {} 
    for one_word in list_content: 
     dict[one_word] = 0 
    for one_word in list_content: 
     dict[one_word] += 1 
    print dict.items() 
    print sorted(dict.items(),key=func) 
0

мне довелось работать на какой-то искры упражнения, вот мое решение.

tokens = ['quick', 'brown', 'fox', 'jumps', 'lazy', 'dog'] 

print {n: float(tokens.count(n))/float(len(tokens)) for n in tokens} 

** # выход выше **

{'brown': 0.16666666666666666, 'lazy': 0.16666666666666666, 'jumps': 0.16666666666666666, 'fox': 0.16666666666666666, 'dog': 0.16666666666666666, 'quick': 0.16666666666666666} 
0

Использование уменьшения(), чтобы преобразовать список в один Dict.

words = "apple banana apple strawberry banana lemon" 
reduce(lambda d, c: d.update([(c, d.get(c,0)+1)]) or d, words.split(), {}) 

возвращает

{'strawberry': 1, 'lemon': 1, 'apple': 2, 'banana': 2} 
0
words = "apple banana apple strawberry banana lemon" 
w=words.split() 
e=list(set(w))  
for i in e: 
    print(w.count(i)) #Prints frequency of every word in the list 

Надеется, что это помогает!

Смежные вопросы