n- अजगर अजगर में, चार, पाँच, छह ग्राम?


137

मैं एक पाठ को एन-ग्राम में विभाजित करने का एक तरीका ढूंढ रहा हूं। आम तौर पर मैं कुछ ऐसा करूंगा:

import nltk
from nltk import bigrams
string = "I really like python, it's pretty awesome."
string_bigrams = bigrams(string)
print string_bigrams

मुझे पता है कि nltk केवल बिगग्राम और ट्रिगर्स प्रदान करता है, लेकिन क्या मेरे टेक्स्ट को चार-ग्राम, पांच-ग्राम या सौ-ग्राम में विभाजित करने का कोई तरीका है?

धन्यवाद!


क्या आप पाठ को शब्द या वर्ण द्वारा n आकार के समूहों में विभाजित करना चाहते हैं? क्या आप इस बात का उदाहरण दे सकते हैं कि उपरोक्त के लिए क्या आउटपुट दिखना चाहिए?
क्रिसप्रॉसर जूल

4
कभी भी nltk नहीं किया है, लेकिन ऐसा लगता है कि एक फ़ंक्शन है ingramsजिसका दूसरा पैरामीटर आपके इच्छित एनग्राम की डिग्री है। है इस nltk प्रयोग कर रहे हैं के संस्करण? यहां तक कि नहीं करता है, तो, यहाँ है स्रोत संपादित करें: वहाँ है ngramsऔर ingramsवहाँ में, ingramsएक जनरेटर जा रहा है।
ब्रायन

इस सूत्र के अंतर्गत एक उत्तर भी है जो उपयोगी हो सकता है: stackoverflow.com/questions/7591258/fast-n-gram-calacle
क्रिसपॉसर

जवाबों:


212

अन्य उपयोगकर्ताओं द्वारा दिए गए महान देशी अजगर आधारित उत्तर। लेकिन यहाँ nltkदृष्टिकोण (बस मामले में, ओपी को nltkपुस्तकालय में पहले से मौजूद क्या है) को रोकने के लिए दंडित किया जाता है ।

एक एनग्राम मॉड्यूल है जिसका उपयोग लोग शायद ही कभी करते हैं nltk। ऐसा नहीं है क्योंकि यह एनग्राम पढ़ना मुश्किल है, लेकिन एनग्राम पर एक मॉडल बेस को प्रशिक्षण देना जहां n> 3 बहुत डेटा स्पार्सिटी का परिणाम होगा।

from nltk import ngrams

sentence = 'this is a foo bar sentences and i want to ngramize it'

n = 6
sixgrams = ngrams(sentence.split(), n)

for grams in sixgrams:
  print grams

4
वर्ण ngrams के लिए, कृपया यह भी देखें: stackoverflow.com/questions/22428020/…
alvas

क्या txt जैसे किसी संपूर्ण दस्तावेज़ की जांच करने के लिए N-gram का उपयोग करने का कोई तरीका है? मैं पायथन से परिचित नहीं हूं इसलिए मुझे नहीं पता कि क्या यह एक txt फ़ाइल खोल सकता है और फिर एन-ग्राम विश्लेषण का उपयोग कर सकता है?
मैय्यी

1
क्या कोई इस बात पर टिप्पणी कर सकता है कि सटीकता का परीक्षण कैसे किया जाए sixgrams?
LYu

64

मुझे आश्चर्य है कि यह अभी तक नहीं दिखा है:

In [34]: sentence = "I really like python, it's pretty awesome.".split()

In [35]: N = 4

In [36]: grams = [sentence[i:i+N] for i in xrange(len(sentence)-N+1)]

In [37]: for gram in grams: print gram
['I', 'really', 'like', 'python,']
['really', 'like', 'python,', "it's"]
['like', 'python,', "it's", 'pretty']
['python,', "it's", 'pretty', 'awesome.']

यही कारण है कि पहला उत्तर आवृत्ति की गिनती और टुपल रूपांतरण को घटाता है।
ब्रायन

हालांकि यह एक समझ के रूप में इसे फिर से देखना अच्छा है।
ब्रायन

@amirouche: अच्छी पकड़। बग रिपोर्ट के लिए धन्यवाद। अब यह तय हो गया है
इंस्पेक्टरगेट 4

16

केवल nltk टूल का उपयोग करना

from nltk.tokenize import word_tokenize
from nltk.util import ngrams

