Pythonでスキップグラムを計算するにはどうすればいいですか? 質問する

Pythonでスキップグラムを計算するにはどうすればいいですか? 質問する

Akスキップグラムは、すべての ngram のスーパーセットである ngram であり、各 (ki )skipgram は (ki)==0 (0 個の skip グラムを含む) までです。では、これらの skipgram を 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)次の出力を生成します。

[['これ'、'起こった'、'もっと']、['起こった'、'もっと'、'または']、['もっと'、'または'、'もっと']、['または'、'もっと']、['または'、'もっと']、['起こった'、'もっと'、'または'、'もっと']、['または'、'もっと']、['または'、'もっと']、['もっと'、'または'、'もっと']、['もっと'、'または'、'もっと']、['もっと']、['もっと']、['もっと']、['もっと']、['もっと']、['もっと']、['もっと']、['もっと']、['もっと']

ここにリストされているコードも正しい出力を生成しません。https://github.com/heaven00/skipgram/blob/master/skipgram.py

skipgram_ndarray("What is your name") を印刷すると、次のようになります: ['What,is', 'is,your', 'your,name', 'name,', 'What,your', 'is,name']

名前はユニグラムです!

ベストアンサー1

からOP がリンクしている次の文字列:

戦闘継続中に反乱軍が死亡

収量:

2-skip-bi-grams = {反乱軍が殺害された、反乱軍が進行中、反乱軍が進行中、殺害された、戦闘中に殺害された、戦闘中、戦闘中、戦闘継続中}

2 スキップ トライグラム = {反乱軍が殺害された、反乱軍が進行中に殺害された、反乱軍が戦闘中に殺害された、反乱軍が進行中、反乱軍が戦闘中、反乱軍が戦闘中、進行中に殺害された、戦闘中に殺害された、進行中の戦闘で殺害された、進行中の戦闘中、進行中の戦闘中}。

NLTKのngramsコードに若干の修正を加えて(https://github.com/nltk/nltk/blob/develop/nltk/util.py#L383):

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

論文の例に一致するように doctest を実行してみましょう。

>>> 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) # i.e. '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、現在のトークンとコンテキスト + スキップ ウィンドウのスキップグラムを取得します。

>>> [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')]

その後、次の単語に進みます。

おすすめ記事