2012-04-11 12 views
23

Fondamentalmente ho il same question as this guy .. Il example in the NLTK book per il classificatore Naive Bayes considera solo se una parola si verifica in un documento come una caratteristica .. non considera la frequenza delle parole come caratteristica da guardare ("bag-of-words").Implementatore di parole chiave di classificazione Naive-Bayes in NLTK

One of the answers sembra suggerire che questo non può essere fatto con i classificatori NLTK incorporati. È questo il caso? Come posso fare la classificazione NB/bag-of-words NB con NLTK?

risposta

31

scikit-learn ha an implementation of multinomial naive Bayes, che è la variante giusta di Bayes naive in questa situazione. Una macchina vettoriale di supporto (SVM) probabilmente funzionerebbe meglio, però.

Come ha sottolineato Ken nei commenti, NLTK ha a nice wrapper for scikit-learn classifiers. Modificato dai documenti, qui è un po 'complicato che fa la ponderazione TF-IDF, sceglie le 1000 migliori caratteristiche basate su una statistica chi2, e poi lo passa in un classificatore Bayes ingenuo multinomiale. (. Scommetto che questo è un po 'goffo, come io non sono super familiarità con uno o NLTK scikit-learn)

import numpy as np 
from nltk.probability import FreqDist 
from nltk.classify import SklearnClassifier 
from sklearn.feature_extraction.text import TfidfTransformer 
from sklearn.feature_selection import SelectKBest, chi2 
from sklearn.naive_bayes import MultinomialNB 
from sklearn.pipeline import Pipeline 

pipeline = Pipeline([('tfidf', TfidfTransformer()), 
        ('chi2', SelectKBest(chi2, k=1000)), 
        ('nb', MultinomialNB())]) 
classif = SklearnClassifier(pipeline) 

from nltk.corpus import movie_reviews 
pos = [FreqDist(movie_reviews.words(i)) for i in movie_reviews.fileids('pos')] 
neg = [FreqDist(movie_reviews.words(i)) for i in movie_reviews.fileids('neg')] 
add_label = lambda lst, lab: [(x, lab) for x in lst] 
classif.train(add_label(pos[:100], 'pos') + add_label(neg[:100], 'neg')) 

l_pos = np.array(classif.classify_many(pos[100:])) 
l_neg = np.array(classif.classify_many(neg[100:])) 
print "Confusion matrix:\n%d\t%d\n%d\t%d" % (
      (l_pos == 'pos').sum(), (l_pos == 'neg').sum(), 
      (l_neg == 'pos').sum(), (l_neg == 'neg').sum()) 

Questo stampato per me:

Confusion matrix: 
524  376 
202  698 

Non perfetto, ma decente, considerando non è un problema super facile ed è solo addestrato su 100/100.

+1

In realtà, probabilmente desidera che i modelli di supporto per la macchina vettoriale supportino gli scikit. NLTK ha un bel wrapper 'nltk.classify.scikitlearn.SklearnClassifier' che rende questi classificatori adatti alla sua API. –

+0

@KenBloom Sì, gli SVM probabilmente andrebbero meglio, ma ha fatto espressamente domande sull'ingenuo Bayes.:) Quel wrapper è bello, e ho appena realizzato che c'è anche un Baye ingenuo multinomiale in scikit-learn, quindi cambierò la mia risposta per usarlo. – Dougal

+1

che sembra straordinariamente semplice. Vorrei aver imparato Python mentre stavo facendo il mio dottorato. in questo. Ho fatto un sacco di classificazioni per il wrapping del lavoro in Ruby che sarebbe stato del tutto inutile. –

6

Le funzioni nel classificatore bayes NLTK sono "nominali", non numeriche. Ciò significa che possono prendere un numero finito di valori discreti (etichette), ma non possono essere trattati come frequenze.

Quindi, con il classificatore Bayes, non si può direttamente utilizzo frequenza delle parole come Caratteristica-- si potrebbe fare qualcosa di simile a utilizzare le 50 parole più frequenti da ogni testo come il vostro set di funzionalità, ma che è una cosa ben diversa

Ma forse ci sono altri classificatori nel NLTK che dipendono dalla frequenza. Non lo saprei, ma hai guardato? Direi che vale la pena provarlo.

3
  • messo la corda si sta guardando in un elenco, suddiviso in parole
  • per ogni elemento della lista, chiedere: è questo oggetto una caratteristica che ho in lista di funzionalità.
  • Se lo è, aggiungere il log log come al solito, in caso contrario, ignorarlo.

Se la tua frase ha la stessa parola più volte, aggiungerà i probs più volte. Se la parola appare più volte nella stessa classe, i dati di allenamento dovrebbero riflettere quello nel conteggio delle parole.

Per maggiore precisione, contare tutti i bi-grammi, i trilogrammi, ecc. Come caratteristiche separate.

Aiuta a scrivere manualmente i propri classificatori in modo da capire esattamente cosa sta succedendo e cosa è necessario fare per migliorare l'accuratezza. Se si utilizza una soluzione preconfezionata e non funziona abbastanza bene, non c'è molto che si possa fare al riguardo.