Я использую NLTK для поиска n-граммов в корпусе, но в некоторых случаях он занимает очень много времени. Я заметил, что вычисление n-граммов не является необычной особенностью в других пакетах (очевидно, у Haystack есть некоторые функции для этого). Означает ли это потенциально более быстрый способ поиска n-граммов в моем корпусе, если я откажусь от NLTK? Если да, то что я могу использовать для ускорения работы?
Быстрый расчет n-грамм
Ответ 1
Поскольку вы не указали, хотите ли вы использовать 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
Ответ 2
Вы можете найти питонную, элегантную и быструю функцию генерации ngram, используя zip
и оператор splat (*) здесь:
def find_ngrams(input_list, n):
return zip(*[input_list[i:] for i in range(n)])
Ответ 3
Для n-граммов уровня персонажа вы можете использовать следующую функцию
def ngrams(text, n):
n-=1
return [text[i-n:i+1] for i,char in enumerate(text)][n:]