2015-03-27 16 views
8

Il codice seguente è Classificatore di recensioni di film Naive Bayes. Il codice genera un elenco delle funzionalità più informative.Test del classificatore NLTK su un file specifico

Nota: la cartella**movie review** è nello nltk.

from itertools import chain 
from nltk.corpus import stopwords 
from nltk.probability import FreqDist 
from nltk.classify import NaiveBayesClassifier 
from nltk.corpus import movie_reviews 
stop = stopwords.words('english') 

documents = [([w for w in movie_reviews.words(i) if w.lower() not in stop and w.lower() not in string.punctuation], i.split('/')[0]) for i in movie_reviews.fileids()] 


word_features = FreqDist(chain(*[i for i,j in documents])) 
word_features = word_features.keys()[:100] 

numtrain = int(len(documents) * 90/100) 
train_set = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in documents[:numtrain]] 
test_set = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in documents[numtrain:]] 

classifier = NaiveBayesClassifier.train(train_set) 
print nltk.classify.accuracy(classifier, test_set) 
classifier.show_most_informative_features(5) 

link of code da alvas

come posso prova il classificatore sul specifico di file?

Per favore fatemi sapere se la mia domanda è ambigua o sbagliata.

risposta

8

In primo luogo, leggere attentamente queste risposte, che contengono parti delle risposte necessarie e anche brevemente spiega cosa il classificatore fa e come funziona in NLTK:


test classificatore su dati annotati

Ora per rispondere alla tua domanda. Partiamo dal presupposto che la tua domanda è un follow-up di questa domanda: Using my own corpus instead of movie_reviews corpus for Classification in NLTK

Se il testo di prova è strutturata allo stesso modo come il movie_review corpus, allora si può semplicemente leggere i dati di test come si farebbe per i dati di formazione:

Solo nel caso in cui la spiegazione del codice non è chiaro, ecco una guida:

traindir = '/home/alvas/my_movie_reviews' 
mr = CategorizedPlaintextCorpusReader(traindir, r'(?!\.).*\.txt', cat_pattern=r'(neg|pos)/.*', encoding='ascii') 

le due linee di cui sopra è quello di leggere una directory my_movie_reviews con una tale struttura:

\my_movie_reviews 
    \pos 
     123.txt 
     234.txt 
    \neg 
     456.txt 
     789.txt 
    README 

Quindi la riga successiva estrae i documenti con il tag pos/neg che fa parte della struttura di directory.

documents = [([w for w in mr.words(i) if w.lower() not in stop and w not in string.punctuation], i.split('/')[0]) for i in mr.fileids()] 

Ecco la spiegazione per la linea di cui sopra:

# This extracts the pos/neg tag 
labels = [i for i.split('/')[0]) for i in mr.fileids()] 
# Reads the words from the corpus through the CategorizedPlaintextCorpusReader object 
words = [w for w in mr.words(i)] 
# Removes the stopwords 
words = [w for w in mr.words(i) if w.lower() not in stop] 
# Removes the punctuation 
words = [w for w in mr.words(i) w not in string.punctuation] 
# Removes the stopwords and punctuations 
words = [w for w in mr.words(i) if w.lower() not in stop and w not in string.punctuation] 
# Removes the stopwords and punctuations and put them in a tuple with the pos/neg labels 
documents = [([w for w in mr.words(i) if w.lower() not in stop and w not in string.punctuation], i.split('/')[0]) for i in mr.fileids()] 

Il processo stesso dovrebbe essere applicata quando si leggono i dati di prova !!!

Ora al trattamento funzione:

le seguenti righe primi 100 funzioni extra per il classificatore:

# Extract the words features and put them into FreqDist 
# object which records the no. of times each unique word occurs 
word_features = FreqDist(chain(*[i for i,j in documents])) 
# Cuts the FreqDist to the top 100 words in terms of their counts. 
word_features = word_features.keys()[:100] 

Accanto alla elaborazione dei documenti in formato classificare-grado:

# Splits the training data into training size and testing size 
numtrain = int(len(documents) * 90/100) 
# Process the documents for training data 
train_set = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in documents[:numtrain]] 
# Process the documents for testing data 
test_set = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in documents[numtrain:]] 

