web-dev-qa-db-fra.com

Python mémoire insuffisante sur un gros fichier CSV (numpy)

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

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 Memory and CPU usage of numpy.loadtxt while loading a ~500MB ascii file


Genfromtxt Memory and CPU usage of numpy.genfromtxt while loading a ~500MB ascii file


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

Using fromiter to load the same ~500MB data file

70
Joe Kington

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.

4
CoderMD666

Pourquoi n'utilisez-vous pas le module python csv ?

>> import csv
>> reader = csv.reader(open('All.csv'))
>>> for row in reader:
...     print row
2
anijhaw