22

私のプロジェクトの 1 つで英語の小さなサブセットを解析する必要があり、(1 レベルの) 機能構造を持つ文脈自由文法 ( example ) として記述されており、それを効率的に行う必要があります。

現在、正しい出力を生成するNLTKのパーサーを使用していますが、非常に遅いです。約 450 のかなりあいまいな非語彙規則と 50 万の語彙エントリからなる私の文法では、単純な文の解析には、結果のツリーの数にもよりますが、2 秒から 30 秒かかります。レキシアル エントリは、パフォーマンスにほとんどまたはまったく影響を与えません。

もう 1 つの問題は、最初に (25MB) 文法と語彙集をロードするのに 1 分ほどかかることです。

私が文献で見つけたものから、そのような文法 (Earley または CKY) を解析するために使用されるアルゴリズムの実行時間は、文法のサイズに対して線形であり、入力トークン リストのサイズに対して 3 次でなければなりません。私の NLTK の経験から、文法の絶対的なサイズではなく、あいまいさがパフォーマンスに最も悪影響を与えることが分かります。

そこで、NLTK に代わる CFG パーサーを探しています。私はPLYを検討してきましたが、私の場合に必要な CFG の機能構造をサポートしているかどうかはわかりません。私が見た例では、文法を指定するだけでなく、多くの手続き型解析を行っているようです。機能構造体をサポートし、宣言型文法を使用する PLY の例を誰かに見せてもらえますか?

また、必要なことを効率的に実行できる他のパーサーでも問題ありません。Python インターフェイスが望ましいですが、絶対に必要というわけではありません。

4

8 に答える 8

15

ぜひ、Pyparsingをご覧ください。これは、私が遭遇した構文解析の最も Pythonic な実装であり、純粋に学術的な観点から見た優れた設計です。

ANTLRJavaCCの両方を使用して、地元の大学で翻訳者とコンパイラの理論を教えました。どちらも優れた成熟したものですが、Python プロジェクトでは使用しません。

とはいえ、プログラミング言語とは異なり、自然言語は構文よりもセマンティクスに重点を置いているため、既存の解析ツールの学習曲線をスキップして、自作の (トップダウン、バックトラック、無制限の先読み) 字句解析器とパーサーを使用し、解析されたがあいまいな自然言語の文が何を意味するかを理解するコードを書くことに多くの時間を費やしています。

于 2010-12-28T01:50:37.573 に答える
2

C++ で書かれた非常に効率的な PCFG パーサーである bitpar の使用をお勧めします。そのためのシェルベースの Python ラッパーを作成しました。https://github.com/andreasvc/eodop/blob/master/bitpar.pyを参照してください。

于 2011-03-21T15:17:34.243 に答える
2

ツーリングはさておき...

同じ言語を定義する無限の文法があることを理論から覚えているかもしれません。文法を分類し、特定の言語に対してどちらが「正規」または「最小」であるかを判断するための基準がありますが、最終的には、「最良の」文法は、手元のタスクとツールにとってより便利なものです ( CFG の LL および LR 文法への変換?)

そうすれば、英語の文を解析するのに膨大な辞書は必要ないでしょう。ドイツ語やラテン語 (またはスペイン語) などの言語の単語について知られることはたくさんありますが、恣意的であいまいな英語ではそうではありません。文の構造にたどり着くために必要なキーワードだけを含む小さな辞書で済むはずです。とにかく、選択した文法は、そのサイズに関係なく、ツールが直接使用できる方法でキャッシュできます (つまり、文法の解析をスキップできます)。

それを考えると、他の誰かがすでに取り組んでいる、より単純なパーサーを調べるのは良い考えかもしれません。文献には何千ものそれらがあるに違いありません。さまざまなアプローチを研究することで、自分自身のアプローチを評価できるようになり、他の人のアプローチを採用するようになる可能性があります。

最後に、すでに述べたように、自然言語の解釈は、構文解析よりも人工知能に関するものです。構造が意味を決定し、意味が構造を決定するため、両方を同時に扱う必要があります。80 年代以降の文献で私が見たアプローチは、さまざまな専門エージェントに「黒板」に対して問題を解決する試みをさせるというものです。そのアプローチでは、構文解析と意味解析が同時に行われます。

于 2010-12-28T14:40:09.080 に答える
2

限られた語彙コマンドの解析に pyparsing を使用しましたが、投稿された例に対処する pyparsing の上に小さなフレームワークがあります。

from pyparsing import *

transVerb, transVerbPlural, transVerbPast, transVerbProg = (Forward() for i in range(4))
intransVerb, intransVerbPlural, intransVerbPast, intransVerbProg = (Forward() for i in range(4))
singNoun,pluralNoun,properNoun = (Forward() for i in range(3))
singArticle,pluralArticle = (Forward() for i in range(2))
verbProg = transVerbProg | intransVerbProg
verbPlural = transVerbPlural | intransVerbPlural

