Бързо изчисляване на n-грам

Използвам NLTK за търсене на n-грами в корпус, но в някои случаи отнема много време. Забелязах, че изчисляването на n-грамове не е необичайна функция в други пакети (очевидно Haystack има някаква функционалност за това). Това означава ли, че има потенциално по-бърз начин за намиране на n-грами в моя корпус, ако изоставя NLTK? Ако е така, какво мога да използвам, за да ускоря нещата?


person Trindaz    schedule 29.09.2011    source източник
comment
Още четиво за интересуващите се: packages.python.org/Whoosh/ngrams.html   -  person Trindaz    schedule 29.09.2011
comment
Свързан въпрос: stackoverflow.com/ въпроси/21883108/   -  person dmcc    schedule 21.04.2014


Отговори (3)


Тъй като не посочихте дали искате n-грами на ниво дума или знак, просто ще приема първото, без загуба на общост.

Предполагам също, че започвате със списък от токени, представени от низове. Това, което можете лесно да направите, е сами да напишете извличане на n-грам.

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-грам (добавете го към 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
person Fred Foo    schedule 29.09.2011
comment
По-новите версии на Cython разпознават Python за изрази и ги ускоряват, ако е възможно. Освен това имате търсене на метод във вътрешната итерация. дефинирането на 'tokenjoiner= .join' извън цикъла и замяната на вътрешния .join трябва да ускори нещата. - person rocksportrocker; 29.09.2011
comment
и можете да пренапишете вътрешния ред с count.get(....) +=1 въведете друга променлива за избягване на търсене на метод. - person rocksportrocker; 29.09.2011

Може да намерите питонична, елегантна и бърза функция за генериране на ngram, използваща zip и splat (*) оператор тук:

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

За n-грами на ниво символ можете да използвате следната функция

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