Как вычислить skipgrams в python?

K skipgram – это ngram, которая является надмножеством всех ngrams и каждого (ki) skipgram до (ki) == 0 (который включает в себя 0 графов пропуска). Итак, как эффективно вычислить эти skipgrams в python?

Ниже приведен код, который я пробовал, но он не работает так, как ожидалось:

<pre> input_list = ['all', 'this', 'happened', 'more', 'or', 'less'] def find_skipgrams(input_list, N,K): bigram_list = [] nlist=[] K=1 for k in range(K+1): for i in range(len(input_list)-1): if i+k+1<len(input_list): nlist=[] for j in range(N+1): if i+k+j+1<len(input_list): nlist.append(input_list[i+k+j+1]) bigram_list.append(nlist) return bigram_list </pre> 

Вышеупомянутый код не отображается правильно, но print find_skipgrams(['all', 'this', 'happened', 'more', 'or', 'less'],2,1) дает следующий результат

[['это', 'произошло', 'больше'], ['произошло', 'больше', 'или'], ['больше', 'или', 'меньше'], ['или', 'less '], [' less '], ['used', 'more', 'or'], ['more', 'or', 'less'], ['or', 'less'], ['less '], ['Меньше']]

Код, указанный здесь, также не дает корректного вывода: https://github.com/heaven00/skipgram/blob/master/skipgram.py

print skipgram_ndarray («Ваше имя») дает: ['What, is', 'is, your', 'your, name', 'name,', 'What, your', 'is, name']