Ora per spiegare quella lunga lista di comprensione per train_set e `test_set:

# Take the first `numtrain` no. of documents 
# as training documents 
train_docs = documents[:numtrain] 
# Takes the rest of the documents as test documents. 
test_docs = documents[numtrain:] 
# These extract the feature sets for the classifier 
# please look at the full explanation on https://stackoverflow.com/questions/20827741/nltk-naivebayesclassifier-training-for-sentiment-analysis/ 
train_set = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in train_docs] 

È necessario elaborare i documenti come sopra anche per le funzioni di estrazione nei documenti di prova anche !!!

Quindi, ecco come si può leggere i dati del test:

stop = stopwords.words('english') 

# Reads the training data. 
traindir = '/home/alvas/my_movie_reviews' 
mr = CategorizedPlaintextCorpusReader(traindir, r'(?!\.).*\.txt', cat_pattern=r'(neg|pos)/.*', encoding='ascii') 

# Converts training data into tuples of [(words,label), ...] 
documents = [([w for w in mr.words(i) if w.lower() not in stop and w not in string.punctuation], i.split('/')[0]) for i in mr.fileids()] 

# Now do the same for the testing data. 
testdir = '/home/alvas/test_reviews' 
mr_test = CategorizedPlaintextCorpusReader(testdir, r'(?!\.).*\.txt', cat_pattern=r'(neg|pos)/.*', encoding='ascii') 
# Converts testing data into tuples of [(words,label), ...] 
test_documents = [([w for w in mr_test.words(i) if w.lower() not in stop and w not in string.punctuation], i.split('/')[0]) for i in mr_test.fileids()] 

quindi continuare con le fasi di lavorazione di cui sopra, e semplicemente fare questo per ottenere l'etichetta per il documento di prova come @yvespeirsman rispose:

#### FOR TRAINING DATA #### 
stop = stopwords.words('english') 

# Reads the training data. 
traindir = '/home/alvas/my_movie_reviews' 
mr = CategorizedPlaintextCorpusReader(traindir, r'(?!\.).*\.txt', cat_pattern=r'(neg|pos)/.*', encoding='ascii') 

# Converts training data into tuples of [(words,label), ...] 
documents = [([w for w in mr.words(i) if w.lower() not in stop and w not in string.punctuation], i.split('/')[0]) for i in mr.fileids()] 
# Extract training features. 
word_features = FreqDist(chain(*[i for i,j in documents])) 
word_features = word_features.keys()[:100] 
# Assuming that you're using full data set 
# since your test set is different. 
train_set = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in documents] 

#### TRAINS THE TAGGER #### 
# Train the tagger 
classifier = NaiveBayesClassifier.train(train_set) 

#### FOR TESTING DATA #### 
# Now do the same reading and processing for the testing data. 
testdir = '/home/alvas/test_reviews' 
mr_test = CategorizedPlaintextCorpusReader(testdir, r'(?!\.).*\.txt', cat_pattern=r'(neg|pos)/.*', encoding='ascii') 
# Converts testing data into tuples of [(words,label), ...] 
test_documents = [([w for w in mr_test.words(i) if w.lower() not in stop and w not in string.punctuation], i.split('/')[0]) for i in mr_test.fileids()] 
# Reads test data into features: 
test_set = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in test_documents] 

#### Evaluate the classifier #### 
for doc, gold_label in test_set: 
    tagged_label = classifier.classify(doc) 
    if tagged_label == gold_label: 
     print("Woohoo, correct") 
    else: 
     print("Boohoo, wrong") 

Se il codice di cui sopra e la spiegazione non ha senso per voi, allora si DOVETE leggere questo tutorial prima di procedere: http://www.nltk.org/howto/classify.html

012.

Ora diciamo che non avete annotazioni nei tuoi dati di test, vale a dire la vostra test.txt non è nella struttura di directory come la movie_review e solo un file di testo semplice:

\test_movie_reviews 
    \1.txt 
    \2.txt 

Poi c'è alcun senso leggerlo in un corpus classificato, si può semplicemente fare leggere e contrassegnare i documenti, vale a dire:

for infile in os.listdir(`test_movie_reviews): 
    for line in open(infile, 'r'): 
     tagged_label = classifier.classify(doc) 

MA si non può valutare i risultati senza l'annotazione, quindi non è possibile controllare il tag se il if-else, anche è necessario tokenizzare il testo se non si utilizza CategorizedPlaintextCorpusReader.

Se si desidera solo per contrassegnare un file di testo in chiaro test.txt:

import string 
from itertools import chain 
from nltk.corpus import stopwords 
from nltk.probability import FreqDist 
from nltk.classify import NaiveBayesClassifier 
from nltk.corpus import movie_reviews 
from nltk import word_tokenize 

stop = stopwords.words('english') 

# Extracts the documents. 
documents = [([w for w in movie_reviews.words(i) if w.lower() not in stop and w.lower() not in string.punctuation], i.split('/')[0]) for i in movie_reviews.fileids()] 
# Extract the features. 
word_features = FreqDist(chain(*[i for i,j in documents])) 
word_features = word_features.keys()[:100] 
# Converts documents to features. 
train_set = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in documents] 
# Train the classifier. 
classifier = NaiveBayesClassifier.train(train_set) 

# Tag the test file. 
with open('test.txt', 'r') as fin: 
    for test_sentence in fin: 
     # Tokenize the line. 
     doc = word_tokenize(test_sentence.lower()) 
     featurized_doc = {i:(i in doc) for i in word_features} 
     tagged_label = classifier.classify(featurized_doc) 
     print(tagged_label) 

Ancora una volta, per favore non basta copiare e incollare la soluzione e cercare di capire perché e come funziona.

+0

Grazie per la spiegazione completa e cerco di capirli. Ma spesso incontro risultati sbagliati. Voglio dire che dovrebbe essere 'pos' ma il programma mostra' neg'. E non conosco la ragione. – ZaM

+1

Ci sono molte ragioni e non è perfetto, forse (i) i dati sono insufficienti, (ii) le caratteristiche non sono abbastanza buone, (iii) la scelta del classificatore, ecc. Prendi questo corso https://www.coursera.org/ corso/ml per maggiori informazioni. E se puoi, ti incoraggio fortemente a frequentare http://lxmls.it.pt/2015/ – alvas

+0

Sono confuso. Per prima cosa ottengo un file da 'nltk/movie_reviews/neg/cv081.txt'. Poi decido di ** testare ** il file dal tuo programma che fornisce 'Woohoo, correct'or'wrong'. Ho messo il file in '/home/neg/cv081.txt'per test e poi ho ottenuto l'output di' Boohoo, wrong'as! Poi metto il file in "/ home/pos/cv081.txt" e poi ho ottenuto "Woohoo, corretto" come output! Poi provo lo stesso file sul programma 'print (tagged_label)' mi danno molti 'neg's. E sul programma che 'print (tagged_label)'. Non so esattamente come funziona. Mi dà molti 'neg' anche per file' pos' !!. Come posso valutare questi output di 'neg's e' pos's. – ZaM

4

È possibile eseguire il test su un file con classifier.classify(). Questo metodo accetta come input un dizionario con le funzioni come chiavi e True o False come valori, a seconda che la funzione si verifichi nel documento o meno. Emette l'etichetta più probabile per il file, secondo il classificatore. È quindi possibile confrontare questa etichetta con l'etichetta corretta per il file per vedere se la classificazione è corretta.

Nei set di allenamento e test, i dizionari delle funzionalità sono sempre il primo elemento nelle tuple, le etichette sono il secondo elemento nelle tuple.

Così, si può classificare il primo documento nel test impostato in questo modo:

(my_document, my_label) = test_set[0] 
if classifier.classify(my_document) == my_label: 
    print "correct!" 
else: 
    print "incorrect!" 
+0

Potrebbe per favore mostrarmi un esempio completo e ** se ** possibile il vostro esempio essere secondo il mio esempio in questione. Sono così nuovo in Python.Potresti dirmi perché scrivi '0' in' test_set [0] ' – ZaM

+2

Questo è un esempio completo: se si incolla il codice immediatamente dopo il codice nella domanda, funzionerà. Il '0' prende semplicemente il primo documento nel set di test (il primo elemento in un elenco ha l'indice 0). – yvespeirsman

+0

Grazie mille. C'è un modo per scrivere 'name_of_file' invece di' 0' in 'test_set [0]'? Non lo so, il 'test_set' indica esattamente a quale file dato che abbiamo 2 cartella' pos | neg' e ogni cartella ha i suoi file. Lo chiedo perché la parola "più informativo" era "cattiva" (il risultato del mio esempio in questione). Il primo file contiene oltre un centinaio di ** parole "cattive" **. Ma il programma mostra 'errato' nell'output. Dov'è il mio errore? – ZaM