2014-04-07 18 views
27

Ho lavorato con la classe CountVectorizer in scikit-learn.Posso usare CountVectorizer in scikit-learn per contare la frequenza dei documenti che non sono stati utilizzati per estrarre i token?

Capisco che se utilizzato nel modo illustrato di seguito, l'output finale sarà costituito da un array contenente i conteggi di funzionalità o token.

Questi gettoni sono estratti da una serie di parole chiave, vale a dire

tags = [ 
    "python, tools", 
    "linux, tools, ubuntu", 
    "distributed systems, linux, networking, tools", 
] 

Il passo successivo è:

from sklearn.feature_extraction.text import CountVectorizer 
vec = CountVectorizer(tokenizer=tokenize) 
data = vec.fit_transform(tags).toarray() 
print data 

dove otteniamo

[[0 0 0 1 1 0] 
[0 1 0 0 1 1] 
[1 1 1 0 1 0]] 

Questo va bene, ma il mio la situazione è solo un po 'diversa.

Desidero estrarre le funzionalità come sopra, ma non voglio che le righe in data siano gli stessi documenti da cui sono state estratte le funzionalità.

In altre parole, come posso ottenere i conteggi di un altro insieme di documenti, per esempio,

list_of_new_documents = [ 
    ["python, chicken"], 
    ["linux, cow, ubuntu"], 
    ["machine learning, bird, fish, pig"] 
] 

E ottenere:

[[0 0 0 1 0 0] 
[0 1 0 0 0 1] 
[0 0 0 0 0 0]] 

Ho letto la documentazione per la classe CountVectorizer, ed è venuto attraverso l'argomento vocabulary, che è una mappatura dei termini agli indici delle caratteristiche. Tuttavia, non riesco a ottenere questo argomento per aiutarmi.

Qualsiasi consiglio è apprezzato.
PS: tutto il credito dovuto a Matthias Friedrich's Blog per l'esempio che ho usato sopra.

risposta

39

Hai ragione che vocabulary è quello che vuoi. Funziona in questo modo:

>>> cv = sklearn.feature_extraction.text.CountVectorizer(vocabulary=['hot', 'cold', 'old']) 
>>> cv.fit_transform(['pease porridge hot', 'pease porridge cold', 'pease porridge in the pot', 'nine days old']).toarray() 
array([[1, 0, 0], 
     [0, 1, 0], 
     [0, 0, 0], 
     [0, 0, 1]], dtype=int64) 

Quindi si passa un dict con le caratteristiche desiderate come le chiavi.

se si è utilizzato CountVectorizer su una serie di documenti e poi si desidera utilizzare l'insieme delle caratteristiche di tali documenti per un nuovo set, utilizzare l'attributo vocabulary_ dell'originale CountVectorizer e passarlo al nuovo. Quindi nel tuo esempio, si potrebbe fare

newVec = CountVectorizer(vocabulary=vec.vocabulary_) 

per creare un nuovo tokenizzatore usando il vocabolario dal primo.

+0

Grazie, questo sembra grande! Per la prima soluzione: il vocabolario dovrebbe sempre essere un dict, non un elenco? Correggimi se sbaglio, ma i conteggi (0, 1, 2) sembrano irrilevanti. Il secondo metodo che hai delineato sembra forse un po 'più chiaro. –

+1

@ MattO'Brien: hai ragione, può essere una lista, ho letto male la documentazione. Ho modificato la mia risposta. Nel secondo metodo, però, è un dict, perché è quello che è il metodo 'vocabulary_ 'di un vectorizer adattato. – BrenBarn

+1

BrenBarn, la tua risposta mi ha fatto risparmiare un sacco di tempo. Sul serio. Grazie per essere su questo sito. –

6

È necessario chiamare fit_transform o solo fit sul codice sorgente del vocabolario originale in modo che il vettorizzatore apprenda un vocabolario.

Quindi è possibile utilizzare questo vettore fit su qualsiasi nuova origine dati tramite il metodo transform().

È possibile ottenere il vocabolario prodotta dal fit (cioè la mappatura di parola a gettone ID) tramite vectorizer.vocabulary_ (supponendo che il nome del tuo CountVectorizer il nome vectorizer.

0
>>> tags = [ 
    "python, tools", 
    "linux, tools, ubuntu", 
    "distributed systems, linux, networking, tools", 
] 

>>> list_of_new_documents = [ 
    ["python, chicken"], 
    ["linux, cow, ubuntu"], 
    ["machine learning, bird, fish, pig"] 

] 

>>> from sklearn.feature_extraction.text import CountVectorizer 
>>> vect = CountVectorizer() 
>>> tags = vect.fit_transform(tags) 

# vocabulary learned by CountVectorizer (vect) 
>>> print(vect.vocabulary_) 
{'python': 3, 'tools': 5, 'linux': 1, 'ubuntu': 6, 'distributed': 0, 'systems': 4, 'networking': 2} 

# counts for tags 
>>> tags.toarray() 
array([[0, 0, 0, 1, 0, 1, 0], 
     [0, 1, 0, 0, 0, 1, 1], 
     [1, 1, 1, 0, 1, 1, 0]], dtype=int64) 

# to use `transform`, `list_of_new_documents` should be a list of strings 
# `itertools.chain` flattens shallow lists more efficiently than list comprehensions 

>>> from itertools import chain 
>>> new_docs = list(chain.from_iterable(list_of_new_documents) 
>>> new_docs = vect.transform(new_docs) 

# finally, counts for new_docs! 
>>> new_docs.toarray() 
array([[0, 0, 0, 1, 0, 0, 0], 
     [0, 1, 0, 0, 0, 0, 1], 
     [0, 0, 0, 0, 0, 0, 0]]) 

Per verificare che CountVectorizer sta usando il vocabolario appreso da tags su new_docs: stampare vect.vocabulary_ di nuovo o di confrontare l'output di new_docs.toarray() a quella di tags.toarray()