имя – это униграмма!

  • Как проверить, пуст ли пул в Python?
  • Вызывается неправильный интерпретатор python
  • как рекурсивно перебирать теги XML в Python с помощью ElementTree?
  • Почему Python Vincent отображает визуализацию, не отображает данные из Data Frame?
  • Перерыв или выход из заявления «с»?
  • Python: как увеличить экземпляр экземпляра POINTER
  • как преобразовать дату строки в формат datetime в python?
  • Вычислить среднее из каждых x строк в таблице и создать новую таблицу
  • 5 Solutions collect form web for “Как вычислить skipgrams в python?”

    Из документа, который ссылки OP, следующая строка:

    Повстанцы погибли в ходе боевых действий

    Урожайность:

    2-skip-bi-grams = {повстанцы убиты, повстанцы, боевики продолжаются, убиты, убивают, убивают, убивают боевые действия, продолжают сражаться, продолжаются боевые действия}

    2-skip-tri-grams = {повстанцы убиты, повстанцы убиты, боевики убили боевые действия, повстанцы в продолжающихся боевиках в боевых действиях, боевики продолжали сражаться, убивали в продолжающихся, убитых в бою, убивали продолжающиеся боевые действия в ходе продолжающихся боевых действий}.

    С незначительной модификацией кода ngrams ( ngrams ):

     from itertools import chain, combinations import copy from nltk.util import ngrams def pad_sequence(sequence, n, pad_left=False, pad_right=False, pad_symbol=None): if pad_left: sequence = chain((pad_symbol,) * (n-1), sequence) if pad_right: sequence = chain(sequence, (pad_symbol,) * (n-1)) return sequence def skipgrams(sequence, n, k, pad_left=False, pad_right=False, pad_symbol=None): sequence_length = len(sequence) sequence = iter(sequence) sequence = pad_sequence(sequence, n, pad_left, pad_right, pad_symbol) if sequence_length + pad_left + pad_right < k: raise Exception("The length of sentence + padding(s) < skip") if n < k: raise Exception("Degree of Ngrams (n) needs to be bigger than skip (k)") history = [] nk = n+k # Return point for recursion. if nk < 1: return # If n+k longer than sequence, reduce k by 1 and recur elif nk > sequence_length: for ng in skipgrams(list(sequence), n, k-1): yield ng while nk > 1: # Collects the first instance of n+k length history history.append(next(sequence)) nk -= 1 # Iterative drop first item in history and picks up the next # while yielding skipgrams for each iteration. for item in sequence: history.append(item) current_token = history.pop(0) # Iterates through the rest of the history and # pick out all combinations the n-1grams for idx in list(combinations(range(len(history)), n-1)): ng = [current_token] for _id in idx: ng.append(history[_id]) yield tuple(ng) # Recursively yield the skigrams for the rest of seqeunce where # len(sequence) < n+k for ng in list(skipgrams(history, n, k-1)): yield ng 

    Давайте сделаем некоторое досье, чтобы соответствовать примеру в документе:

     >>> two_skip_bigrams = list(skipgrams(text, n=2, k=2)) [('Insurgents', 'killed'), ('Insurgents', 'in'), ('Insurgents', 'ongoing'), ('killed', 'in'), ('killed', 'ongoing'), ('killed', 'fighting'), ('in', 'ongoing'), ('in', 'fighting'), ('ongoing', 'fighting')] >>> two_skip_trigrams = list(skipgrams(text, n=3, k=2)) [('Insurgents', 'killed', 'in'), ('Insurgents', 'killed', 'ongoing'), ('Insurgents', 'killed', 'fighting'), ('Insurgents', 'in', 'ongoing'), ('Insurgents', 'in', 'fighting'), ('Insurgents', 'ongoing', 'fighting'), ('killed', 'in', 'ongoing'), ('killed', 'in', 'fighting'), ('killed', 'ongoing', 'fighting'), ('in', 'ongoing', 'fighting')] 

    Но обратите внимание, что если n+k > len(sequence) , это даст те же эффекты, что и skipgrams(sequence, n, k-1) (это не ошибка, это функция безопасности), например

     >>> three_skip_trigrams = list(skipgrams(text, n=3, k=3)) >>> three_skip_fourgrams = list(skipgrams(text, n=4, k=3)) >>> four_skip_fourgrams = list(skipgrams(text, n=4, k=4)) >>> four_skip_fivegrams = list(skipgrams(text, n=5, k=4)) >>> >>> print len(three_skip_trigrams), three_skip_trigrams 10 [('Insurgents', 'killed', 'in'), ('Insurgents', 'killed', 'ongoing'), ('Insurgents', 'killed', 'fighting'), ('Insurgents', 'in', 'ongoing'), ('Insurgents', 'in', 'fighting'), ('Insurgents', 'ongoing', 'fighting'), ('killed', 'in', 'ongoing'), ('killed', 'in', 'fighting'), ('killed', 'ongoing', 'fighting'), ('in', 'ongoing', 'fighting')] >>> print len(three_skip_fourgrams), three_skip_fourgrams 5 [('Insurgents', 'killed', 'in', 'ongoing'), ('Insurgents', 'killed', 'in', 'fighting'), ('Insurgents', 'killed', 'ongoing', 'fighting'), ('Insurgents', 'in', 'ongoing', 'fighting'), ('killed', 'in', 'ongoing', 'fighting')] >>> print len(four_skip_fourgrams), four_skip_fourgrams 5 [('Insurgents', 'killed', 'in', 'ongoing'), ('Insurgents', 'killed', 'in', 'fighting'), ('Insurgents', 'killed', 'ongoing', 'fighting'), ('Insurgents', 'in', 'ongoing', 'fighting'), ('killed', 'in', 'ongoing', 'fighting')] >>> print len(four_skip_fivegrams), four_skip_fivegrams 1 [('Insurgents', 'killed', 'in', 'ongoing', 'fighting')] 

    Это позволяет n == k но он запрещает n > k как показано в строках:

     if n < k: raise Exception("Degree of Ngrams (n) needs to be bigger than skip (k)") 

    Для понимания, давайте попробуем понять «мистическую» линию:

     for idx in list(combinations(range(len(history)), n-1)): pass # Do something 

    Учитывая список уникальных предметов, комбинации производят это:

     >>> from itertools import combinations >>> x = [0,1,2,3,4,5] >>> list(combinations(x,2)) [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)] 

    А так как индексы списка токенов всегда уникальны, например

     >>> sent = ['this', 'is', 'a', 'foo', 'bar'] >>> current_token = sent.pop(0) # ie 'this' >>> range(len(sent)) [0,1,2,3] 

    Можно вычислить возможные комбинации (без замены) диапазона:

     >>> n = 3 >>> list(combinations(range(len(sent)), n-1)) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] 

    Если мы переведем индексы обратно в список токенов:

     >>> [tuple(sent[id] for id in idx) for idx in combinations(range(len(sent)), 2) [('is', 'a'), ('is', 'foo'), ('is', 'bar'), ('a', 'foo'), ('a', 'bar'), ('foo', 'bar')] 

    Затем мы конкатенируем с current_token , получаем скипграммы для текущего токена и контекстного окна + skip:

     >>> [tuple([current_token]) + tuple(sent[id] for id in idx) for idx in combinations(range(len(sent)), 2)] [('this', 'is', 'a'), ('this', 'is', 'foo'), ('this', 'is', 'bar'), ('this', 'a', 'foo'), ('this', 'a', 'bar'), ('this', 'foo', 'bar')] 

    Поэтому после этого мы переходим к следующему слову.

    Вот более чистая реализация от @jnothman из репозитория NLTK:

     import itertools from nltk import ngrams def skipgrams(sequence, n, k): for ngram in ngrams(sequence, n + k, pad_right=True): head = ngram[:1] tail = ngram[1:] for skip_tail in itertools.combinations(tail, n - 1): if skip_tail[-1] is None: continue yield head + skip_tail 

    Хотя это будет полностью связано с вашим кодом и отложить его до внешней библиотеки; вы можете использовать Colibri Core ( https://proycon.github.io/colibri-core ) для извлечения проб. Это библиотека, написанная специально для эффективного извлечения n-грамма и пропусков из больших текстовых корпусов. База кода находится в C ++ (для скорости / эффективности), но доступна привязка Python.

    Вы по праву отметили эффективность, поскольку извлечение skipgram быстро показывает экспоненциальную сложность, что может быть не большой проблемой, если вы передаете только предложение, как в вашем input_list , но становится проблематичным, если вы отпустите его на большие данные корпуса. Чтобы смягчить это, вы можете установить такие параметры, как порог возникновения, или потребовать, чтобы каждый пропуск skipgram был заполнен не менее чем на х различных n-граммов.

     import colibricore #Prepare corpus data (will be encoded for efficiency) corpusfile_plaintext = "somecorpus.txt" #input, one sentence per line encoder = colibricore.ClassEncoder() encoder.build(corpusfile_plaintext) corpusfile = "somecorpus.colibri.dat" #corpus output classfile = "somecorpus.colibri.cls" #class encoding output encoder.encodefile(corpusfile_plaintext,corpusfile) encoder.save(classfile) #Set options for skipgram extraction (mintokens is the occurrence threshold, maxlength maximum ngram/skipgram length) colibricore.PatternModelOptions(mintokens=2,maxlength=8,doskipgrams=True) #Instantiate an empty pattern model model = colibricore.UnindexedPatternModel() #Train the model on the encoded corpus file (this does the skipgram extraction) model.train(corpusfile, options) #Load a decoder so we can view the output decoder = colibricore.ClassDecoder(classfile) #Output all skipgrams for pattern in model: if pattern.category() == colibricore.Category.SKIPGRAM: print(pattern.tostring(decoder)) 

    На веб-сайте есть более обширный учебник Python обо всем этом.

    Отказ от ответственности: я являюсь автором Colibri Core

    Обратитесь к этому за полной информацией.

    Следующий пример уже упоминался в нем о его использовании и работает как шарм!

     >>>sent = "Insurgents killed in ongoing fighting".split() >>>list(skipgrams(sent, 2, 2)) [('Insurgents', 'killed'), ('Insurgents', 'in'), ('Insurgents', 'ongoing'), ('killed', 'in'), ('killed', 'ongoing'), ('killed', 'fighting'), ('in', 'ongoing'), ('in', 'fighting'), ('ongoing', 'fighting')] 

    Как об использовании чужой реализации https://github.com/heaven00/skipgram/blob/master/skipgram.py , где k = skip_size и n=ngram_order :

     def skipgram_ndarray(sent, k=1, n=2): """ This is not exactly a vectorized version, because we are still using a for loop """ tokens = sent.split() if len(tokens) < k + 2: raise Exception("REQ: length of sentence > skip + 2") matrix = np.zeros((len(tokens), k + 2), dtype=object) matrix[:, 0] = tokens matrix[:, 1] = tokens[1:] + [''] result = [] for skip in range(1, k + 1): matrix[:, skip + 1] = tokens[skip + 1:] + [''] * (skip + 1) for index in range(1, k + 2): temp = matrix[:, 0] + ',' + matrix[:, index] map(result.append, temp.tolist()) limit = (((k + 1) * (k + 2)) / 6) * ((3 * n) - (2 * k) - 6) return result[:limit] def skipgram_list(sent, k=1, n=2): """ Form skipgram features using list comprehensions """ tokens = sent.split() tokens_n = ['''tokens[index + j + {0}]'''.format(index) for index in range(n - 1)] x = '(tokens[index], ' + ', '.join(tokens_n) + ')' query_part1 = 'result = [' + x + ' for index in range(len(tokens))' query_part2 = ' for j in range(1, k+2) if index + j + n < len(tokens)]' exec(query_part1 + query_part2) return result 
    Python - лучший язык программирования в мире.