2012-12-30 4 views
29

Ich benutze NLTK, um ein paar klassische Texte zu analysieren, und ich renne in Probleme, die den Text für den Satz tokenisieren. Zum Beispiel, hier ist was ich für ein Snippet erhalten von Moby Dick:Wie man den NLTK-Satz-Tokenizer zwickt

import nltk 
sent_tokenize = nltk.data.load('tokenizers/punkt/english.pickle') 

''' 
(Chapter 16) 
A clam for supper? a cold clam; is THAT what you mean, Mrs. Hussey?" says I, "but 
that's a rather cold and clammy reception in the winter time, ain't it, Mrs. Hussey?" 
''' 
sample = 'A clam for supper? a cold clam; is THAT what you mean, Mrs. Hussey?" says I, "but that\'s a rather cold and clammy reception in the winter time, ain\'t it, Mrs. Hussey?"' 

print "\n-----\n".join(sent_tokenize.tokenize(sample)) 
''' 
OUTPUT 
"A clam for supper? 
----- 
a cold clam; is THAT what you mean, Mrs. 
----- 
Hussey? 
----- 
" says I, "but that\'s a rather cold and clammy reception in the winter time, ain\'t it, Mrs. 
----- 
Hussey? 
----- 
" 
''' 

Ich erwarte nicht, Perfektion hier, wenn man bedenkt, dass Melvilles Syntax etwas veraltet, aber NLTK sollte in der Lage sein Terminal doppelte Anführungszeichen zu handhaben und Titel wie "Frau" Da der Tokenizer jedoch das Ergebnis eines unbeaufsichtigten Trainingsalgorithmus ist, kann ich nicht herausfinden, wie man damit bastelt.

Hat jemand Empfehlungen für einen besseren Satz Tokenizer? Ich würde eine einfache Heuristik bevorzugen, die ich hacken kann, anstatt meinen eigenen Parser trainieren zu müssen.

Antwort

40

Sie müssen eine Liste der Abkürzungen in tokenizer liefern, etwa so:

from nltk.tokenize.punkt import PunktSentenceTokenizer, PunktParameters 
punkt_param = PunktParameters() 
punkt_param.abbrev_types = set(['dr', 'vs', 'mr', 'mrs', 'prof', 'inc']) 
sentence_splitter = PunktSentenceTokenizer(punkt_param) 
text = "is THAT what you mean, Mrs. Hussey?" 
sentences = sentence_splitter.tokenize(text) 

Sätze ist jetzt:

['is THAT what you mean, Mrs. Hussey?'] 

Update: Dies funktioniert nicht, wenn das letzte Wort des Satzes ein Apostroph oder ein Anführungszeichen hat (wie Hussey?). So eine schnelle und unsaubere Weise um dieses ist Plätze vor Apostrophe und Anführungszeichen zu setzen, die Satz-End-Symbole folgen (.!?):

text = text.replace('?"', '? "').replace('!"', '! "').replace('."', '. "') 
+0

Ah, gut zu wissen. Seltsamerweise funktioniert das nicht, wenn ich den kompletten Satz in meiner Frage durch Ihre Lösung ausführen lasse. Irgendeine Idee warum? –

+0

Nur ein paar mehr Informationen in die Antwort hinzugefügt. – vpekar

+3

Ich vermeide im Allgemeinen "Danke" Kommentare, aber hier ist es wirklich vor Ort: Danke! – Private

7

Sie können die Methode PunktSentenceTokenizer.tokenize anweisen, terminale doppelte Anführungszeichen in den Rest des Satzes aufzunehmen, indem Sie den Parameter realign_boundaries auf True setzen. Im folgenden Code finden Sie ein Beispiel.

Ich weiß nicht, eine saubere Möglichkeit zu verhindern, dass Text wie Mrs. Hussey in zwei Sätze aufgeteilt wird. Aber hier ist ein Hack, die

  • alle Vorkommen von Mrs. Hussey-Mrs._Hussey Mangeln,
  • dann den Text in Sätze teilt mit sent_tokenize.tokenize,
  • dann für jeden Satz, unmangles Mrs._Hussey zurück zu Mrs. Hussey

Ich wünschte, ich wüsste einen besseren Weg, aber das könnte in Not arbeiten.


import nltk 
import re 
import functools 

mangle = functools.partial(re.sub, r'([MD]rs?[.]) ([A-Z])', r'\1_\2') 
unmangle = functools.partial(re.sub, r'([MD]rs?[.])_([A-Z])', r'\1 \2') 

sent_tokenize = nltk.data.load('tokenizers/punkt/english.pickle') 

sample = '''"A clam for supper? a cold clam; is THAT what you mean, Mrs. Hussey?" says I, "but that\'s a rather cold and clammy reception in the winter time, ain\'t it, Mrs. Hussey?"'''  

sample = mangle(sample) 
sentences = [unmangle(sent) for sent in sent_tokenize.tokenize(
    sample, realign_boundaries = True)]  

print u"\n-----\n".join(sentences) 

Ausbeuten

"A clam for supper? 
----- 
a cold clam; is THAT what you mean, Mrs. Hussey?" 
----- 
says I, "but that's a rather cold and clammy reception in the winter time, ain't it, Mrs. Hussey?" 
+0

Genau das, was ich brauchte - danke! –

+0

Update: Konsolidierter Teil dieser Antwort mit dem einen über –

2

So hatte ich ein ähnliches Problem und versucht, aus vpekar-Lösung über.

Vielleicht ist meine eine Art Randfall, aber ich beobachtete das gleiche Verhalten nach der Anwendung der Ersetzungen, aber als ich versuchte, die Satzzeichen durch die vor ihnen platzierten Zitate zu ersetzen, bekam ich die Ausgabe, nach der ich suchte. Vermutlich ist die fehlende Einhaltung von MLA weniger wichtig, als das ursprüngliche Zitat als einen einzigen Satz beizubehalten.

Um mehr klar:

text = text.replace('?"', '"?').replace('!"', '"!').replace('."', '".') 

Wenn MLA wichtig ist, wenn Sie immer wieder und umgekehrt, diese Änderungen gehen könnte, wo es zählt.

24

Sie können den vortrainierten englischen Satz-Tokenizer des NLTK modifizieren, um weitere Abkürzungen zu erkennen, indem Sie sie zum Satz _params.abbrev_types hinzufügen. Zum Beispiel:

extra_abbreviations = ['dr', 'vs', 'mr', 'mrs', 'prof', 'inc', 'i.e'] 
sentence_tokenizer = nltk.data.load('tokenizers/punkt/english.pickle') 
sentence_tokenizer._params.abbrev_types.update(extra_abbreviations) 

Beachten Sie, dass die Abkürzungen ohne die letzte Periode muss angegeben werden, aber sind interne Perioden, wie in 'i.e' oben. Einzelheiten zu den anderen Tokenizer-Parametern finden Sie unter the relevant documentation.

+1

Dies sollte die beste Antwort sein. Wenn Sie nur einen neuen Tokenizer erstellen, erhalten Sie nicht alle vorhandenen Funktionen des englischen Tokenizers. –

+0

Es schien nicht für mich zu arbeiten, während die oberste Antwort tat. – Alter