web-dev-qa-db-ja.com

Pythonを使用したNグラムの計算

次のようなテキストを含むテキストファイルのUnigram、BiGrams、Trigramを計算する必要がありました。

「嚢胞性線維症は、米国だけで30,000人の子供と若い成人に影響しますThe New England Journal of Medicineの今週号に掲載された2つの研究のうち、

Python=で開始し、次のコードを使用しました。

#!/usr/bin/env python
# File: n-gram.py
def N_Gram(N,text):
NList = []                      # start with an empty list
if N> 1:
    space = " " * (N-1)         # add N - 1 spaces
    text = space + text + space # add both in front and back
# append the slices [i:i+N] to NList
for i in range( len(text) - (N - 1) ):
    NList.append(text[i:i+N])
return NList                    # return the list
# test code
for i in range(5):
print N_Gram(i+1,"text")
# more test code
nList = N_Gram(7,"Here is a lot of text to print")
for ngram in iter(nList):
print '"' + ngram + '"'

http://www.daniweb.com/software-development/python/threads/39109/generated-n-grams-from-a-Word

しかし、CYSTICとFIBROSISまたはCYSTIC FIBROSISのように単語間で必要な場合は、Word内のすべてのn-gramに対して機能します。誰かが私がこれを達成する方法について私を助けることができますか?

21
gran_profaci

入力がx = "a b c d"のようなスペースで区切られた単語を含む文字列であると仮定すると、次の関数を使用できます(編集:より完全なソリューションについては最後の関数を参照してください):

def ngrams(input, n):
    input = input.split(' ')
    output = []
    for i in range(len(input)-n+1):
        output.append(input[i:i+n])
    return output

ngrams('a b c d', 2) # [['a', 'b'], ['b', 'c'], ['c', 'd']]

それらを文字列に戻したい場合は、次のように呼び出すことができます。

[' '.join(x) for x in ngrams('a b c d', 2)] # ['a b', 'b c', 'c d']

最後に、それは物事を合計に要約しないので、入力が'a a a a'だった場合、それらを辞書にカウントアップする必要があります:

for g in (' '.join(x) for x in ngrams(input, 2)):
    grams.setdefault(g, 0)
    grams[g] += 1

これらすべてを1つの最終関数にまとめると、次のようになります。

def ngrams(input, n):
   input = input.split(' ')
   output = {}
   for i in range(len(input)-n+1):
       g = ' '.join(input[i:i+n])
       output.setdefault(g, 0)
       output[g] += 1
    return output

ngrams('a a a a', 2) # {'a a': 3}
29
dave mankoff

これからの短いPythonesqueソリューション blog

def find_ngrams(input_list, n):
  return Zip(*[input_list[i:] for i in range(n)])

使用法:

>>> input_list = ['all', 'this', 'happened', 'more', 'or', 'less']
>>> find_ngrams(input_list, 1)
[('all',), ('this',), ('happened',), ('more',), ('or',), ('less',)]
>>> find_ngrams(input_list, 2)
[('all', 'this'), ('this', 'happened'), ('happened', 'more'), ('more', 'or'), ('or', 'less')]
>>> find_ngrams(input_list, 3))
[('all', 'this', 'happened'), ('this', 'happened', 'more'), ('happened', 'more', 'or'), ('more', 'or', 'less')]
35

NLTK(Natural Language Toolkit)を使用し、関数を使用してテキストをリストにトークン化(分割)し、バイグラムとトライグラムを見つけます。

import nltk
words = nltk.Word_tokenize(my_text)
my_bigrams = nltk.bigrams(words)
my_trigrams = nltk.trigrams(words)
25
Spaceghost

Scikitと呼ばれるpythonにもう1つの興味深いモジュールがあります。これがコードです。これは、特定の範囲で指定されたすべてのグラムを取得するのに役立ちます。

from sklearn.feature_extraction.text import CountVectorizer 
text = "this is a foo bar sentences and i want to ngramize it"
vectorizer = CountVectorizer(ngram_range=(1,6))
analyzer = vectorizer.build_analyzer()
print analyzer(text)

出力は

[u'this', u'is', u'foo', u'bar', u'sentences', u'and', u'want', u'to', u'ngramize', u'it', u'this is', u'is foo', u'foo bar', u'bar sentences', u'sentences and', u'and want', u'want to', u'to ngramize', u'ngramize it', u'this is foo', u'is foo bar', u'foo bar sentences', u'bar sentences and', u'sentences and want', u'and want to', u'want to ngramize', u'to ngramize it', u'this is foo bar', u'is foo bar sentences', u'foo bar sentences and', u'bar sentences and want', u'sentences and want to', u'and want to ngramize', u'want to ngramize it', u'this is foo bar sentences', u'is foo bar sentences and', u'foo bar sentences and want', u'bar sentences and want to', u'sentences and want to ngramize', u'and want to ngramize it', u'this is foo bar sentences and', u'is foo bar sentences and want', u'foo bar sentences and want to', u'bar sentences and want to ngramize', u'sentences and want to ngramize it']

