2015-10-08 15 views
15

Ho una lista di elenchi in python piena di testi. È come impostare le parole di ogni documento. Quindi per ogni documento ho una lista e poi in lista per tutti i documenti.Come posso contare l'occorrenza di ogni parola nel documento usando Comprensione del dizionario

Tutto l'elenco contiene solo parole univoche. Il mio scopo è contare l'occorrenza di ogni parola nel documento completo. Sono in grado di farlo con successo usando il codice seguente:

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

Ma io voglio usare la comprensione dizionario a fare lo stesso. Questa è la prima volta, sto cercando di scrivere la comprensione dizionario e l'utilizzo di post precedenti esistenti in StackOverflow, sono stato in grado di scrivere il seguente:

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} 

Post precedente di riferimento:

Simple syntax error in Python if else dict comprehension

Come suggerito nel post sopra, ho anche usato il seguente codice:

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

il codice di cui sopra è riuscita a pr oducing liste vuote, ma alla fine ha gettato la seguente traceback:

[] 

[] 

[] 

[] 

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' 

Qualsiasi aiuto nel migliorare la mia comprensione attuale sarebbe molto apprezzato.

Guardando l'errore di cui sopra, ho anche provato

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

Questo ha funzionato senza alcun errore, ma l'uscita era solo liste vuote.

+0

Buona fortuna ... Qui è un pensiero, dict predefinito sarà di default a zero, che significa che potrebbe non essere necessario la parte if-else . – nehemiah

risposta

12

Come spiegato nelle altre risposte, il problema è che la comprensione del dizionario crea un nuovo dizionario, quindi non si ottiene il riferimento a quel nuovo dizionario fino a quando non è stato creato. Non puoi fare la comprensione del dizionario per quello che stai facendo.

Dato che, quello che stai facendo è provare a reimplementare ciò che è già stato fatto da collections.Counter. Potresti semplicemente usare Counter.Esempio -

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

Se si vuole veramente fare questo in una sorta di comprensione, si può fare:

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

Demo -

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

L'uscita [None, None, None, None] è fr om la comprensione della lista risultante in quella lista (perché questa è stata eseguita in modo interattivo), se la si esegue in uno script come python <script>, quell'output verrebbe semplicemente scartato.


È inoltre possibile utilizzare itertools.chain.from_iterable() per creare una lista appiattita dai vostri text_lists e quindi utilizzare tale per Counter. Esempio:

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

Inoltre, un altro problema nel codice originale, in linea -

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

Questo è in realtà la comprensione insieme con la comprensione dizionario annidati dentro.

Questo è il motivo per cui si sta verificando l'errore - TypeError: unhashable type: 'dict'. Perché dopo aver eseguito per la prima volta la comprensione del dizionario e aver creato un dict, si sta tentando di aggiungerlo allo set. Ma i dizionari non sono lavabili, quindi l'errore.

6

Il motivo per cui si sta verificando l'errore di tipo non cancellabile è che non è possibile utilizzare un dizionario come chiave per un altro dizionario in Python, poiché sono contenitori modificabili.

See: why dict objects are unhashable in python?

3

comprensioni dizionario in Python 2.7+ non funzionano il modo in cui si potrebbe pensare funzionano.

Come list comprehension, creano un nuovo dizionario ma non li possono utilizzare per aggiungere le chiavi a un dizionario giàesistente (che in questo caso è quello che si sta cercando di fare).

3

Si prega di guardare attraverso answer da Anand S Kumar se si desidera utilizzare collections.Counter che è un grande suggerimento. Tuttavia c'è un'altra soluzione relative al utilizzando collections.defaultdict che trovo degni di nota:

from collections import defaultdict 

text_appearances = defaultdict() 

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

Ho usato questo costrutto alcune volte, e penso che sia un modo pulito e piacevole di fare il conteggio. Soprattutto se per qualche ragione hai bisogno di fare delle verifiche intermedie, questo è un modo efficace per aggiornare direttamente il conteggio senza preoccuparti se la chiave/parola esiste già nel tuo dizionario (come nella tua prima soluzione).

Sidenote sulla denominazione variabile: prega di non utilizzare in minuscolo l (minuscolo di L) come un nome di variabile, è difficile da distinguere dalla 1 (il numero uno). Nel tuo caso potresti nominare le variabili, words e word? Con l'aggiunta di non usare _list come suffisso, il codice potrebbe leggere:

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