def get_ngrams(text, n ):
    n_grams = ngrams(word_tokenize(text), n)
    return [ ' '.join(grams) for grams in n_grams]

उदाहरण आउटपुट

get_ngrams('This is the simplest text i could think of', 3 )

['This is the', 'is the simplest', 'the simplest text', 'simplest text i', 'text i could', 'i could think', 'could think of']

आदेश को केवल स्वरूप में ngrams रखने के लिए निकालें ' '.join


15

यहाँ n- ग्राम करने के लिए एक और सरल तरीका है

>>> from nltk.util import ngrams
>>> text = "I am aware that nltk only offers bigrams and trigrams, but is there a way to split my text in four-grams, five-grams or even hundred-grams"
>>> tokenize = nltk.word_tokenize(text)
>>> tokenize
['I', 'am', 'aware', 'that', 'nltk', 'only', 'offers', 'bigrams', 'and', 'trigrams', ',', 'but', 'is', 'there', 'a', 'way', 'to', 'split', 'my', 'text', 'in', 'four-grams', ',', 'five-grams', 'or', 'even', 'hundred-grams']
>>> bigrams = ngrams(tokenize,2)
>>> bigrams
[('I', 'am'), ('am', 'aware'), ('aware', 'that'), ('that', 'nltk'), ('nltk', 'only'), ('only', 'offers'), ('offers', 'bigrams'), ('bigrams', 'and'), ('and', 'trigrams'), ('trigrams', ','), (',', 'but'), ('but', 'is'), ('is', 'there'), ('there', 'a'), ('a', 'way'), ('way', 'to'), ('to', 'split'), ('split', 'my'), ('my', 'text'), ('text', 'in'), ('in', 'four-grams'), ('four-grams', ','), (',', 'five-grams'), ('five-grams', 'or'), ('or', 'even'), ('even', 'hundred-grams')]
>>> trigrams=ngrams(tokenize,3)
>>> trigrams
[('I', 'am', 'aware'), ('am', 'aware', 'that'), ('aware', 'that', 'nltk'), ('that', 'nltk', 'only'), ('nltk', 'only', 'offers'), ('only', 'offers', 'bigrams'), ('offers', 'bigrams', 'and'), ('bigrams', 'and', 'trigrams'), ('and', 'trigrams', ','), ('trigrams', ',', 'but'), (',', 'but', 'is'), ('but', 'is', 'there'), ('is', 'there', 'a'), ('there', 'a', 'way'), ('a', 'way', 'to'), ('way', 'to', 'split'), ('to', 'split', 'my'), ('split', 'my', 'text'), ('my', 'text', 'in'), ('text', 'in', 'four-grams'), ('in', 'four-grams', ','), ('four-grams', ',', 'five-grams'), (',', 'five-grams', 'or'), ('five-grams', 'or', 'even'), ('or', 'even', 'hundred-grams')]
>>> fourgrams=ngrams(tokenize,4)
>>> fourgrams
[('I', 'am', 'aware', 'that'), ('am', 'aware', 'that', 'nltk'), ('aware', 'that', 'nltk', 'only'), ('that', 'nltk', 'only', 'offers'), ('nltk', 'only', 'offers', 'bigrams'), ('only', 'offers', 'bigrams', 'and'), ('offers', 'bigrams', 'and', 'trigrams'), ('bigrams', 'and', 'trigrams', ','), ('and', 'trigrams', ',', 'but'), ('trigrams', ',', 'but', 'is'), (',', 'but', 'is', 'there'), ('but', 'is', 'there', 'a'), ('is', 'there', 'a', 'way'), ('there', 'a', 'way', 'to'), ('a', 'way', 'to', 'split'), ('way', 'to', 'split', 'my'), ('to', 'split', 'my', 'text'), ('split', 'my', 'text', 'in'), ('my', 'text', 'in', 'four-grams'), ('text', 'in', 'four-grams', ','), ('in', 'four-grams', ',', 'five-grams'), ('four-grams', ',', 'five-grams', 'or'), (',', 'five-grams', 'or', 'even'), ('five-grams', 'or', 'even', 'hundred-grams')]

1
Nltk.word_tokenize () फ़ंक्शन का उपयोग करने के लिए nltk.download ('पंकट') करना पड़ा। इसके अलावा परिणामों को प्रिंट करने के लिए सूची (<genrator_object>) का उपयोग करके जेनरेटर ऑब्जेक्ट को बिगोग्राम, ट्रिगर्स और फोरग्राम की सूची में बदलना पड़ा।
bhatman

