単語分割クメールのための実行可能なソリューション?
-
27-10-2019 - |
質問
私は、クメール(カンボジア語)の長い線を個々の単語(UTF-8)に分割するための解決策に取り組んでいます。 Khmerは単語間のスペースを使用しません。そこにはいくつかの解決策がありますが、それらは適切ではありません(ここ と ここ)、そしてそれらのプロジェクトは道端に落ちました。
ここに、分割する必要があるクメールのサンプルラインがあります(これよりも長くなる可能性があります):
ចូរសរសើរដល់ទ្រង់ដែលទ្រង់បានប្រទានការទាំងអស់នោះមកដល់រូបអ្នកដោយព្រោះអង្គព្រះយេស៊ូវ ហើយដែលអ្នកមិនអាចរកការទាំងអស់នោះដោយសារការប្រព្រឹត្តរបស់អ្នកឡើយ។
Khmerの単語を分割する実行可能なソリューションを作成するという目標は2つあります。それは、Khmer Legacy(Ununicode)フォントを使用した人がUnicode(多くの利点がある)に変換することを奨励し、Legacy Khmerフォントをインポートできるようになりますスペルチェッカーで迅速に使用するユニコードに(大きなドキュメントを使用して非常に長い時間がかかる可能性がある単語を手動で通過して分割するのではなく)。
100%の精度は必要ありませんが、速度は重要です(特に、クメール語に分割する必要があるラインはかなり長くなる可能性があるため)。私は提案を受け入れていますが、現在、正しく分割された(非壊れた空間で)正しく分割されたクメール語の大きなコーパスがあり、単語の確率辞書ファイル(freick.csv)を作成して、単語スプリッター。
このPythonコードを見つけました ここ それはを使用します viterbiアルゴリズム そして、それはおそらく速く実行されます。
import re
from itertools import groupby
def viterbi_segment(text):
probs, lasts = [1.0], [0]
for i in range(1, len(text) + 1):
prob_k, k = max((probs[j] * word_prob(text[j:i]), j)
for j in range(max(0, i - max_word_length), i))
probs.append(prob_k)
lasts.append(k)
words = []
i = len(text)
while 0 < i:
words.append(text[lasts[i]:i])
i = lasts[i]
words.reverse()
return words, probs[-1]
def word_prob(word): return dictionary.get(word, 0) / total
def words(text): return re.findall('[a-z]+', text.lower())
dictionary = dict((w, len(list(ws)))
for w, ws in groupby(sorted(words(open('big.txt').read()))))
max_word_length = max(map(len, dictionary))
total = float(sum(dictionary.values()))
また、このページの著者からソースJavaコードを使用してみました。 テキストセグメンテーション:辞書ベースの単語分割 しかし、それはあまりにも遅すぎて使用するには走りすぎていません(私のWord Probability Dictionaryには1万人以上の用語があります...)。
そして、ここにPythonの別のオプションがあります スペース /組み合わせた単語のないテキストから最も可能性の高い単語を検出する:
WORD_FREQUENCIES = {
'file': 0.00123,
'files': 0.00124,
'save': 0.002,
'ave': 0.00001,
'as': 0.00555
}
def split_text(text, word_frequencies, cache):
if text in cache:
return cache[text]
if not text:
return 1, []
best_freq, best_split = 0, []
for i in xrange(1, len(text) + 1):
word, remainder = text[:i], text[i:]
freq = word_frequencies.get(word, None)
if freq:
remainder_freq, remainder = split_text(
remainder, word_frequencies, cache)
freq *= remainder_freq
if freq > best_freq:
best_freq = freq
best_split = [word] + remainder
cache[text] = (best_freq, best_split)
return cache[text]
print split_text('filesaveas', WORD_FREQUENCIES, {})
--> (1.3653e-08, ['file', 'save', 'as'])
私はPythonに関してはNewbeeであり、私はすべての本当のプログラミング(Webサイト以外)に本当に新しいので、私と一緒に我慢してください。誰かが彼らがうまく機能すると感じる選択肢はありますか?
解決
ICUライブラリ( Python とjava bindings)はaを持っています dictionarybasedbreakiterator これに使用できるクラス。
他のヒント
例のあるPython filesaveas
入力文字列全体を再発するように見えます(for i in xrange(1, len(text) + 1)
)、最良の結果をに詰めます cache
途中。潜在的な単語ごとに、それ それから を見始めます 次 単語(その後の単語などを見ます)、そしてその2番目の単語があまり良く見えない場合、それはその特定のものを保存しません。これ 感じます o(n!)ランタイムのように、nは入力文字列の長さです。
非常に賢いですが、おそらく単純なタスク以外のものにとっては恐ろしいことでしょう。あなたが持っている最も長いクメールの言葉は何ですか? 20文字未満のキャラクターを願っています。
たぶん、その例20文字に一度に入力を与えた場合、ランタイムを合理的に近づいているものまで減らすことができます。最初の20枚の文字に供給し、最初の単語を吸い取り、残りの入力に供給します。キャッシュを再利用すると、途中で部分的な単語のような愚かなことをするかもしれません。
まったく異なるタックでは、2つ以上の合法的な単語を連結することにより、いくつのクメール語が形成されますか? (「ペンナイフ」や「バスケットボール」に似ています)あまり多すぎない場合は、単語の長さによって分離された辞書のセットを作成し、単語から使用の確率にマッピングするのが理にかなっています。
たとえば、最長のクメール語は14枚の長さです。入力の14文字をフィードします len14
辞書、確率を保存します。 13文字を与えます len13
, 、確率を保存します。 12文字でフィード... 1までずっと1まで len1
. 。次に、最も高い確率で解釈を選択し、単語を保存し、その多くのキャラクターを取り除き、再試行します。
したがって、「I」対「画像」のような入力についてはひどく失敗することはありません。
楽しい質問をありがとう;)私はこのような言語を知りませんでした、かなりクールです。
これは良い考えだと思います。
あなたがそれを経験したとき、あなたはいくつかのルールを追加することをお勧めします、あなたはいくつかのルールを追加します、例えば以前の単語に応じて、周囲の単語に応じて、現在の単語の前の単語のシーケンスに応じて、非常に具体的なことができます。単語、最も頻繁なものを列挙するためだけです。 gposttl.sf.netプロジェクトでは、ファイルデータ/ContextualRuleFileで、POSTタグ付けプロジェクトである一連のルールを見つけることができます。
統計評価が終了した後、ルールを使用する必要があり、微調整を行い、精度を著しく改善することができます。