27

私は NLTK の本を読み進めていますが、適切な文法を構築するための自然な第一歩と思われる何かを行うことができないようです。

私の目標は、特定のテキスト コーパスの文法を構築することです。

(最初の質問: ゼロから文法を始めようとするべきですか、それとも定義済みの文法から始めるべきですか? 別の文法から始めるべきである場合、英語を始めるのに適した文法はどれですか?)

次の単純な文法があるとします。

simple_grammar = nltk.parse_cfg("""
S -> NP VP
PP -> P NP
NP -> Det N | Det N PP
VP -> V NP | VP PP
Det -> 'a' | 'A'
N -> 'car' | 'door'
V -> 'has'
P -> 'in' | 'for'
 """);

この文法は、次のような非常に単純な文を解析できます。

parser = nltk.ChartParser(simple_grammar)
trees = parser.nbest_parse("A car has a door")

次に、この文法を拡張して、他の名詞や動詞を含む文を処理したいと考えています。文法で手動で定義せずに、これらの名詞と動詞を文法に追加するにはどうすればよいですか?

たとえば、「車には車輪があります」という文を解析できるようにしたいとします。提供されているトークナイザーは、どの単語が動詞/名詞などであるかを魔法のように判断できることを知っています。トークナイザーの出力を使用して、「wheels」が名詞であることを文法に伝えるにはどうすればよいですか?

4

3 に答える 3

16

テキストに対して POS タガーを実行し、単語ではなく POS タグで機能するように文法を適応させることができます。

> text = nltk.word_tokenize("A car has a door")
['A', 'car', 'has', 'a', 'door']

> tagged_text = nltk.pos_tag(text)
[('A', 'DT'), ('car', 'NN'), ('has', 'VBZ'), ('a', 'DT'), ('door', 'NN')]

> pos_tags = [pos for (token,pos) in nltk.pos_tag(text)]
['DT', 'NN', 'VBZ', 'DT', 'NN']

> simple_grammar = nltk.parse_cfg("""
  S -> NP VP
  PP -> P NP
  NP -> Det N | Det N PP
  VP -> V NP | VP PP
  Det -> 'DT'
  N -> 'NN'
  V -> 'VBZ'
  P -> 'PP'
  """)

> parser = nltk.ChartParser(simple_grammar)
> tree = parser.parse(pos_tags)
于 2011-02-01T09:23:24.760 に答える
12

これは1年後のことですが、いくつかの考えを追加したかったのです。

取り組んでいるプロジェクトのために、たくさんの異なる文章を取り上げて品詞のタグを付けます。そこから、StompChicken が提案したように、タプル (単語、タグ) からタグを取り出し、それらのタグを「ターミナル」 (完全にタグ付けされた文を作成するときのツリーの下部ノード) として使用していました。

文法にはタグしかないため、頭の名詞「単語」を文法に引き込むことができないため、最終的には、これは名詞句で頭の名詞をマークしたいという私の欲求には合いません。

そのため、代わりに (単語、タグ) タプルのセットを使用してタグの辞書を作成し、そのタグを持つすべての単語をそのタグの値として使用しました。次に、この辞書を screen/grammar.cfg (文脈自由文法) ファイルに出力します。

私がそれを印刷するために使用するフォームは、文法ファイル ( ) をロードしてパーサーを設定することで完全に機能しますparser = nltk.load_parser('grammar.cfg')。生成される行の 1 つは次のようになります。

VBG -> "fencing" | "bonging" | "amounting" | "living" ... over 30 more words...

これで、私の文法は実際の単語を終端として持ち、同じタグを割り当てますnltk.tag_pos

これが、大規模なコーパスのタグ付けを自動化し、実際の単語を文法の終端として保持したい他の人に役立つことを願っています.

import nltk
from collections import defaultdict

tag_dict = defaultdict(list)

...
    """ (Looping through sentences) """

        # Tag
        tagged_sent = nltk.pos_tag(tokens)

        # Put tags and words into the dictionary
        for word, tag in tagged_sent:
            if tag not in tag_dict:
                tag_dict[tag].append(word)
            elif word not in tag_dict.get(tag):
                tag_dict[tag].append(word)

# Printing to screen
for tag, words in tag_dict.items():
    print tag, "->",
    first_word = True
    for word in words:
        if first_word:
            print "\"" + word + "\"",
            first_word = False
        else:
            print "| \"" + word + "\"",
    print ''
于 2012-08-02T15:18:32.913 に答える
11

解析はトリッキーな問題です。多くのことがうまくいかない可能性があります。

ここでは (少なくとも) 3 つのコンポーネント、トークナイザー、タガー、そして最後にパーサーが必要です。

まず、実行中のテキストをトークンのリストにトークン化する必要があります。これは、入力文字列を空白で分割するのと同じくらい簡単ですが、より一般的なテキストを解析する場合は、数字と句読点も処理する必要があり、これは重要です。たとえば、文末のピリオドはしばしば、それが付加されている単語の一部とはみなされませんが、略語を示すピリオドはしばしばそうです。

入力トークンのリストがある場合、タガーを使用して各単語の POS を決定し、それを使用して入力タグ シーケンスを明確にすることができます。これには主な利点が 2 つあります。1 つ目は、POS タガーがすでにこれを行っているため、あいまいな単語によって認可された代替仮説を考慮する必要がなくなるため、解析が高速化されることです。次に、未知の単語の処理が改善されます。それらの単語にタグを割り当てることによって、あなたの文法にない単語 (できれば正しいもの) を割り当てます。このようにパーサーとタガーを組み合わせることは一般的です。

POS タグは、文法の前終端を構成します。前終端は、プロダクションの左側であり、終端のみが右側です。つまり、N -> "house"、V -> "jump" など。N と V は前終端記号です。構文の文法、両側に非終端記号のみ、プロダクションとレキシカル プロダクション、1 つの非終端記号が 1 つの終端記号を使用することはかなり一般的です。ほとんどの場合、これは言語的に意味があり、ほとんどの CFG パーサーは文法がこの形式である必要があります。ただし、RHSes の任意の端末から非端末を含む「ダミー プロダクション」を作成することにより、この方法で任意の CFG を表すことができます。

タガーが出力するものよりも細かい粒度のタグ区別を文法で行いたい場合は、POS タグとプリターミナルの間に何らかのマッピングを行う必要があります。次に、タガーからの結果でチャートを初期化できます。各入力トークンにまたがる適切なカテゴリのパッシブ アイテム。悲しいことに、私は NTLK を知りませんが、これを行う簡単な方法があると確信しています。チャートがシードされると、解析は通常どおり継続でき、通常の方法で解析ツリーを (単語も含めて) 抽出できます。

ただし、ほとんどの実際のアプリケーションでは、自然言語は非常にあいまいであるため、パーサーがいくつかの異なる分析を返すことがあることがわかります。どのような種類のテキスト コーパスを解析しようとしているのかはわかりませんが、それが自然言語のようなものであれば、おそらく何らかの解析選択モデルを構築する必要があるでしょう。数百から数千の解析の範囲のサイズは、すべて文法と必要な正確な結果に依存します。このツリーバンクが与えられると、それに対応する PCFG を自動的に推測できます。PCFG は、解析ツリーをランク付けするための単純なモデルとして使用できます。

これはすべて自分で行うには大変な作業です。解析結果を何に使用していますか? NTLK の他のリソースや、StanfordParser や BerkeleyParser などの他のパッケージを参照しましたか?

于 2011-02-02T15:28:39.820 に答える