ここでは、1〜6の範囲で指定されたすべてのグラムが表示されます。countVectorizerというメソッドを使用しています。これが link です。

9
Gunjan

collections.dequeを使用:

from collections import deque
from itertools import islice

def ngrams(message, n=1):
    it = iter(message.split())
    window = deque(islice(it, n), maxlen=n)
    yield Tuple(window)
    for item in it:
        window.append(item)
        yield Tuple(window)

...または、リスト内包表記として1行で実行できます。

n = 2
message = "Hello, how are you?".split()
myNgrams = [message[i:i+n] for i in range(len(message) - n)]
3
Joel Cornett

効率が問題であり、複数の異なるn-gramを作成する必要がある場合、次のコードを使用することを検討します(フランクの優れた答えに基づいて構築します)。

from itertools import chain

def n_grams(seq, n=1):
    """Returns an iterator over the n-grams given a list_tokens"""
    shift_token = lambda i: (el for j,el in enumerate(seq) if j>=i)
    shifted_tokens = (shift_token(i) for i in range(n))
    Tuple_ngrams = Zip(*shifted_tokens)
    return Tuple_ngrams # if join in generator : (" ".join(i) for i in Tuple_ngrams)

def range_ngrams(list_tokens, ngram_range=(1,2)):
    """Returns an itirator over all n-grams for n in range(ngram_range) given a list_tokens."""
    return chain(*(n_grams(list_tokens, i) for i in range(*ngram_range)))

使用法 :

>>> input_list = input_list = 'test the ngrams generator'.split()
>>> list(range_ngrams(input_list, ngram_range=(1,3)))
[('test',), ('the',), ('ngrams',), ('generator',), ('test', 'the'), ('the', 'ngrams'), ('ngrams', 'generator'), ('test', 'the', 'ngrams'), ('the', 'ngrams', 'generator')]

〜NLTKと同じ速度:

import nltk
%%timeit
input_list = 'test the ngrams interator vs nltk '*10**6
nltk.ngrams(input_list,n=5)
# 7.02 ms ± 79 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
input_list = 'test the ngrams interator vs nltk '*10**6
n_grams(input_list,n=5)
# 7.01 ms ± 103 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
input_list = 'test the ngrams interator vs nltk '*10**6
nltk.ngrams(input_list,n=1)
nltk.ngrams(input_list,n=2)
nltk.ngrams(input_list,n=3)
nltk.ngrams(input_list,n=4)
nltk.ngrams(input_list,n=5)
# 7.32 ms ± 241 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
input_list = 'test the ngrams interator vs nltk '*10**6
range_ngrams(input_list, ngram_range=(1,6))
# 7.13 ms ± 165 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1
Yann Dubois

投稿は古いものですが、ほとんどのNgram作成ロジックを1つの投稿に含めることができるように、ここで私の答えに言及しようと思いました。

PythonにはTextBlobという名前の何かがあります。 NLTKと非常に簡単に似たngramを作成します。

以下は、理解を容易にするためのコードスニペットとその出力です。

sent = """This is to show the usage of Text Blob in Python"""
blob = TextBlob(sent)
unigrams = blob.ngrams(n=1)
bigrams = blob.ngrams(n=2)
trigrams = blob.ngrams(n=3)

出力は次のとおりです。

unigrams
[WordList(['This']),
 WordList(['is']),
 WordList(['to']),
 WordList(['show']),
 WordList(['the']),
 WordList(['usage']),
 WordList(['of']),
 WordList(['Text']),
 WordList(['Blob']),
 WordList(['in']),
 WordList(['Python'])]

bigrams
[WordList(['This', 'is']),
 WordList(['is', 'to']),
 WordList(['to', 'show']),
 WordList(['show', 'the']),
 WordList(['the', 'usage']),
 WordList(['usage', 'of']),
 WordList(['of', 'Text']),
 WordList(['Text', 'Blob']),
 WordList(['Blob', 'in']),
 WordList(['in', 'Python'])]

trigrams
[WordList(['This', 'is', 'to']),
 WordList(['is', 'to', 'show']),
 WordList(['to', 'show', 'the']),
 WordList(['show', 'the', 'usage']),
 WordList(['the', 'usage', 'of']),
 WordList(['usage', 'of', 'Text']),
 WordList(['of', 'Text', 'Blob']),
 WordList(['Text', 'Blob', 'in']),
 WordList(['Blob', 'in', 'Python'])]

それと同じくらい簡単です。

これには、TextBlobによって行われているものがさらにあります。詳細については、このドキュメントをご覧ください- https://textblob.readthedocs.io/en/dev/

1
JKC

nltkはngramをネイティブでサポートしています

「n」はngramサイズですex:n = 3はトライグラム用です

from nltk import ngrams

def ngramize(texts, n):
    output=[]
    for text in texts:
        output += ngrams(text,n)
    return output
1
r11