11

परिदृश्य के लिए लोग पहले से ही बहुत अच्छे से उत्तर दे चुके हैं, जहाँ आपको बिग्रेड्स या ट्रिगर्स की आवश्यकता होती है, लेकिन यदि आपको उस वाक्य के लिए हर आवश्यकता की आवश्यकता होती है , तो आप इसका उपयोग कर सकते हैंnltk.util.everygrams

>>> from nltk.util import everygrams

>>> message = "who let the dogs out"

>>> msg_split = message.split()

>>> list(everygrams(msg_split))
[('who',), ('let',), ('the',), ('dogs',), ('out',), ('who', 'let'), ('let', 'the'), ('the', 'dogs'), ('dogs', 'out'), ('who', 'let', 'the'), ('let', 'the', 'dogs'), ('the', 'dogs', 'out'), ('who', 'let', 'the', 'dogs'), ('let', 'the', 'dogs', 'out'), ('who', 'let', 'the', 'dogs', 'out')]

यह सुनिश्चित करें कि आपके पास ट्रिगर्स के मामले में एक सीमा है जहां अधिकतम लंबाई 3 होनी चाहिए फिर आप इसे निर्दिष्ट करने के लिए max_len परम का उपयोग कर सकते हैं।

>>> list(everygrams(msg_split, max_len=2))
[('who',), ('let',), ('the',), ('dogs',), ('out',), ('who', 'let'), ('let', 'the'), ('the', 'dogs'), ('dogs', 'out')]

आप बस जो भी चार ग्राम, चार ग्राम, पांच ग्राम, छह या सौ ग्राम प्राप्त करने के लिए max_len परम को संशोधित कर सकते हैं।

पिछले उल्लिखित समाधानों को उपर्युक्त समाधान को लागू करने के लिए संशोधित किया जा सकता है लेकिन यह समाधान उससे बहुत आगे है।

आगे पढ़ने के लिए यहां क्लिक करें

और जब आपको बस एक विशिष्ट चना जैसे कि आश्रम या ट्रायग्राम आदि की आवश्यकता हो तो आप nltk.util.ngrams का उपयोग कर सकते हैं जैसा कि माहासन के उत्तर में वर्णित है।


6

आप आसानी से इस का उपयोग करने के लिए अपने खुद के समारोह कोड़ा कर सकते हैं itertools:

from itertools import izip, islice, tee
s = 'spam and eggs'
N = 3
trigrams = izip(*(islice(seq, index, None) for index, seq in enumerate(tee(s, N))))
list(trigrams)
# [('s', 'p', 'a'), ('p', 'a', 'm'), ('a', 'm', ' '),
# ('m', ' ', 'a'), (' ', 'a', 'n'), ('a', 'n', 'd'),
# ('n', 'd', ' '), ('d', ' ', 'e'), (' ', 'e', 'g'),
# ('e', 'g', 'g'), ('g', 'g', 's')]

1
क्या आप izip(*(islice(seq, index, None) for index, seq in enumerate(tee(s, N))))मुझे समझा सकते हैं, मैं इसे बहुत नहीं समझता।
टॉमाज़सटिलजकोविक

4

अजगर के बिलिन के साथ बीग्राम्स बनाने के लिए एक अधिक सुरुचिपूर्ण दृष्टिकोण zip()। बस मूल स्ट्रिंग को सूची में परिवर्तित करें split(), फिर सूची को एक बार सामान्य रूप से और एक बार एक तत्व द्वारा ऑफसेट करें।

string = "I really like python, it's pretty awesome."

def find_bigrams(s):
    input_list = s.split(" ")
    return zip(input_list, input_list[1:])

def find_ngrams(s, n):
  input_list = s.split(" ")
  return zip(*[input_list[i:] for i in range(n)])

find_bigrams(string)

[('I', 'really'), ('really', 'like'), ('like', 'python,'), ('python,', "it's"), ("it's", 'pretty'), ('pretty', 'awesome.')]

2

मैं nltk के साथ कभी नहीं निपटा लेकिन कुछ छोटे वर्ग के प्रोजेक्ट के हिस्से के रूप में एन-ग्राम था। यदि आप स्ट्रिंग में होने वाली सभी एन-ग्राम की आवृत्ति को ढूंढना चाहते हैं, तो यहां ऐसा करने का एक तरीका है। Dआपको अपने N- शब्दों का हिस्टोग्राम देगा।

