有人知道使用动态编程进行分词的示例算法吗?

时间:2009-11-23 07:43:05

标签: dynamic word iteration text-segmentation

如果你搜索谷歌的分词,实际上没有很好的描述,我只是想完全理解动态编程算法找到一个字符串分割成单个单词的过程。有没有人知道一个对分词问题有很好描述的地方,或者有人能形容它吗?

分词基本上只是取一串字符并决定将它分成单词的位置,如果你不知道并使用动态编程,它会考虑一些子问题。使用递归这很简单,但我无法在网上找到任何在线查找迭代算法的描述,因此如果有人有任何示例或者可以提供一个很棒的算法。 / p>

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

我将假设我们不是在谈论这里的小问题(即不仅仅是在空格中拆分字符串,因为那只是一个基本的标记化问题) - 而是我们在讨论有些东西没有明确的单词分隔符,因此我们必须“猜测”字符串 - >单词的最佳匹配 - 例如,一组连接单词没有空格的情况,比如改变这个:

lotsofwordstogether

进入这个:

lots, of, words, together

在这种情况下,动态编程方法可能是计算出一个表,其中一个维度对应于序列中的M个字,另一个维度对应于每个N个字符在输入字符串中。然后,您为表格的每个方格填写的值是“如果我们在位置M结束(或替代,开始)N单词,我们可以获得的最佳匹配分数。

答案 1 :(得分:2)

Python wordsegment module有这样的算法。它使用递归和memoization来实现动态编程。

该来源位于Github,此处是相关摘录:

def segment(text):
    "Return a list of words that is the best segmenation of `text`."

    memo = dict()

    def search(text, prev='<s>'):
        if text == '':
            return 0.0, []

        def candidates():
            for prefix, suffix in divide(text):
                prefix_score = log10(score(prefix, prev))

                pair = (suffix, prefix)
                if pair not in memo:
                    memo[pair] = search(suffix, prefix)
                suffix_score, suffix_words = memo[pair]

                yield (prefix_score + suffix_score, [prefix] + suffix_words)

        return max(candidates())

    result_score, result_words = search(clean(text))

    return result_words

请注意memo如何缓存search的来电,后者又会从candidates中选择最大值。

答案 2 :(得分:0)

这是迭代风格的以下解决方案(主要思想是将问题分解为:在输入的特定范围内找到具有正好1,2,3..n分段单词的分段。对不起,如果有任何小问题索引错误,这些天我的脑袋非常模糊。但这对你来说是一个迭代的解决方案。):

static List<String> connectIter(List<String> tokens) {

    // use instead of array, the key is of the from 'int int'
    Map<String, List<String>> data = new HashMap<String, List<String>>();

    int n = tokens.size();

    for(int i = 0; i < n; i++) {
        String str = concat(tokens, i, n);
        if (dictContains(str)) {
            data.put(1 + " " + i, Collections.singletonList(str));
        }
    }

    for (int i = 2; i <= n; i++) {
        for (int start = 0; i < n; start++) {
            List<String> solutions = new ArrayList<String>();
            for (int end = start + 1; end <= n - i + 1; end++) {
                String firstPart = concat(tokens, start, end);

                if (dictContains(firstPart)) {
                    List<String> partialSolutions = data.get((i - 1) + " " + end);
                    if (partialSolutions != null) {
                        List<String> newSolutions = new ArrayList<>();
                        for (String onePartialSolution : partialSolutions) {
                            newSolutions.add(firstPart + " "
                                    + onePartialSolution);
                        }
                        solutions.addAll(newSolutions);
                    }
                }
            }

            if (solutions.size() != 0) {
                data.put(i + " " + start, solutions);
            }
        }
    }

    List<String> ret = new ArrayList<String>();
    for(int i = 1; i <= n; i++) { // can be optimized to run with less iterations
        List<String> solutions = data.get(i + " " + 0);
        if (solutions != null) {
            ret.addAll(solutions);
        }
    }

    return ret;
}


static private String concat(List<String> tokens, int low, int hi) {
    StringBuilder sb = new StringBuilder();
    for(int i = low; i < hi; i++) {
        sb.append(tokens.get(i));
    }
    return sb.toString();
}