web-dev-qa-db-ja.com

nltkによるカスタムタグ付け

タスクを指定するための小さな英語のような言語を作成しようとしています。基本的な考え方は、ステートメントを動詞と名詞句に分割し、それらの動詞を適用することです。 nltkを使用していますが、期待した結果が得られません。例:

>>> nltk.pos_tag(nltk.Word_tokenize("select the files and copy to harddrive'"))
[('select', 'NN'), ('the', 'DT'), ('files', 'NNS'), ('and', 'CC'), ('copy', 'VB'), ('to', 'TO'), ("harddrive'", 'NNP')]
>>> nltk.pos_tag(nltk.Word_tokenize("move the files to harddrive'"))
[('move', 'NN'), ('the', 'DT'), ('files', 'NNS'), ('to', 'TO'), ("harddrive'", 'NNP')]
>>> nltk.pos_tag(nltk.Word_tokenize("copy the files to harddrive'"))
[('copy', 'NN'), ('the', 'DT'), ('files', 'NNS'), ('to', 'TO'), ("harddrive'", 'NNP')]

いずれの場合も、最初の単語(選択、移動、コピー)が動詞として意図されていることに気づきませんでした。私はこれを回避するためにカスタムタガーと文法を作成できることを知っていますが、同時に、これらのものの多くが私のリーグから外れているとき、私は車輪の再発明に行くのをためらっています。私は特に、英語以外の言語も処理できるソリューションを望んでいます。

とにかく、私の質問は次の1つです。このタイプの文法に適したタガーはありますか?名詞形式よりも動詞形式をより頻繁に使用するように既存のタガーに重みを付ける方法はありますか?タガーを訓練する方法はありますか?完全にもっと良い方法はありますか?

28
SpliFF

1つの解決策は、NLTKタガーに戻るマニュアル nigramTagger を作成することです。このようなもの:

>>> import nltk.tag, nltk.data
>>> default_tagger = nltk.data.load(nltk.tag._POS_TAGGER)
>>> model = {'select': 'VB'}
>>> tagger = nltk.tag.UnigramTagger(model=model, backoff=default_tagger)

次に、

>>> tagger.tag(['select', 'the', 'files'])
[('select', 'VB'), ('the', 'DT'), ('files', 'NNS')]

これと同じ方法は、適切なデフォルトのタガーがある限り、英語以外の言語でも機能します。 nltk-trainertrain_tagger.pyと適切なコーパスを使用して独自のタガーをトレーニングできます。

28
Jacob

ヤコブの答えは的確です。ただし、それを拡張するには、ユニグラム以上のものが必要な場合があります。

たとえば、次の3つの文について考えてみます。

select the files
use the select function on the sockets
the select was good

ここでは、「select」という単語がそれぞれ動詞、形容詞、名詞として使用されています。ユニグラムタガーはこれをモデル化できません。 2つのケースが同じ先行単語(つまり「the」)を共有しているため、バイグラムタガーでさえそれを処理できません。このケースを正しく処理するには、トリグラムタガーが必要です。

import nltk.tag, nltk.data
from nltk import Word_tokenize
default_tagger = nltk.data.load(nltk.tag._POS_TAGGER)

def evaluate(tagger, sentences):
    good,total = 0,0.
    for sentence,func in sentences:
        tags = tagger.tag(nltk.Word_tokenize(sentence))
        print tags
        good += func(tags)
        total += 1
    print 'Accuracy:',good/total

sentences = [
    ('select the files', lambda tags: ('select', 'VB') in tags),
    ('use the select function on the sockets', lambda tags: ('select', 'JJ') in tags and ('use', 'VB') in tags),
    ('the select was good', lambda tags: ('select', 'NN') in tags),
]

train_sents = [
    [('select', 'VB'), ('the', 'DT'), ('files', 'NNS')],
    [('use', 'VB'), ('the', 'DT'), ('select', 'JJ'), ('function', 'NN'), ('on', 'IN'), ('the', 'DT'), ('sockets', 'NNS')],
    [('the', 'DT'), ('select', 'NN'), ('files', 'NNS')],
]

tagger = nltk.TrigramTagger(train_sents, backoff=default_tagger)
evaluate(tagger, sentences)
#model = tagger._context_to_tag

NLTKの NgramTagger を使用して、任意の数のn-gramを使用してタガーをトレーニングできますが、通常、トリグラムの後でパフォーマンスが大幅に向上することはありません。

22
Cerin

ヤコブの答えを参照してください。

それ以降のバージョン(少なくともnltk 3.2)ではnltk.tag._POS_TAGGER 存在しない。デフォルトのタガーは通常、nltk_data/taggers /ディレクトリにダウンロードされます。例:

>>> import nltk
>>> nltk.download('maxent_treebank_pos_tagger') 

使い方は以下の通りです。

>>> import nltk.tag, nltk.data
>>> tagger_path = '/path/to/nltk_data/taggers/maxent_treebank_pos_tagger/english.pickle'
>>> default_tagger = nltk.data.load(tagger_path)
>>> model = {'select': 'VB'}
>>> tagger = nltk.tag.UnigramTagger(model=model, backoff=default_tagger)

参照: PythonでNLTK POSタガーを使用してPOSタグ付けを行う方法

6
Bud

バドの答えは正しいです。また、 このリンク によると、

nltk_dataパッケージが正しくインストールされている場合、NLTKはそれらがシステム上のどこにあるかを認識しているため、絶対パスを渡す必要はありません。

つまり、あなたはただ言うことができます

tagger_path = '/path/to/nltk_data/taggers/maxent_treebank_pos_tagger/english.pickle'
default_tagger = nltk.data.load(tagger_path)
2
noobalert