web-dev-qa-db-fra.com

Comment modifier le jeton de phrase NLTK

J'utilise NLTK pour analyser quelques textes classiques et j'ai du mal à tokeniser le texte par phrase. Par exemple, voici ce que j'obtiens pour un extrait 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\'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?
-----
"
'''

Je ne m'attends pas à la perfection ici, étant donné que la syntaxe de Melville est un peu datée, mais NLTK devrait être capable de gérer les guillemets terminaux et les titres comme "Mme". Étant donné que le tokenizer est le résultat d'un algo d'entraînement non supervisé, je ne peux pas comprendre comment le bricoler.

Quelqu'un a des recommandations pour un meilleur tokenizer de phrases? Je préfère une simple heuristique que je peux pirater plutôt que d'avoir à former mon propre analyseur.

34
Chris Wilson

Vous devez fournir une liste d'abréviations au tokenizer, comme ceci:

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)

phrases est maintenant:

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

Mise à jour: cela ne fonctionne pas si le dernier mot de la phrase a une apostrophe ou un guillemet attaché (comme Hussey? '). Donc, un moyen rapide et sale de contourner cela est de mettre des espaces devant les apostrophes et les guillemets qui suivent les symboles de fin de phrase (.!?):

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

Vous pouvez modifier le tokenizer de phrases en anglais pré-formé du NLTK pour reconnaître plus d'abréviations en les ajoutant à l'ensemble _params.abbrev_types. Par exemple:

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)

Notez que les abréviations doivent être spécifiées sans la période finale, mais incluent toutes les périodes internes, comme dans 'i.e' au dessus. Pour plus de détails sur les autres paramètres du tokenizer, reportez-vous à la documentation appropriée.

34
bjmc

Vous pouvez dire au PunktSentenceTokenizer.tokenize méthode pour inclure des guillemets "terminaux" avec le reste de la phrase en définissant le realign_boundaries paramètre à True. Voir le code ci-dessous pour un exemple.

Je ne connais pas de méthode propre pour empêcher le texte comme Mrs. Hussey d'être divisé en deux phrases. Cependant, voici un hack qui

  • réduit toutes les occurrences de Mrs. Hussey à Mrs._Hussey,
  • puis divise le texte en phrases avec sent_tokenize.tokenize,
  • puis pour chaque phrase, démêle Mrs._Hussey retour à Mrs. Hussey

Je souhaite que je connaissais une meilleure façon, mais cela pourrait fonctionner dans un pincement.


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)

les rendements

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

J'ai donc eu un problème similaire et j'ai essayé la solution de vpekar ci-dessus.

Peut-être que le mien est une sorte de cas Edge, mais j'ai observé le même comportement après avoir appliqué les remplacements, cependant, lorsque j'ai essayé de remplacer la ponctuation par les citations placées devant eux, j'ai obtenu la sortie que je cherchais. Le manque d'adhésion à l'entraide judiciaire est probablement moins important que de conserver la citation originale en une seule phrase.

Pour être plus clair:

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

Si le MLA est important, vous pouvez toujours revenir en arrière et inverser ces changements partout où cela compte.

2
aidankmcl