D = dict()
string = 'whatever string...'
strparts = string.split()
for i in range(len(strparts)-N): # N-grams
    try:
        D[tuple(strparts[i:i+N])] += 1
    except:
        D[tuple(strparts[i:i+N])] = 1

collections.Counter(tuple(strparts[i:i+N]) for i in xrange(len(strparts)-N))कोशिश को छोड़कर तेजी से काम करेंगे
इंस्पेक्टरगेट 4

2

चार_ग्राम के लिए यह पहले से ही एनएलटीके में है , यहाँ एक कोड है जो आपको इस ओर मदद कर सकता है:

 from nltk.collocations import *
 import nltk
 #You should tokenize your text
 text = "I do not like green eggs and ham, I do not like them Sam I am!"
 tokens = nltk.wordpunct_tokenize(text)
 fourgrams=nltk.collocations.QuadgramCollocationFinder.from_words(tokens)
 for fourgram, freq in fourgrams.ngram_fd.items():  
       print fourgram, freq

मुझे उम्मीद है यह मदद करेगा।


2

आप sklearn.feature_extraction.text.CountVectorizer का उपयोग कर सकते हैं :

import sklearn.feature_extraction.text # FYI http://scikit-learn.org/stable/install.html
ngram_size = 4
string = ["I really like python, it's pretty awesome."]
vect = sklearn.feature_extraction.text.CountVectorizer(ngram_range=(ngram_size,ngram_size))
vect.fit(string)
print('{1}-grams: {0}'.format(vect.get_feature_names(), ngram_size))

आउटपुट:

4-grams: [u'like python it pretty', u'python it pretty awesome', u'really like python it']

आप ngram_sizeकिसी भी सकारात्मक पूर्णांक पर सेट कर सकते हैं । यानी आप एक पाठ को चार-ग्राम, पाँच-ग्राम या सौ-ग्राम में विभाजित कर सकते हैं।


2

यदि दक्षता एक समस्या है और आपको कई अलग-अलग एन-ग्राम (एक सौ तक, जैसा कि आप कहते हैं) का निर्माण करना होगा, लेकिन आप शुद्ध अजगर का उपयोग करना चाहते हैं जो मैं करूंगा:

from itertools import chain

def n_grams(seq, n=1):
    """Returns an itirator over the n-grams given a listTokens"""
    shiftToken = lambda i: (el for j,el in enumerate(seq) if j>=i)
    shiftedTokens = (shiftToken(i) for i in range(n))
    tupleNGrams = zip(*shiftedTokens)
    return tupleNGrams # if join in generator : (" ".join(i) for i in tupleNGrams)

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

उपयोग:

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

~ एनएलटीके के समान गति:

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, ngramRange=(1,6))
# 7.13 ms ± 165 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

मेरे पिछले उत्तर से रिपॉस्ट करें ।


0

Nltk महान है, लेकिन कभी-कभी कुछ परियोजनाओं के लिए एक ओवरहेड होता है:

import re
def tokenize(text, ngrams=1):
    text = re.sub(r'[\b\(\)\\\"\'\/\[\]\s+\,\.:\?;]', ' ', text)
    text = re.sub(r'\s+', ' ', text)
    tokens = text.split()
    return [tuple(tokens[i:i+ngrams]) for i in xrange(len(tokens)-ngrams+1)]

उदाहरण का उपयोग करें:

>> text = "This is an example text"
>> tokenize(text, 2)
[('This', 'is'), ('is', 'an'), ('an', 'example'), ('example', 'text')]
>> tokenize(text, 3)
[('This', 'is', 'an'), ('is', 'an', 'example'), ('an', 'example', 'text')]

0

आप नीचे दिए गए अन्य पैकेज के बिना कोड का उपयोग करके सभी 4-6gram प्राप्त कर सकते हैं:

from itertools import chain

def get_m_2_ngrams(input_list, min, max):
    for s in chain(*[get_ngrams(input_list, k) for k in range(min, max+1)]):
        yield ' '.join(s)

def get_ngrams(input_list, n):
    return zip(*[input_list[i:] for i in range(n)])

