私は、Python で順次パターン マッチングのアルゴリズムを実装する必要があるという状況に陥っています。何時間も検索しても、インターネット上で機能するライブラリ/スニペットが見つかりません。
問題定義:
関数 sequential_pattern_match を実装します
入力: トークン (順序付けられた文字列のコレクション)
出力: タプルのリスト、各タプル = (トークンの任意のサブコレクション、タグ)
ドメインの専門家が、通常は正規表現を使用して一致ルールを定義します
テスト (トークン) -> タグまたはなし
例:
入力: [「シンガポール」、「Python」、「ユーザー」、「グループ」、「は」、「ここ」]
出力: [(["シンガポール", "Python", "ユーザー", "グループ"], "組織"), ("ある", 'O'), ("ここ", 'O')]
「O」は一致しないことを意味します。
競合解決規則:
- 最初に表示される一致が優先されます。たとえば、「シンガポールの不動産販売」の場合、資産として「シンガポールの不動産」、イベントとして「不動産の販売」という 2 つの競合する一致が可能である場合、最初のものが使用されます。
- 長い一致は、短い一致よりも優先されます。たとえば、組織としての「Singapore Python User Group」は、場所としての「Singapore」+言語としての「Python」の個々の一致よりも優先されます。
アルゴリズムとデータ構造に関する私の専門知識により、これが私の実装です。
from itertools import ifilter, imap
MAX_PATTERN_LENGTH = 3
def test(tokens):
length = len(tokens)
if (length == 1):
if tokens[0] == "Nexium":
return "MEDICINE"
elif tokens[0] == "pain":
return "SYMPTOM"
elif (length == 2):
string = ' '.join(tokens)
if string == "Barium Swallow":
return "INTERVENTION"
elif string == "Swallow Test":
return "INTERVENTION"
else:
if ' '.join(tokens) == "pain in stomach":
return "SYMPTOM"
def _evaluate(tokens):
tag = test(tokens)
if tag:
return (tokens, tag)
elif len(tokens) == 1:
return (tokens, 'O')
def _splits(tokens):
return ((tokens[:i], tokens[i:]) for i in xrange(min(len(tokens), MAX_PATTERN_LENGTH), 0, -1))
def sequential_pattern_match(tokens):
return ifilter(bool, imap(_halves_match, _splits(tokens))).next()
def _halves_match(halves):
result = _evaluate(halves[0])
if result:
return [result] + (halves[1] and sequential_pattern_match(halves[1]))
if __name__ == "__main__":
tokens = "I went to a clinic to do a Barium Swallow Test because I had pain in stomach after taking Nexium".split()
output = sequential_pattern_match(tokens)
slashTags = ' '.join(t + '/' + tag for tokens, tag in output for t in tokens)
print(slashTags)
assert slashTags == "I/O went/O to/O a/O clinic/O to/O do/O a/O Barium/INTERVENTION Swallow/INTERVENTION Test/O because/O I/O had/O pain/SYMPTOM in/SYMPTOM stomach/SYMPTOM after/O taking/O Nexium/MEDICINE"
import timeit
t = timeit.Timer(
'sequential_pattern_match("I went to a clinic to do a Barium Swallow Test because I had pain in stomach after taking Nexium".split())',
'from __main__ import sequential_pattern_match'
)
print(t.repeat(3, 10000))
もっと速くできないと思います。残念ながら、関数型で書かれており、Python には適していない可能性があります。オブジェクト指向または命令型スタイルでより高速な実装を実現できますか?
(注: C で実装した方が高速になると確信していますが、現時点では Python 以外の言語を使用する予定はありません)