Быстрый расчет 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/ questions / 21883108 /   -  person dmcc    schedule 21.04.2014


Ответы (3)


Поскольку вы не указали, нужны ли вам н-граммы на уровне слов или символов, я просто предполагаю первое без потери общности.

Я также предполагаю, что вы начинаете со списка токенов, представленных строками. Что вы можете легко сделать, так это написать извлечение 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 for и по возможности ускоряют их. Далее у вас есть поиск метода во внутренней итерации. определение '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