【问题标题】:Fast n-gram calculation快速 n-gram 计算
【发布时间】:2011-11-27 07:43:44
【问题描述】:

我正在使用 NLTK 在语料库中搜索 n-gram,但在某些情况下需要很长时间。我注意到计算 n-gram 在其他包中并不少见(显然 Haystack 有一些功能)。这是否意味着如果我放弃 NLTK,在我的语料库中找到 n-gram 的方法可能更快?如果是这样,我可以用什么来加快速度?

【问题讨论】:

标签: python nlp nltk n-gram


【解决方案1】:
def generate_ngrams(words, ngram=2):
  return [words[i:i+ngram] for i in range(len(words)-ngram+1)]



sentence = "I really like python, it's pretty awesome."
words = sentence.split()
words

['I', 'really', 'like', 'python,', "it's", 'pretty', 'awesome.']


res = generate_ngrams(words, ngram=2)
res

[['I', 'really'],
 ['really', 'like'],
 ['like', 'python,'],
 ['python,', "it's"],
 ["it's", 'pretty'],
 ['pretty', 'awesome.']]


res = generate_ngrams(words, ngram=3)
res

[['I', 'really', 'like'],
 ['really', 'like', 'python,'],
 ['like', 'python,', "it's"],
 ['python,', "it's", 'pretty'],
 ["it's", 'pretty', 'awesome.']]


res = generate_ngrams(words, ngram=4)
res

[['I', 'really', 'like', 'python,'],
 ['really', 'like', 'python,', "it's"],
 ['like', 'python,', "it's", 'pretty'],
 ['python,', "it's", 'pretty', 'awesome.']]

【讨论】:

    【解决方案2】:

    对于字符级 n-gram,您可以使用以下函数

    def ngrams(text, n):
        n-=1
        return [text[i-n:i+1] for i,char in enumerate(text)][n:] 
    

    【讨论】:

      【解决方案3】:

      您可能会发现使用zip 和splat (*) 运算符here 的pythonic、优雅和快速的ngram 生成函数:

      def find_ngrams(input_list, n):
        return zip(*[input_list[i:] for i in range(n)])
      

      【讨论】:

        【解决方案4】:

        由于您没有说明您想要单词还是字符级别的 n-gram,我只是假设前者,但不失一般性。

        我还假设您从一个由字符串表示的标记列表开始。您可以轻松地自己编写 n-gram 提取。

        def ngrams(tokens, MIN_N, MAX_N):
            n_tokens = len(tokens)
            for i in xrange(n_tokens):
                for j in xrange(i+MIN_N, min(n_tokens, i+MAX_N)+1):
                    yield tokens[i:j]
        

        然后将 yield 替换为您要对每个 n-gram 采取的实际操作(将其添加到 dict,将其存储在数据库中,等等)以消除生成器开销。

        最后,如果实在不够快,把上面的转换成Cython,然后编译。使用defaultdict 代替yield 的示例:

        def ngrams(tokens, int MIN_N, int MAX_N):
            cdef Py_ssize_t i, j, n_tokens
        
            count = defaultdict(int)
        
            join_spaces = " ".join
        
            n_tokens = len(tokens)
            for i in xrange(n_tokens):
                for j in xrange(i+MIN_N, min(n_tokens, i+MAX_N)+1):
                    count[join_spaces(tokens[i:j])] += 1
        
            return count
        

        【讨论】:

        • 较新版本的 Cython 可以识别 Python 的语句并尽可能加快它们的速度。此外,您在内部迭代中有一个方法查找。在循环外定义 'tokenjoiner=" ".join' 并替换内部 " ".join 应该会加快速度。
        • 你可以用“count.get(....) +=1”重写内行,引入另一个var来避免方法查找。
        猜你喜欢
        • 2014-03-19
        • 2013-09-10
        • 1970-01-01
        • 1970-01-01
        • 2012-12-31
        • 1970-01-01
        • 1970-01-01
        • 2018-03-16
        • 1970-01-01
        相关资源
        最近更新 更多