Как я могу подсчитать появление каждого слова в документе, используя понимание словаря
У меня есть список списков в 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}
Предыдущее сообщение для справки:
Простая синтаксическая ошибка в Python, если в противном случае понимается dict
Как было сказано выше, я также использовал следующий код:
{{l : term_appearance[l] + 1 if l else 1 for l in x} for x in texts_list}
Вышеприведенный код был успешным при создании пустых списков, но в итоге бросил следующую трассировку:
[]
[]
[]
[]
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]
Это выполнялось без какой-либо ошибки, но вывод был пустым списком.
Ответы
Ответ 1
Как объяснено в других ответах, проблема в том, что понимание словаря создает новый словарь, поэтому вы не получите ссылку на этот новый словарь до тех пор, пока он не будет создан. Вы не можете делать понимание словаря за то, что вы делаете.
Учитывая то, что вы делаете, это попытка повторной реализации того, что уже сделано collections.Counter
. Вы можете просто использовать Counter
. Пример -
from collections import Counter
term_appearance = Counter()
for x in texts_list:
term_appearance.update(x)
Демо -
>>> 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]
происходит из понимания списка, приводящего к этому списку (поскольку это было запущено в интерактивном режиме), если вы запустите его в script как python <script>
, этот вывод будет просто отброшен.
Вы также можете использовать itertools.chain.from_iterable()
, чтобы создать сплющенный список из ваших текстовых списков, а затем использовать для Counter. Пример:
from collections import Counter
from itertools import chain
term_appearance = Counter(chain.from_iterable(texts_list))
Демо -
>>> 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
. Но словари не хешируются, следовательно, ошибка.
Ответ 2
Причина, по которой вы получаете сообщение о неустранимой типе, заключается в том, что вы не можете использовать словарь в качестве ключа для другого словаря в Python, поскольку они являются изменяемыми контейнерами.
Смотрите: почему объекты dict не сотрясаются в python?
Ответ 3
Словарные слова в Python 2.7+ не работают так, как вы думаете, они работают.
Подобно пониманию списков, они создают словарь new, но вы не можете использовать их для добавления ключей в словарь уже существующих (который в этом случае это то, что вы пытаетесь сделать).
Ответ 4
Пожалуйста, просмотрите ответ 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