5 votes

Calcul de la fréquence des mots pour un fichier texte de 1 Go en Python

J'essaie de calculer la fréquence des mots pour un fichier texte de 1,2 Go contenant environ 203 millions de mots. J'utilise le code Python suivant. Mais il me donne une erreur de mémoire. Existe-t-il une solution à ce problème ?

Voici mon code :

import re
# this one in honor of 4th July, or pick text file you have!!!!!!!
filename = 'inputfile.txt'
# create list of lower case words, \s+ --> match any whitespace(s)
# you can replace file(filename).read() with given string
word_list = re.split('\s+', file(filename).read().lower())
print 'Words in text:', len(word_list)
# create dictionary of word:frequency pairs
freq_dic = {}
# punctuation marks to be removed
punctuation = re.compile(r'[.?!,":;]') 
for word in word_list:
    # remove punctuation marks
    word = punctuation.sub("", word)
    # form dictionary
    try: 
        freq_dic[word] += 1
    except: 
        freq_dic[word] = 1

print 'Unique words:', len(freq_dic)
# create list of (key, val) tuple pairs
freq_list = freq_dic.items()
# sort by key or word
freq_list.sort()
# display result
for word, freq in freq_list:
    print word, freq

Et voici l'erreur que j'ai reçue :

Traceback (most recent call last):
  File "count.py", line 6, in <module>
    word_list = re.split('\s+', file(filename).read().lower())
  File "/usr/lib/python2.7/re.py", line 167, in split
    return _compile(pattern, flags).split(string, maxsplit)
MemoryError

16voto

unutbu Points 222216

Le problème commence ici :

file(filename).read()

Ceci lit le fichier entier dans une chaîne de caractères. En revanche, si vous traitez le fichier ligne par ligne ou morceau par morceau, vous ne rencontrerez pas de problème de mémoire.

with open(filename) as f:
    for line in f:

Vous pourriez également bénéficier de l'utilisation d'un collections.Counter pour compter la fréquence des mots.

In [1]: import collections

In [2]: freq = collections.Counter()

In [3]: line = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod'

In [4]: freq.update(line.split())

In [5]: freq
Out[5]: Counter({'ipsum': 1, 'amet,': 1, 'do': 1, 'sit': 1, 'eiusmod': 1, 'consectetur': 1, 'sed': 1, 'elit,': 1, 'dolor': 1, 'Lorem': 1, 'adipisicing': 1})

Et pour compter quelques mots de plus,

In [6]: freq.update(line.split())

In [7]: freq
Out[7]: Counter({'ipsum': 2, 'amet,': 2, 'do': 2, 'sit': 2, 'eiusmod': 2, 'consectetur': 2, 'sed': 2, 'elit,': 2, 'dolor': 2, 'Lorem': 2, 'adipisicing': 2})

A collections.Counter est une sous-classe de dict Vous pouvez donc l'utiliser d'une manière qui vous est déjà familière. En outre, il dispose de quelques méthodes de comptage utiles, telles que plus_commune .

5voto

SynthC Points 430

Le problème est que vous essayez de lire l'intégralité du fichier en mémoire. La solution consiste à lire le fichier ligne par ligne, à compter les mots de chaque ligne et à additionner les résultats.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X