2015-10-08 1 views
15

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

Весь список содержит только уникальные слова. Моя цель - подсчитать количество каждого слова в полном документе. Я могу сделать это успешно, используя код ниже:

for x in texts_list: 
    for l in x: 
     if l in term_appearance: 
      term_appearance[l] += 1 
     else: 
      term_appearance[l] = 1 

Но я хочу использовать словарь понимание, чтобы сделать то же самое. Это первый раз, когда я пытаюсь писать словарь понимание и использование ранее существующих постов в StackOverflow, я смог написать следующее:

from collections import defaultdict 
term_appearance = defaultdict(int) 

{{term_appearance[l] : term_appearance[l] + 1 if l else term_appearance[l] : 1 for l in x} for x in texts_list} 

Предыдущая запись для справки:

Simple syntax error in Python if else dict comprehension

Как говорился в посте выше, я также использовал следующий код:

{{l : term_appearance[l] + 1 if l else 1 for l in x} for x in texts_list} 

Приведенных выше код был успешным в пре oducing пустых списков, но в конечном счете бросил следующее отслеживающее:

[] 

[] 

[] 

[] 

Traceback (most recent call last): 

    File "term_count_fltr.py", line 28, in <module> 

    {{l : term_appearance[l] + 1 if l else 1 for l in x} for x in texts_list} 
    File "term_count_fltr.py", line 28, in <setcomp> 

    {{l : term_appearance[l] + 1 if l else 1 for l in x} for x in texts_list} 

TypeError: unhashable type: 'dict' 

Любой помощь в улучшении моего нынешнего понимания будет высоко ценится.

Глядя на выше ошибки, я также попытался

[{l : term_appearance[l] + 1 if l else 1 for l in x} for x in texts_list] 

Это выбежала без каких-либо ошибок, но выход был только пустые списки.

+0

Успехов ... Вот мысль, по умолчанию ДИКТ будет по умолчанию равно нулю, что означает, что вы, возможно, не потребуется, если, еще часть , – nehemiah

ответ

12

Как объяснено в других ответах, проблема в том, что понимание словаря создает новый словарь, поэтому вы не получите ссылку на этот новый словарь до тех пор, пока он не будет создан. Вы не можете делать словарное понимание того, что делаете.

Учитывая то, что вы делаете, пытается повторно реализовать то, что уже сделано collections.Counter. Вы можете просто использовать Counter.Пример -

from collections import Counter 
term_appearance = Counter() 
for x in texts_list: 
    term_appearance.update(x) 

Demo -

>>> l = [[1,2,3],[2,3,1],[5,4,2],[1,1,3]] 
>>> from collections import Counter 
>>> term_appearance = Counter() 
>>> for x in l: 
...  term_appearance.update(x) 
... 
>>> term_appearance 
Counter({1: 4, 2: 3, 3: 3, 4: 1, 5: 1}) 

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

from collections import Counter 
term_appearance = Counter() 
[term_appearance.update(x) for x in texts_list] 

Демо -

>>> l = [[1,2,3],[2,3,1],[5,4,2],[1,1,3]] 
>>> from collections import Counter 
>>> term_appearance = Counter() 
>>> [term_appearance.update(x) for x in l] 
[None, None, None, None] 
>>> term_appearance 
Counter({1: 4, 2: 3, 3: 3, 4: 1, 5: 1}) 

Выход [None, None, None, None] является fr om понимание списка, в результате чего этот список (потому что это было запущено в интерактивном режиме), если вы запустили это в скрипте как python <script>, этот вывод будет просто отброшен.


Вы также можете использовать itertools.chain.from_iterable() создать уплощенный список из ваших text_lists, а затем использовать его для счетчика. Пример:

from collections import Counter 
from itertools import chain 
term_appearance = Counter(chain.from_iterable(texts_list)) 

Demo -

>>> from collections import Counter 
>>> from itertools import chain 
>>> term_appearance = Counter(chain.from_iterable(l)) 
>>> term_appearance 
Counter({1: 4, 2: 3, 3: 3, 4: 1, 5: 1}) 

Кроме того, еще один вопрос, в исходном коде в строке -

{{term_appearance[l] : term_appearance[l] + 1 if l else term_appearance[l] : 1 for l in x} for x in texts_list} 

На самом деле это набор понимание со словарем понимания вложенными внутри.

Именно по этой причине вы получаете сообщение об ошибке - TypeError: unhashable type: 'dict'. Поскольку после первого запуска понимания словаря и создания dict, он пытается добавить это в set. Но словари не хешируются, следовательно, ошибка.

6

Причина, по которой вы получаете сообщение об отключенной типе, заключается в том, что вы не можете использовать словарь в качестве ключа для другого словаря в Python, поскольку они являются изменяемыми контейнерами.

См: why dict objects are unhashable in python?

3

словарь постижений в Python 2.7+ не работает так, как вы можете думать, что они работают.

Как списочные, они создают новый словарь, но вы не можете использовать их, чтобы добавить ключи к ужесуществующего словаря (который в данном случае является то, что вы пытаетесь сделать).

3

Пожалуйста, просмотрите answer по Anand S Kumar, если вы хотите использовать collections.Counter, что является отличным предложением. Однако есть и другое решение связано с использованием collections.defaultdict, которые я считаю стоит упомянуть:

from collections import defaultdict 

text_appearances = defaultdict() 

for x in texts_lists: 
    for l in x: 
     text_appearances[l] += 1 

Я использовал эту конструкцию несколько раз, и я думаю, что это чистый и приятный способ сделать подсчет. Особенно, если вам по какой-то причине необходимо выполнить некоторую проверку между циклами, это эффективный способ непосредственного обновления счетчика, не беспокоясь о том, существует ли ключ/слово в вашем словаре (например, в вашем первом решении).

Sidenote по переменному именованию: Пожалуйста, не используйте строчную l (строчные L) в качестве имени переменного, то трудно отличить от 1 (номер один). В вашем случае, возможно, вы могли бы назвать переменные, words и word? С добавлением не используя _list как постфикс код мог читать:

for words in texts: 
    for word in words: 
     text_appearance[word] += 1