2012-09-19 18 views
11

Quiero contar el número de ocurrencias de todos los bigrams (par de palabras adyacentes) en un archivo usando python. Aquí, estoy tratando con archivos muy grandes, así que estoy buscando una manera eficiente. Intenté usar el método de conteo con la expresión regular "\ w + \ s \ w +" en el contenido del archivo, pero no resultó ser eficiente.Cuenta de bigrams (par de dos palabras) en un archivo usando python

p. Ej. Digamos que quiero contar el número de Bigramas de un a.txt archivo, que tiene los siguientes contenidos:

"the quick person did not realize his speed and the quick person bumped " 

Para archivo anterior, la bigram fijar y su recuento serán:

(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 

I han encontrado un ejemplo de objetos Counter en Python, que se usa para contar unigramas (palabras sueltas). También utiliza el enfoque regex.

El ejemplo dice así:

>>> # 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 salida del código anterior es:

[('the', 2), ('quick', 2), ('person', 2), ('did', 1), ('not', 1), 
('realize', 1), ('his', 1), ('speed', 1), ('bumped', 1)] 

Me preguntaba si es posible utilizar el objeto de contador para obtener el recuento de Bigramas. Cualquier otro enfoque que no sea el objeto Counter o regex también será apreciado.

+0

pegar el texto de la muestra en cuestión. –

+0

¿Tiene que manejar varias líneas o el texto está en una línea por archivo? – mhawke

+1

posible duplicado de [Conteo de frecuencias de bi-gramo] (http://stackoverflow.com/questions/5883573/counting-bi-gram-frequencies) –

Respuesta

30

Algunos itertools mágica:

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

Salida:

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

Bono

Obtener la frecuencia de cualquier n-gram:

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

Salida:

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

Esto funciona con iterables perezosos y generadores también. De modo que puede escribir un generador que lea un archivo línea por línea, generando palabras, y pasarlo a ngarms para consumir perezosamente sin leer todo el archivo en la memoria.

+1

¡Impresionante! Funcionó como por arte de magia. ¡Muchas gracias! –

+0

que ES magia. wow, tendré que diseccionar ese. – Jake

+0

¡La función de itertools ngram es excelente! Sin embargo, si necesita realizar análisis de texto adicionales, vale la pena consultar [TextBlob] (https://textblob.readthedocs.io/en/dev/). También tiene una función TextBlob.ngrams() que básicamente hace lo mismo. He probado tanto los itertools como la función TextBlob y parecen funcionar con una velocidad y resultados comparables (una ventaja muy pequeña para la función itertools). – Montmons

6

¿Qué tal zip()?

import re 
from collections import Counter 
words = re.findall('\w+', open('a.txt').read()) 
print(Counter(zip(words,words[1:]))) 
+0

Esto también funcionó muy bien. Gracias –

0

Ha pasado mucho tiempo desde que se hizo esta pregunta y se respondió con éxito. Me beneficio de las respuestas para crear mi propia solución. Me gustaría compartirlo:

import regex 
    bigrams_tst = regex.findall(r"\b\w+\s\w+", open(myfile).read(), overlapped=True) 

Esto proporcionará todos los bigrams que no estén interrumpidos por un signo de puntuación.

1

¿Cómo se obtiene el recuento de un bigram y trigram en un diccionario bidimensional y tridimensional? ejemplo para unigram debajo de

copyText = unigramModel.prepData (texto)

para la lista de copyText & & palabra en la lista:

unigramCount = sum(x.count(word) for x in copyText) 
    self.nGramCounts[word] = unigramCount 

self.nGramCounts retorno

Cuestiones relacionadas