if __name__ == '__main__':
    input_list = ['I', 'am', 'aware', 'that', 'nltk', 'only', 'offers', 'bigrams', 'and', 'trigrams', ',', 'but', 'is', 'there', 'a', 'way', 'to', 'split', 'my', 'text', 'in', 'four-grams', ',', 'five-grams', 'or', 'even', 'hundred-grams']
    for s in get_m_2_ngrams(input_list, 4, 6):
        print(s)

उत्पादन नीचे है:

I am aware that
am aware that nltk
aware that nltk only
that nltk only offers
nltk only offers bigrams
only offers bigrams and
offers bigrams and trigrams
bigrams and trigrams ,
and trigrams , but
trigrams , but is
, but is there
but is there a
is there a way
there a way to
a way to split
way to split my
to split my text
split my text in
my text in four-grams
text in four-grams ,
in four-grams , five-grams
four-grams , five-grams or
, five-grams or even
five-grams or even hundred-grams
I am aware that nltk
am aware that nltk only
aware that nltk only offers
that nltk only offers bigrams
nltk only offers bigrams and
only offers bigrams and trigrams
offers bigrams and trigrams ,
bigrams and trigrams , but
and trigrams , but is
trigrams , but is there
, but is there a
but is there a way
is there a way to
there a way to split
a way to split my
way to split my text
to split my text in
split my text in four-grams
my text in four-grams ,
text in four-grams , five-grams
in four-grams , five-grams or
four-grams , five-grams or even
, five-grams or even hundred-grams
I am aware that nltk only
am aware that nltk only offers
aware that nltk only offers bigrams
that nltk only offers bigrams and
nltk only offers bigrams and trigrams
only offers bigrams and trigrams ,
offers bigrams and trigrams , but
bigrams and trigrams , but is
and trigrams , but is there
trigrams , but is there a
, but is there a way
but is there a way to
is there a way to split
there a way to split my
a way to split my text
way to split my text in
to split my text in four-grams
split my text in four-grams ,
my text in four-grams , five-grams
text in four-grams , five-grams or
in four-grams , five-grams or even
four-grams , five-grams or even hundred-grams

आप इस ब्लॉग पर अधिक विवरण पा सकते हैं


0

लगभग सात वर्षों के बाद, यहाँ एक और अधिक सुंदर जवाब दिया गया है collections.deque:

def ngrams(words, n):
    d = collections.deque(maxlen=n)
    d.extend(words[:n])
    words = words[n:]
    for window, word in zip(itertools.cycle((d,)), words):
        print(' '.join(window))
        d.append(word)

words = ['I', 'am', 'become', 'death,', 'the', 'destroyer', 'of', 'worlds']

आउटपुट:

In [15]: ngrams(words, 3)                                                                                                                                                                                                                     
I am become
am become death,
become death, the
death, the destroyer
the destroyer of

In [16]: ngrams(words, 4)                                                                                                                                                                                                                     
I am become death,
am become death, the
become death, the destroyer
death, the destroyer of

In [17]: ngrams(words, 1)                                                                                                                                                                                                                     
I
am
become
death,
the
destroyer
of

In [18]: ngrams(words, 2)                                                                                                                                                                                                                     
I am
am become
become death,
death, the
the destroyer
destroyer of

0

यदि आप निरंतर मेमोरी उपयोग के साथ बड़े स्ट्रिंग्स के लिए एक शुद्ध पुनरावृत्ति समाधान चाहते हैं:

from typing import Iterable  
import itertools

def ngrams_iter(input: str, ngram_size: int, token_regex=r"[^\s]+") -> Iterable[str]:
    input_iters = [ 
        map(lambda m: m.group(0), re.finditer(token_regex, input)) 
        for n in range(ngram_size) 
    ]
    # Skip first words
    for n in range(1, ngram_size): list(map(next, input_iters[n:]))  

    output_iter = itertools.starmap( 
        lambda *args: " ".join(args),  
        zip(*input_iters) 
    ) 
    return output_iter

परीक्षा:

input = "If you want a pure iterator solution for large strings with constant memory usage"
list(ngrams_iter(input, 5))

आउटपुट:

['If you want a pure',
 'you want a pure iterator',
 'want a pure iterator solution',
 'a pure iterator solution for',
 'pure iterator solution for large',
 'iterator solution for large strings',
 'solution for large strings with',
 'for large strings with constant',
 'large strings with constant memory',
 'strings with constant memory usage']
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.