2014-01-14 9 views
11

Ich bin auf der Suche nach einer Einteilung in die Ader von NLTK Chapter 6. Das Buch scheint einen Schritt beim Erstellen der Kategorien zu überspringen, und ich bin mir nicht sicher, was ich falsch mache. Ich habe mein Skript hier mit der folgenden Antwort. Meine Probleme stammen hauptsächlich von der ersten Kategorie - Erstellung auf der Basis von Verzeichnisnamen. Einige andere Fragen hier haben Dateinamen verwendet (d. H. pos_1.txt und neg_1.txt), aber ich würde lieber Verzeichnisse erstellen, in die ich dumps dateien könnte.Klassifizierung mit Film Review Korpus in NLTK/Python

from nltk.corpus import movie_reviews 

reviews = CategorizedPlaintextCorpusReader('./nltk_data/corpora/movie_reviews', r'(\w+)/*.txt', cat_pattern=r'/(\w+)/.txt') 
reviews.categories() 
['pos', 'neg'] 

documents = [(list(movie_reviews.words(fileid)), category) 
      for category in movie_reviews.categories() 
      for fileid in movie_reviews.fileids(category)] 

all_words=nltk.FreqDist(
    w.lower() 
    for w in movie_reviews.words() 
    if w.lower() not in nltk.corpus.stopwords.words('english') and w.lower() not in string.punctuation) 
word_features = all_words.keys()[:100] 

def document_features(document): 
    document_words = set(document) 
    features = {} 
    for word in word_features: 
     features['contains(%s)' % word] = (word in document_words) 
    return features 
print document_features(movie_reviews.words('pos/11.txt')) 

featuresets = [(document_features(d), c) for (d,c) in documents] 
train_set, test_set = featuresets[100:], featuresets[:100] 
classifier = nltk.NaiveBayesClassifier.train(train_set) 

print nltk.classify.accuracy(classifier, test_set) 
classifier.show_most_informative_features(5) 

Das gibt:

File "test.py", line 38, in <module> 
    for w in movie_reviews.words() 

File "/usr/local/lib/python2.6/dist-packages/nltk/corpus/reader/plaintext.py", line 184, in words 
    self, self._resolve(fileids, categories)) 

File "/usr/local/lib/python2.6/dist-packages/nltk/corpus/reader/plaintext.py", line 91, in words 
    in self.abspaths(fileids, True, True)]) 

File "/usr/local/lib/python2.6/dist-packages/nltk/corpus/reader/util.py", line 421, in concat 
    raise ValueError('concat() expects at least one object!') 

ValueError: concat() expects at least one object! 

--------- UPDATE ------------- Dank alvas für Ihre ausführliche Antwort! Ich habe jedoch zwei Fragen.

  1. Ist es möglich, die Kategorie aus dem Dateinamen zu greifen, wie ich es versuchte? Ich hatte gehofft, es in der gleichen Weise wie die review_pos.txt Methode zu tun, nur die pos aus dem Ordnernamen und nicht den Dateinamen zu greifen.
  2. lief ich Ihren Code und erlebe einen Syntaxfehler auf

    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:]]

mit der Karotte unter den ersten for. Ich bin ein Anfänger Python-Benutzer und ich bin nicht vertraut genug mit dieser Bit-Syntax, um zu versuchen, es zu vermeiden.

---- UPDATE 2 ---- Fehler ist

File "review.py", line 17 
    for i in word_features}, tag) 
    ^