for expr in (transVerb, transVerbPlural, transVerbPast, transVerbProg,
            intransVerb, intransVerbPlural, intransVerbPast, intransVerbProg,
            singNoun, pluralNoun, properNoun, singArticle, pluralArticle):
    expr << MatchFirst([])

def appendExpr(e1, s):
    c1 = s[0]
    e2 = Regex(r"[%s%s]%s\b" % (c1.upper(), c1.lower(), s[1:]))
    e1.expr.exprs.append(e2)

def makeVerb(s, transitive):
    v_pl, v_sg, v_past, v_prog = s.split()
    if transitive:
        appendExpr(transVerb, v_sg)
        appendExpr(transVerbPlural, v_pl)
        appendExpr(transVerbPast, v_past)
        appendExpr(transVerbProg, v_prog)
    else:
        appendExpr(intransVerb, v_sg)
        appendExpr(intransVerbPlural, v_pl)
        appendExpr(intransVerbPast, v_past)
        appendExpr(intransVerbProg, v_prog)

def makeNoun(s, proper=False):
    if proper:
        appendExpr(properNoun, s)
    else:
        n_sg,n_pl = (s.split() + [s+"s"])[:2]
        appendExpr(singNoun, n_sg)
        appendExpr(pluralNoun, n_pl)

def makeArticle(s, plural=False):
    for ss in s.split():
        if not plural:
            appendExpr(singArticle, ss)
        else:
            appendExpr(pluralArticle, ss)

makeVerb("disappear disappears disappeared disappearing", transitive=False)
makeVerb("walk walks walked walking", transitive=False)
makeVerb("see sees saw seeing", transitive=True)
makeVerb("like likes liked liking", transitive=True)

makeNoun("dog")
makeNoun("girl")
makeNoun("car")
makeNoun("child children")
makeNoun("Kim", proper=True)
makeNoun("Jody", proper=True)

makeArticle("a the")
makeArticle("this every")
makeArticle("the these all some several", plural=True)

transObject = (singArticle + singNoun | properNoun | Optional(pluralArticle) + pluralNoun | verbProg | "to" + verbPlural)
sgSentence = (singArticle + singNoun | properNoun) + (intransVerb | intransVerbPast | (transVerb | transVerbPast) + transObject)
plSentence = (Optional(pluralArticle) + pluralNoun) + (intransVerbPlural | intransVerbPast | (transVerbPlural |transVerbPast) + transObject)

sentence = sgSentence | plSentence


def test(s):
    print s
    try:
        print sentence.parseString(s).asList()
    except ParseException, pe:
        print pe

test("Kim likes cars")
test("The girl saw the dog")
test("The dog saw Jody")
test("Kim likes walking")
test("Every girl likes dogs")
test("All dogs like children")
test("Jody likes to walk")
test("Dogs like walking")
test("All dogs like walking")
test("Every child likes Jody")

版画:

Kim likes cars
['Kim', 'likes', 'cars']
The girl saw the dog
['The', 'girl', 'saw', 'the', 'dog']
The dog saw Jody
['The', 'dog', 'saw', 'Jody']
Kim likes walking
['Kim', 'likes', 'walking']
Every girl likes dogs
['Every', 'girl', 'likes', 'dogs']
All dogs like children
['All', 'dogs', 'like', 'children']
Jody likes to walk
['Jody', 'likes', 'to', 'walk']
Dogs like walking
['Dogs', 'like', 'walking']
All dogs like walking
['All', 'dogs', 'like', 'walking']
Every child likes Jody
['Every', 'child', 'likes', 'Jody']

語彙を増やすと、これは遅くなる可能性があります。50万のエントリー?妥当な機能語彙は 5 ~ 6,000 語程度であると考えました。そして、処理できる文の構造はかなり制限されます。自然言語は NLTK の目的です。

于 2010-12-28T10:38:47.557 に答える
1

これには少し遅れますが、次の2つのオプションがあります。

Sparkは、Pythonで記述されたEarleyパーサーです。

ElkhoundはC++で記述されたGLRパーサーですElkhoundはBisonのような構文を使用します

于 2011-01-02T19:35:29.240 に答える
1

ANTLR は、私が知っている Java 用の最高のパーサー ジェネレーターだと思います。Jython が Python と Java の対話に良い方法を提供するかどうかはわかりません。

于 2010-12-28T01:08:37.580 に答える
0

PyPyで実行してみてください。はるかに高速になる可能性があります。

于 2010-12-28T02:46:29.437 に答える
0

それがPEG言語として表現できる場合(すべての CFG ができるとは思いませんが、おそらく多くの CFG ができるとは思いません)、packrat 解析実装を使用する場合は線形時間であると想定されるpyPEGを使用できます (ただし、メモリ使用量)。

長い間離れていた解析とコンパイルを再び研究し始めたばかりなので、経験はありませんが、この比較的最新の手法についての良い話題を読んでいます. YMMV。

于 2010-12-28T02:43:23.150 に答える