web-dev-qa-db-ja.com

NLTK文トークナイザーを調整する方法

私はNLTKを使用していくつかの古典的なテキストを分析しており、テキストを文ごとにトークン化するのに苦労しています。たとえば、これは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?
-----
"
'''

Melvilleの構文は少し古くなっていることを考えると、ここで完璧を期待することはできませんが、NLTKはターミナルの二重引用符や「Mrs」のようなタイトルを処理できるはずです。トークナイザーは教師なしのトレーニングアルゴの結果であるため、いじくり回す方法がわかりません。

誰もがより良い文章トークナイザーのための推奨事項を持っていますか?自分のパーサーをトレーニングする必要はなく、ハッキングできる単純なヒューリスティックを使用したいと思います。

34
Chris Wilson

次のように、トークナイザに略語のリストを提供する必要があります。

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)

文章は今です:

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

更新:これは、文の最後の単語にアポストロフィまたは引用符が付いている場合は機能しません(例Hussey? ')。したがって、これを回避する簡単な方法は、文末の記号(。!?)に続くアポストロフィと引用符の前にスペースを置くことです。

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

セット_params.abbrev_typesに追加することで、NLTKの事前トレーニング済みの英語のセンテンストークナイザーを変更して、より多くの略語を認識できます。例えば:

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)

省略形は最後のピリオドなしで指定する必要がありますが、上記の'i.e'のように内部ピリオドは含まれていることに注意してください。その他のトークナイザパラメータの詳細については、 関連ドキュメント を参照してください。

34
bjmc

PunktSentenceTokenizer.tokenizeメソッドにrealign_boundariesパラメータをTrueに設定することで、文の残りに「ターミナル」二重引用符を含めるように指示できます。例については、以下のコードを参照してください。

Mrs. Husseyのようなテキストが2つの文に分割されるのを防ぐための明確な方法がわかりません。しかし、これはハックです

  • すべてのMrs. HusseyMrs._Husseyにマングルします。
  • 次に、テキストをsent_tokenize.tokenizeで文に分割します。
  • 次に、各文について、Mrs._HusseyMrs. Husseyに逆符号化します

もっと良い方法を知っていればいいのですが、これはピンチでうまくいくかもしれません。


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)

収量

"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

だから私は同様の問題があり、上記のvpekarの解決策を試しました。

おそらく私のものはある種のEdgeケースですが、置換を適用した後も同じ動作が見られましたが、句読点をその前に置かれた引用符で置き換えようとすると、探していた出力が得られました。おそらく、MLAの順守の欠如は、元の引用を単一​​の文として保持することよりも重要ではありません。

より明確にするために:

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

MLAが重要な場合でも、いつでも戻ってこれらの変更を元に戻すことができます。

2
aidankmcl