SyntaxError: invalid syntax` 
+0

Ich würde es vorziehen, meine Art und Weise zu verwenden, die Kategorie für jede Datei zu extrahieren. Aber Sie können Ihr Hundefutter essen (http://en.wikipedia.org/wiki/Eating_your_own_dog_food). Können Sie den Fehler, der auf der Konsole angezeigt wird, über den Syntaxfehler veröffentlichen? – alvas

+0

gelöscht - zum Original hinzugefügt – user3128184

+0

verwenden Sie py2.7 und höher? Es scheint, als ob die Syntax aufgrund des Diktatverständnisses fehlschlägt – alvas

Antwort

13

Ja, das Tutorial auf Kapitel 6 ist ein Basiswissen für Studenten zielen und von dort sollten die Schüler darauf aufbauen durch Erkunden, was in NLTK verfügbar ist und was nicht. Lasst uns die Probleme einzeln durchgehen.

Erstens ist der Weg,'pos '/' neg 'Dokumente durch das Verzeichnis zu bekommen, wahrscheinlich das Richtige, da das Korpus so organisiert war.

from nltk.corpus import movie_reviews as mr 
from collections import defaultdict 

documents = defaultdict(list) 

for i in mr.fileids(): 
    documents[i.split('/')[0]].append(i) 

print documents['pos'][:10] # first ten pos reviews. 
print 
print documents['neg'][:10] # first ten neg reviews. 

[out]:

['pos/cv000_29590.txt', 'pos/cv001_18431.txt', 'pos/cv002_15918.txt', 'pos/cv003_11664.txt', 'pos/cv004_11636.txt', 'pos/cv005_29443.txt', 'pos/cv006_15448.txt', 'pos/cv007_4968.txt', 'pos/cv008_29435.txt', 'pos/cv009_29592.txt'] 

['neg/cv000_29416.txt', 'neg/cv001_19502.txt', 'neg/cv002_17424.txt', 'neg/cv003_12683.txt', 'neg/cv004_12641.txt', 'neg/cv005_29357.txt', 'neg/cv006_17022.txt', 'neg/cv007_4992.txt', 'neg/cv008_29326.txt', 'neg/cv009_29417.txt'] 

Alternativ möchte ich eine Liste von Tupeln, wo das erste Element ist die Liste von Wörtern in der TXT-Datei und zweite ist die Kategorie . Und während Dabei entfernen auch die Stoppwörter und Interpunktion:

from nltk.corpus import movie_reviews as mr 
import string 
from nltk.corpus import stopwords 
stop = stopwords.words('english') 
documents = [([w for w in mr.words(i) if w.lower() not in stop and w.lower() not in string.punctuation], i.split('/')[0]) for i in mr.fileids()] 

Als nächstes ist der Fehler bei FreqDist(for w in movie_reviews.words() ...). Es ist nichts falsch mit Ihrem Code, nur dass Sie versuchen sollten, Namespace zu verwenden (siehe http://en.wikipedia.org/wiki/Namespace#Use_in_common_languages).Der folgende Code:

from nltk.corpus import movie_reviews as mr 
from nltk.probability import FreqDist 
from nltk.corpus import stopwords 
import string 
stop = stopwords.words('english') 

all_words = FreqDist(w.lower() for w in mr.words() if w.lower() not in stop and w.lower() not in string.punctuation) 

print all_words 

[Ausgänge]:

<FreqDist: 'film': 9517, 'one': 5852, 'movie': 5771, 'like': 3690, 'even': 2565, 'good': 2411, 'time': 2411, 'story': 2169, 'would': 2109, 'much': 2049, ...> 

Seit dem obigen Code druckt die FreqDist richtig, der Fehler scheint, wie Sie die Dateien nicht in nltk_data/ Verzeichnis haben.

Die Tatsache, dass Sie haben fic/11.txt schlägt vor, dass Sie einige ältere Version der NLTK oder NLTK-Korpora verwenden. Normalerweise beginnt die fileids in movie_reviews mit entweder pos/neg dann ein Schrägstrich dann der Dateiname und schließlich .txt, z.B. pos/cv001_18431.txt.

So denke ich, vielleicht sollten Sie die Dateien mit redownload:

$ python 
>>> import nltk 
>>> nltk.download() 

Dann stellen Sie sicher, dass der Film Überprüfung Korpus richtig unter den Corpora Tab heruntergeladen:

MR dl

Zurück zu Der Code, der alle Wörter im Filmüberblickskorpus durchläuft, scheint redundant zu sein, wenn Sie bereits alle Wörter in Ihren Dokumenten gefiltert haben, also würde ich dies lieber tun, um alle Feature-Sets zu extrahieren:

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

featuresets = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in documents] 

Als nächstes wird durch Merkmale der Zug/Test Aufspaltung ist in Ordnung, aber ich denke, dass es besser ist, Dokumente zu verwenden, dies so statt:

featuresets = [({i:(i in tokens) for i in word_features}, tag) for tokens,tag in documents] 
train_set, test_set = featuresets[100:], featuresets[:100] 

ich dies empfehlen stattdessen würde:

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:]] 

Dann füttern Sie die Daten in den Klassifikator und voila! Also hier ist der Code, ohne die Kommentare und Exemplarische Vorgehensweise:

import string 
from itertools import chain 

from nltk.corpus import movie_reviews as mr 
from nltk.corpus import stopwords 
from nltk.probability import FreqDist 
from nltk.classify import NaiveBayesClassifier as nbc 
import nltk 

stop = stopwords.words('english') 
documents = [([w for w in mr.words(i) if w.lower() not in stop and w.lower() not in string.punctuation], i.split('/')[0]) for i in mr.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 = nbc.train(train_set) 
print nltk.classify.accuracy(classifier, test_set) 
classifier.show_most_informative_features(5) 

[out]:

0.655 
Most Informative Features 
        bad = True    neg : pos =  2.0 : 1.0 
        script = True    neg : pos =  1.5 : 1.0 
        world = True    pos : neg =  1.5 : 1.0 
       nothing = True    neg : pos =  1.5 : 1.0 
        bad = False    pos : neg =  1.5 : 1.0 
+0

Ich habe es. Aber ein merkwürdiges Ergebnis, das ich hier bekomme, ist, dass das Naive Bayes Ergebnis die Antwort als 0,16 bis 0,17 gibt, was ich wirklich seltsam finde. Gibt es einen möglichen Grund, warum das passiert? – Arqam

+0

alvas Ich habe den gleichen Code versucht. Allerdings bekomme ich nur 0,16 warum? –