Je veux compter le nombre d'occurrences de tous les bigrammes (paire de mots adjacents) dans un fichier en utilisant python. Ici, je traite de très gros fichiers, donc je cherche un moyen efficace. J'ai essayé d'utiliser la méthode count avec l'expression rationnelle "\ w +\s\w +" sur le contenu du fichier, mais cela ne s'est pas avéré efficace.
par exemple. Supposons que je veuille compter le nombre de bigrams d'un fichier a.txt, dont le contenu est le suivant:
"the quick person did not realize his speed and the quick person bumped "
Pour le fichier ci-dessus, l'ensemble bigramme et leur nombre seront:
(the,quick) = 2
(quick,person) = 2
(person,did) = 1
(did, not) = 1
(not, realize) = 1
(realize,his) = 1
(his,speed) = 1
(speed,and) = 1
(and,the) = 1
(person, bumped) = 1
Je suis tombé sur un exemple d'objets Counter en Python, utilisé pour compter des unigrammes (mots simples). Il utilise également l'approche regex.
L'exemple va comme ceci:
>>> # Find the ten most common words in Hamlet
>>> import re
>>> from collections import Counter
>>> words = re.findall('\w+', open('a.txt').read())
>>> print Counter(words)
La sortie du code ci-dessus est:
[('the', 2), ('quick', 2), ('person', 2), ('did', 1), ('not', 1),
('realize', 1), ('his', 1), ('speed', 1), ('bumped', 1)]
Je me demandais s'il était possible d'utiliser l'objet Counter pour obtenir le compte de bigrams. Toute approche autre que Counter object ou regex sera également appréciée.
Un peu de magie itertools
:
>>> import re
>>> from itertools import islice, izip
>>> words = re.findall("\w+",
"the quick person did not realize his speed and the quick person bumped")
>>> print Counter(izip(words, islice(words, 1, None)))
Sortie:
Counter({('the', 'quick'): 2, ('quick', 'person'): 2, ('person', 'did'): 1,
('did', 'not'): 1, ('not', 'realize'): 1, ('and', 'the'): 1,
('speed', 'and'): 1, ('person', 'bumped'): 1, ('his', 'speed'): 1,
('realize', 'his'): 1})
Prime
Obtenez la fréquence de n'importe quel n-gramme:
from itertools import tee, islice
def ngrams(lst, n):
tlst = lst
while True:
a, b = tee(tlst)
l = Tuple(islice(a, n))
if len(l) == n:
yield l
next(b)
tlst = b
else:
break
>>> Counter(ngrams(words, 3))
Sortie:
Counter({('the', 'quick', 'person'): 2, ('and', 'the', 'quick'): 1,
('realize', 'his', 'speed'): 1, ('his', 'speed', 'and'): 1,
('person', 'did', 'not'): 1, ('quick', 'person', 'did'): 1,
('quick', 'person', 'bumped'): 1, ('did', 'not', 'realize'): 1,
('speed', 'and', 'the'): 1, ('not', 'realize', 'his'): 1})
Cela fonctionne aussi avec les iterables et les générateurs paresseux. Vous pouvez donc écrire un générateur qui lit un fichier ligne par ligne, générant des mots, et le transmettre à ngarms
pour le consommer paresseusement sans lire le fichier entier en mémoire.
Que diriez-vous de Zip()
?
import re
from collections import Counter
words = re.findall('\w+', open('a.txt').read())
print(Counter(Zip(words,words[1:])))
Il y a longtemps que cette question a été posée et a répondu avec succès. Je profite des réponses pour créer ma propre solution. Je voudrais le partager:
import regex
bigrams_tst = regex.findall(r"\b\w+\s\w+", open(myfile).read(), overlapped=True)
Cela fournira tous les bigrammes qui ne sont pas interrompus par une ponctuation.
Vous pouvez simplement utiliser Counter
pour tout n_gram comme ceci:
from collections import Counter
from nltk.util import ngrams
text = "the quick person did not realize his speed and the quick person bumped "
n_gram = 2
Counter(ngrams(text.split(), n_gram))
>>>
Counter({('and', 'the'): 1,
('did', 'not'): 1,
('his', 'speed'): 1,
('not', 'realize'): 1,
('person', 'bumped'): 1,
('person', 'did'): 1,
('quick', 'person'): 2,
('realize', 'his'): 1,
('speed', 'and'): 1,
('the', 'quick'): 2})
Pour 3 grammes, il suffit de changer le n_gram
en 3:
n_gram = 3
Counter(ngrams(text.split(), n_gram))
>>>
Counter({('and', 'the', 'quick'): 1,
('did', 'not', 'realize'): 1,
('his', 'speed', 'and'): 1,
('not', 'realize', 'his'): 1,
('person', 'did', 'not'): 1,
('quick', 'person', 'bumped'): 1,
('quick', 'person', 'did'): 1,
('realize', 'his', 'speed'): 1,
('speed', 'and', 'the'): 1,
('the', 'quick', 'person'): 2})