15

我正在研究一种解决方案,将高棉(柬埔寨语)的长行拆分为单个单词(UTF-8 格式)。高棉语不使用单词之间的空格。有一些解决方案,但它们还远远不够(这里这里),而且这些项目已经被搁置了。

这是需要拆分的高棉示例行(它们可能比这更长):



创建一个分割高棉语单词的可行解决方案的目标是双重的:它将鼓励那些使用高棉传统(非 Unicode)字体的人转换为 Unicode(这有很多好处),并且它将允许导入传统高棉字体转换成 Unicode 以便快速与拼写检查器一起使用(而不是手动检查和拆分单词,这对于大型文档可能需要很长时间)。

我不需要 100% 的准确率,但速度很重要(特别是因为需要拆分成高棉语单词的行可能很长)。我愿意接受建议,但目前我有大量正确拆分的高棉语词库(带有不间断空格),并且我创建了一个单词概率字典文件(frequency.csv)用作字典分词器。

我在这里找到了这个使用Viterbi 算法的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 代码:文本分割:基于字典的分词,但运行速度太慢而无法使用(因为我的单词概率字典有超过 100k 的术语......)。

这是 Python 中的另一个选项,来自Detect most possible words from text without spaces / combine words

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 的新手,我对所有真正的编程(网站之外)都很陌生,所以请多多包涵。有没有人有任何他们认为会很好的选择?

4

3 回答 3

3

ICU 库(具有Python和 Java 绑定)有一个DictionaryBasedBreakIterator类可用于此目的。

于 2011-02-01T11:25:39.673 回答
1

带有示例的 pythonfilesaveas似乎在整个输入字符串 ( for i in xrange(1, len(text) + 1)) 中进行递归,将最好的结果填充到cache整个过程中;在每个潜在的单词处,它开始查看下一个单词(依次查看之后的单词,依此类推),如果第二个单词看起来不太好,它就不会保存那个特定的单词. 感觉就像 O(N!) 运行时,其中N 是输入字符串的长度。

超级聪明,但除了简单的任务外,其他任何事情都可能很糟糕。你听过的最长的高棉词是什么?我希望<20个字符。

也许如果您一次向该示例输入 20 个字符,您可以将运行时间保持在接近合理的水平。输入前 20 个字符,删除第一个单词,然后输入剩余的输入。如果您重新使用缓存,它可能会做一些愚蠢的事情,比如在此过程中存储部分单词。

在完全不同的情况下,有多少个高棉词是由两个或多个合法的高棉词连接而成的?(类似于“penknife”或“basketball”)如果不是太多,创建一组字典可能是有意义的,按单词长度分隔,从单词映射到使用概率。

比如说,最长的高棉词是 14 个字符长;将输入的 14 个字符输入len14字典,存储概率。输入 13 个字符len13,存储概率。输入 12 个字符……一直到 1 个len1。然后选择概率最高的解释,保存单词,去掉那么多字符,然后再试一次。

因此,对于像“I”和“Image”这样的输入,它不会严重失败,也许更长的输入应该有自动膨胀的概率?

感谢这个有趣的问题;)我不知道这样的语言,很酷。

于 2011-02-01T11:42:34.380 回答
1

我认为这是一个好主意,因为它是。

我建议你,当你有一些经验时,你添加一些规则,可以非常具体,例如,取决于之前的单词,取决于之后的单词,取决于周围的单词,取决于当前之前的单词序列这个词,只是为了列举最常见的。您可以在文件 data/contextualrulefile 中找到一组规则 gposttl.sf.net 项目,这是一个 pos 标记项目。

规则应该在统计评估完成后使用,它们进行一些微调,可以显着提高准确性。

于 2011-02-02T21:16:41.767 回答