Жизнеспособное решение для разложения слов кхмера?

Я работаю над решением расщепления длинных строк кхмера (камбоджийского языка) на отдельные слова (в UTF-8). Кхмер не использует пробелы между словами. Есть несколько решений, но они далеки от адекватных (здесь и здесь), и эти проекты упали на обочину.

Вот примерная строка кхмера, которую нужно разбить (они могут быть длиннее этого):

ច ូ រ សរសើរ ដល់ ទ្រង់ ដែល ទ្រង់ បាន ប្រទាន ការ ទ ាំ ង អស់ ន ោះ មកដល់ រ ូ ប អ្នក ដោយ ព្រ ោះ អង្គ ព្រ ះ យេ ស ៊ូ វ ហើយ ដែល អ្នក មិនអាច រក ការ ទ ាំ ង អស់ ន ោះ ដោយសារ ការប្រព្រឹត្ត របស់ អ្នក ឡើយ.

Цель создания жизнеспособного решения, разделяющего кхмерские слова, двояка: она будет поощрять тех, кто использовал шрифты Khmer legacy (не Unicode) для преобразования в Unicode (который имеет много преимуществ), и это позволит использовать устаревшие кхмерские шрифты для импорта в Юникод для быстрого использования проверки орфографии (а не для ручного прохождения и разделения слов, которые с большим документом могут занимать очень много времени).

Мне не нужна точность 100%, но скорость важна (тем более, что линия, которая должна быть разделена на кхмерские слова, может быть довольно длинной). Я открыт для предложений, но в настоящее время у меня есть большой корпус из кхмерских слов, которые правильно разделены (с неразрывным пространством), и я создал файл словаря вероятностного словаря (frequency.csv) для использования в качестве словаря для разделитель слов.

Я нашел этот код python здесь, который использует алгоритм Витерби, и он предположительно бежит быстро.

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 от автора этой страницы: Сегментация текста: словарное разбиение слов, но оно слишком медленно, чтобы быть полезным (потому что словарь слов с вероятностью слова имеет более 100 тыс. терминов...).

И вот еще один вариант в 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, и я действительно новичок во всех реальных программах (за пределами веб-сайтов), поэтому, пожалуйста, несите меня. У кого-нибудь есть какие-то варианты, которые, по их мнению, будут хорошо работать?

Ответы

Ответ 1

Библиотека ICU (Python и привязки Java) имеет DictionaryBasedBreakIterator, который можно использовать для этого.

Ответ 2

Питон с примером filesaveas, по-видимому, рекурсирует по всей входной строке (for i in xrange(1, len(text) + 1)), набирая лучшие результаты в cache по пути; при каждом потенциальном слове он затем начинает смотреть на следующее слово (которое, в свою очередь, будет смотреть на слово после этого и т.д.), и если это второе слово выглядит не очень хорошо, оно не спасет тот конкретный, Это похоже на O (N!) Время выполнения, где N - длина входной строки.

Супер умный, но, вероятно, ужасный для чего угодно, кроме простых задач. Какое самое длинное кхмерское слово у вас? Я надеюсь, 20 символов.

Возможно, если вы подаете ввод в этот пример по 20 символов за раз, вы можете удержать время выполнения до чего-то подходящего. Подайте первые 20 символов, отсоедините первое слово, а затем подайте оставшийся вход. Если вы повторно используете кеш, он может сделать что-то глупое, как хранить частичные слова на этом пути.

На совершенно другом уровне, сколько кхмерских слов формируется путем объединения двух или более законных кхмерских слов? (аналогично "penknife" или "баскетболу" ). Если не слишком много, может возникнуть смысл создать набор словарей, разделенных по длине слова, сопоставление от слова к вероятности использования.

Скажем, самое длинное кхмерское слово - 14 символов; введите 14 символов ввода в словарь len14, сохраните вероятность. Подайте 13 символов в len13, сохраните вероятность. Подайте 12 символов... вплоть до 1 в len1. Затем выберите интерпретацию с наивысшей вероятностью, сохраните слово, отмените это количество символов и повторите попытку.

Таким образом, это не сильно ухудшит входные данные, такие как "I" и "Изображение", возможно, более длинные входы должны автоматически раздувать вероятности?

Спасибо за интересный вопрос;) Я не знал о таких языках, как это, довольно круто.

Ответ 3

Я думаю, что это хорошая идея, как есть.

Я предлагаю вам, когда у вас есть некоторый опыт работы с ним, вы добавляете некоторые правила, которые могут быть очень конкретными, например, в зависимости от слова раньше, в зависимости от слова после, в зависимости от окружающих слов, в зависимости от последовательности слов перед текущим словом, просто для перечисления наиболее часто встречающихся. Вы можете найти набор правил в проекте gposttl.sf.net, который является проектом пометки pos, в файле данных /contextualrulefile.

Правила должны использоваться ПОСЛЕ завершения оценки статистики, они делают точную настройку и могут значительно улучшить точность.