J'ai un fichier CSV de 3 Go que j'essaie de lire avec python, j'ai besoin de la colonne médiane.
from numpy import *
def data():
return genfromtxt('All.csv',delimiter=',')
data = data() # This is where it fails already.
med = zeros(len(data[0]))
data = data.T
for i in xrange(len(data)):
m = median(data[i])
med[i] = 1.0/float(m)
print med
L'erreur que j'obtiens est la suivante:
Python(1545) malloc: *** mmap(size=16777216) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Traceback (most recent call last):
File "Normalize.py", line 40, in <module>
data = data()
File "Normalize.py", line 39, in data
return genfromtxt('All.csv',delimiter=',')
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-
packages/numpy/lib/npyio.py", line 1495, in genfromtxt
for (i, line) in enumerate(itertools.chain([first_line, ], fhd)):
MemoryError
Je pense que c'est juste une erreur de mémoire insuffisante. J'utilise un MacOSX 64 bits avec 4 Go de RAM et numpy et Python compilé en mode 64 bits.
Comment puis-je réparer ça? Dois-je essayer une approche distribuée, juste pour la gestion de la mémoire?
Merci
EDIT: également essayé avec cela mais pas de chance ...
genfromtxt('All.csv',delimiter=',', dtype=float16)
Comme d'autres l'ont mentionné, pour un fichier vraiment volumineux, vous feriez mieux d'itérer.
Cependant, vous voulez généralement tout le contenu en mémoire pour diverses raisons.
genfromtxt
est beaucoup moins efficace que loadtxt
(bien qu'il gère les données manquantes, alors que loadtxt
est plus "maigre et méchant", c'est pourquoi les deux fonctions coexistent).
Si vos données sont très régulières (par exemple, simplement de simples lignes délimitées de même type), vous pouvez également les améliorer en utilisant numpy.fromiter
.
Si vous avez suffisamment de RAM, pensez à utiliser np.loadtxt('yourfile.txt', delimiter=',')
(Vous devrez peut-être également spécifier skiprows
si vous avez un en-tête sur le fichier.)
À titre de comparaison rapide, le chargement d'un fichier texte de ~ 500 Mo avec loadtxt
utilise ~ 900 Mo de RAM lors d'une utilisation maximale, tandis que le chargement du même fichier avec genfromtxt
utilise ~ 2,5 Go.
Loadtxt
Genfromtxt
Alternativement, considérez quelque chose comme ce qui suit. Cela ne fonctionnera que pour des données très simples et régulières, mais c'est assez rapide. (loadtxt
et genfromtxt
font beaucoup de devinettes et de vérification d'erreurs. Si vos données sont très simples et régulières, vous pouvez les améliorer considérablement.)
import numpy as np
def generate_text_file(length=1e6, ncols=20):
data = np.random.random((length, ncols))
np.savetxt('large_text_file.csv', data, delimiter=',')
def iter_loadtxt(filename, delimiter=',', skiprows=0, dtype=float):
def iter_func():
with open(filename, 'r') as infile:
for _ in range(skiprows):
next(infile)
for line in infile:
line = line.rstrip().split(delimiter)
for item in line:
yield dtype(item)
iter_loadtxt.rowlength = len(line)
data = np.fromiter(iter_func(), dtype=dtype)
data = data.reshape((-1, iter_loadtxt.rowlength))
return data
#generate_text_file()
data = iter_loadtxt('large_text_file.csv')
Fromiter
Le problème avec l'utilisation de genfromtxt () est qu'il tente de charger le fichier entier en mémoire, c'est-à-dire dans un tableau numpy. C'est génial pour les petits fichiers mais MAUVAIS pour les entrées de 3 Go comme la vôtre. Étant donné que vous calculez simplement les médianes des colonnes, il n'est pas nécessaire de lire l'intégralité du fichier. Un moyen simple, mais pas le plus efficace, serait de lire le fichier entier ligne par ligne plusieurs fois et de parcourir les colonnes.
Pourquoi n'utilisez-vous pas le module python csv ?
>> import csv
>> reader = csv.reader(open('All.csv'))
>>> for row in reader:
... print row