Cómo ajustar el tokenizador de oraciones NLTK

Estoy usando NLTK para analizar algunos textos clásicos y tengo problemas para tokenizar el texto por oración. Por ejemplo, esto es lo que obtengo por un fragmento de Moby Dick :

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\'sa 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\'sa rather cold and clammy reception in the winter time, ain\'t it, Mrs. ----- Hussey? ----- " ''' 

No espero la perfección aquí, teniendo en cuenta que la syntax de Melville es un poco anticuada, pero NLTK debería ser capaz de manejar comillas dobles de terminal y títulos como “Mrs.” Sin embargo, dado que el tokenizador es el resultado de un entrenamiento no supervisado, no puedo encontrar la manera de jugar con él.

¿Alguien tiene recomendaciones para un mejor tokenizador de oraciones? Preferiría una heurística simple que puedo hackear en lugar de tener que entrenar a mi propio analizador.

Debe proporcionar una lista de abreviaturas al tokenizer, de esta manera:

 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) 

oraciones es ahora:

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

Actualización: esto no funciona si la última palabra de la oración tiene un apóstrofe o una comilla adjunta (como Hussey? ‘ ). Así que una forma rápida y sucia de evitar esto es poner espacios delante de los apóstrofes y las comillas que siguen a los símbolos de fin de oración (.!?):

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

Puede modificar el tokenizador de oraciones en inglés pre-entrenado de NLTK para reconocer más abreviaturas al agregarlas al conjunto _params.abbrev_types . Por ejemplo:

 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) 

Tenga en cuenta que las abreviaturas deben especificarse sin el período final, pero incluyen cualquier período interno, como en 'i.e' arriba. Para obtener más información sobre los otros parámetros del tokenizer, consulte la documentación relevante.

Puede decirle al método PunktSentenceTokenizer.tokenize que incluya comillas dobles “terminales” con el rest de la oración estableciendo el parámetro realign_boundaries en True . Vea el código de abajo para un ejemplo.

No conozco una forma clara de evitar que texto como la Mrs. Hussey se divida en dos oraciones. Sin embargo, aquí hay un hack que

  • Derrota todas las ocurrencias de la Mrs. Hussey a la Mrs. Hussey ,
  • luego divide el texto en oraciones con sent_tokenize.tokenize ,
  • luego, para cada oración, desenmascara a Mrs._Hussey nuevo a Mrs. Hussey

Ojalá supiera una mejor manera, pero esto podría funcionar en caso de apuro.


 import nltk import re import functools mangle = functools.partial(re.sub, r'([MD]rs?[.]) ([AZ])', r'\1_\2') unmangle = functools.partial(re.sub, r'([MD]rs?[.])_([AZ])', 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\'sa 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) 

rendimientos

 "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?" 

Así que tuve un problema similar y probé la solución de vpekar anterior.

Quizás el mío es una especie de caso de ventaja, pero observé el mismo comportamiento después de aplicar los reemplazos, sin embargo, cuando intenté reemplazar la puntuación con las citas colocadas delante de ellos, obtuve la salida que estaba buscando. Presumiblemente, la falta de adherencia a MLA es menos importante que conservar la cita original como una sola oración.

Para ser más claros:

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

Si el MLA es importante, siempre podría regresar y revertir estos cambios donde sea que cuente.