Calcul de N grammes en utilisant Python

j'ai dû calculer les Unigrammes, bigrammes et trigrammes pour un fichier texte contenant du texte comme:

" la fibrose kystique affecte 30 000 enfants et jeunes adultes aux États-Unis seulement Inhaler les brouillards de l'eau salée peut réduire le pus et l'infection qui remplit les voies respiratoires des personnes atteintes de fibrose kystique, bien que les effets secondaires comprennent une mauvaise toux fit et un goût sévère. C'est la conclusion de deux études publiées dans le numéro de cette semaine du New England Journal of Médicament."

j'ai commencé en Python et j'ai utilisé le code suivant:

#!/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/generating-n-grams-from-a-word

mais il fonctionne pour tous les N-grammes dans un mot, quand je le veux d'entre les mots comme dans le kystique et la fibrose ou la fibrose kystique. Quelqu'un peut m'aider comment je peux obtenir ce fait?

17
demandé sur Franck Dernoncourt 2012-11-17 00:26:35

8 réponses

en supposant que input est une chaîne de caractères contenant des mots séparés par des espaces, comme x = "a b c d" vous pouvez utiliser la fonction suivante (éditer: voir la dernière fonction pour une solution éventuellement plus complète):

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

si vous voulez que ceux-ci soient réunis en cordes, vous pourriez appeler quelque chose comme:

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

enfin, cela ne résume pas les choses en totaux, donc si votre entrée était 'a a a a' , vous devez les Compter dans un dict:

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

Mettre tous ensemble dans une dernière fonction donne:

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}
25
répondu dave mankoff 2012-11-16 20:46:33

une solution Pythonesque courte de cette blog :

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

Utilisation:

>>> 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')]
30
répondu Franck Dernoncourt 2016-01-15 22:20:29

utilisez NLTK (The Natural Language Toolkit) et utilisez les fonctions pour tokenize (split) votre texte dans une liste et ensuite trouver bigrams et trigrams.

import nltk
words = nltk.word_tokenize(my_text)
my_bigrams = nltk.bigrams(words)
my_trigrams = nltk.trigrams(words)
23
répondu Spaceghost 2012-11-17 15:26:00

il y a un autre module intéressant dans python appelé Scikit. Voici le code. Cela vous aidera à obtenir tous les grammes donnés dans une gamme particulière. Voici le code

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)

sortie est

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

donne ici tous les grammes donnés dans une gamme de 1 à 6. Il utilise la méthode appelée countVectorizer. Voici le lien pour cela.

6
répondu Gunjan 2014-10-30 14:14:55

par 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)

...ou peut-être pourriez-vous le faire en une ligne comme une liste de compréhension:

n = 2
message = "Hello, how are you?".split()
myNgrams = [message[i:i+n] for i in range(len(message) - n)]
3
répondu Joel Cornett 2012-11-16 20:39:38

nltk a un support natif pour les ngrams

'n' est la taille du ngram ex: n=3 est pour un trigram

from nltk import ngrams

def ngramize(texts, n):
    output=[]
    for text in texts:
        output += ngrams(text,n)
    return output
1
répondu r11 2016-09-28 22:35:12

bien que le post soit vieux, j'ai pensé à mentionner ma réponse ici pour que la plupart de la logique de création de ngrams puisse être dans un post.

il y a quelque chose par nom Textlob en Python. Il crée des ngrams très facilement similaires à NLTK.

ci-dessous est l'extrait de code avec sa sortie pour une compréhension facile.

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)

et la sortie est:

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

aussi simple que ça.

il y a plus à cela qui est fait par Textlob. Veuillez vous référer à ce document pour plus de détails - https://textblob.readthedocs.io/en/dev/

1
répondu JKC 2017-09-20 13:11:46

si l'efficacité est un problème et que vous devez construire plusieurs n-grammes différents, je considérerais utiliser le code suivant (construire sur L'excellente réponse de Franck):

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)))

Utilisation :

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

~même vitesse que 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, ngramRange=(1,6))
# 7.13 ms ± 165 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
0
répondu Yann Dubois 2018-01-18 07:53:51