2016-04-22 14 views
13

Sto cercando di ottenere parole che sono distintive di determinati documenti che utilizzano la classe TfIDFVectorizer in scikit-learn. Crea una matrice tfidf con tutte le parole e i loro punteggi in tutti i documenti, ma poi sembra contare anche parole comuni. Questo è parte del codice sto correndo:In che modo il TFIDFVectorizer in scikit-learn dovrebbe funzionare?

vectorizer = TfidfVectorizer() 
tfidf_matrix = vectorizer.fit_transform(contents) 
feature_names = vectorizer.get_feature_names() 
dense = tfidf_matrix.todense() 
denselist = dense.tolist() 
df = pd.DataFrame(denselist, columns=feature_names, index=characters) 
s = pd.Series(df.loc['Adam']) 
s[s > 0].sort_values(ascending=False)[:10] 

Mi aspettavo questo per restituire un elenco di parole distintivi per il documento 'Adamo', ma ciò che lo fa restituire una lista di parole comuni:

and  0.497077 
to  0.387147 
the  0.316648 
of  0.298724 
in  0.186404 
with 0.144583 
his  0.140998 

Potrei non capirlo perfettamente, ma a quanto ho capito, tf-idf dovrebbe trovare le parole che sono distintive di un documento in un corpus, trovando parole che appaiono frequentemente in un documento, ma non in altri documenti. Qui, and appare frequentemente in altri documenti, quindi non so perché restituisca un valore alto qui.

Il codice completo che sto utilizzando per generare questo è in this Jupyter notebook.

Quando computo tf/idfs in modo semi-manuale, utilizzando il NLTK e calcolando i punteggi per ogni parola, ottengo i risultati appropriati. Per la 'Adam' documento:

fresh  0.000813 
prime  0.000813 
bone   0.000677 
relate  0.000677 
blame  0.000677 
enough  0.000677 

che sembra circa la destra, dal momento che queste sono parole che compaiono nel documento 'Adamo', ma non tanto in altri documenti del corpus. Il codice completo utilizzato per generare questo è in this Jupyter notebook.

Sto facendo qualcosa di sbagliato con il codice scikit? C'è un altro modo per inizializzare questa classe dove restituisce i risultati giusti? Ovviamente, posso ignorare le stopword passando lo stop_words = 'english', ma questo non risolve il problema, dal momento che parole comuni di qualsiasi tipo non dovrebbero avere punteggi alti qui.

risposta

3

Da scikit-learn documentazione:

Come TF-IDF è molto spesso utilizzato per le funzioni di testo, c'è anche un'altra classe chiamata TfidfVectorizer che unisce tutte le opzioni di CountVectorizer e TfidfTransformer in un unico modello.

Come potete vedere, TfidfVectorizer è un CountVectorizer seguito da TfidfTransformer.

Quello che state probabilmente cercando è TfidfTransformer e non TfidfVectorizer

+0

TfidfTransformer trasformerà l'output di CountVectorizer, quindi è possibile eseguire CountVectorizer e quindi eseguire TfidfTransformer, ma è come eseguire TfidfVectorizer. Quindi non sono convinto di aver bisogno di TfidfTransformer, se prima dovrò comunque eseguire CountVectorizer. Non restituirà gli stessi risultati? – Jono

2

Credo che il problema risiede nell'utilizzo di diverse liste stopword. Scikit-learn e NLTK utilizzano diversi elenchi di parole chiave per impostazione predefinita. Per scikit-learn di solito è una buona idea avere un elenco stop_words personalizzati passata a TfidfVectorizer, ad esempio:

my_stopword_list = ['and','to','the','of'] 
my_vectorizer = TfidfVectorizer(stop_words=my_stopword_list) 

pagina Doc per la classe TfidfVectorizer: [http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html][1]

+0

Buono a sapersi, ma credo di essere confuso sul motivo per cui è necessario rimuovere le parole chiave per iniziare. Se "e" o "il" si verificano frequentemente in tutti i documenti, diciamo, allora perché dovrebbe avere un alto valore tf-idf? Mi sembra che il punto di tf-idf sia quello di regolare la frequenza del termine su tutti i documenti, in modo che i termini che si verificano frequentemente attraverso il corpus non compaano nella parte superiore dell'elenco. – Jono

+0

@Jono, immagino che il tuo intuito sia che TFIDF dovrebbe beneficiare di termini rari. Questo è per metà vero. TFIDF tiene conto di due aspetti principali: TF, che è il termine frequenza nel documento e IDF, che è la frequenza inversa sull'intero insieme di documenti. TF beneficia di termini frequenti, mentre l'IDF beneficia di termini rari. Queste due misure sono quasi opposte, il che rende il TFIDF una metrica equilibrata. – Rabbit

+0

Inoltre, la rimozione di stopword è una pratica molto comune quando si utilizza una rappresentazione dello spazio vettoriale. Possiamo ragionare in questo modo: per la maggior parte delle applicazioni, vuoi avere una metrica alta per termini importanti e bassa/zero per quelli non importanti. Se la tua rappresentazione (TFIDF in questo caso) non riesce a farlo, puoi contrastare questo rimuovendo un termine che non ti aiuterà e potenzialmente danneggerà il tuo modello. – Rabbit

2

non sono sicuro perché non è il predefinito, ma probabilmente si desidera sublinear_tf=True nell'inizializzazione per TfidfVectorizer. Ho biforcato il tuo repository e ti ho inviato un PR con un esempio che probabilmente assomiglia di più a quello che vuoi.

+0

Fantastico. Questo è un grande miglioramento. Ma se lo esegui con un set di caratteri più piccolo, invece di tutti i personaggi, ottieni di nuovo liste di parole di uso comune: https://github.com/JonathanReeve/milton-analysis/blob/v0.2/tfidf- scikit.ipynb "And," "to," "the," e "of" sono le parole con il più alto tf-idfs per Adamo ed Eva, ma quelle sono parole che appaiono frequentemente attraverso il corpus, quindi non so perché stanno ottenendo buoni punteggi tf-idf qui. – Jono

+0

Poiché ora si utilizzano molti meno documenti. Quindi l'IDF, che cresce nel numero di volte che il termine è trovato in un documento (cioè, un * per numero di documenti *), non diventa molto grande con solo quattro documenti (<= 4 per ogni termine) e tu non hanno abbastanza "potere statistico". – fnl

Problemi correlati