[pyar] ¿cómo guardar variables GRANDES en archivos?

Claudio Freire klaussfreire en gmail.com
Mar Ene 18 00:24:55 ART 2011


2011/1/11 Iván Raskovsky <raskovsky en gmail.com>

> 2011/1/11 Matías Bellone <matiasbellone en gmail.com>:
> > Por eso me resultó muuy raro leer los problemas que tenés. ¿Podrías
> > dar más información para ver de encontrar el cuello de botella?
>
> Muchas gracias a todos. El archivo es una lista de documentos donde
> cada documento es una lista de oraciones, donde cada oracion es una
> lista de palabras que son una tupla de la palabra y el POS (part of
> speech) que no es más que otro string.
>
> [ # documentos
>  [ # oraciones
>   [ # palabras
>    ('palabra', 'pos')
>   ],
>  ],
> ]
>

Lo que describís parece indicar un comportamiento cuadrático en cPickle.

Tengo entendido que unladen-swallow optimizó muchísimo cPickle, y que muchas
de las optimizaciones las mergearon en Python 3. Así que podrías probar con
python3.

Más allá de eso, el comportamiento cuadrático molesta cuando tratás con
estructuras grandes. Para esquivar esto, te recomiendo evitar estructuras
grandes.

Tu archivo puede consistir de varios objetos pickleados en secuencia. Por
ejemplo, en vez de un pickle con todos los documentos, podés picklear
documentos uno atrás de otro, y hacer cPickle.load() hasta que tengas un
EOF, cargando documento por documento en vez de todos de una.

try:
   while True:
       docs.append(cPickle.load(f))
except EOFError:
   pass

Si hay documentos muy grandes, podés partir también cada documento en
oraciones:

try:
   while True:
       oraciones = cPickle.load(f)
       doc = [ cPickle.load(f) for x in xrange(oraciones) ]
       docs.append(doc)
except EOFError:
   pass

Bue, eso es para cargar, para grabar es algo parecido.

Etc.

Eso debería aliviarte tu problema de orden cuadrático en el pickleado, sin
cambiar la representación en memoria de los datos que querés manejar.

El otro problema que podés tener es que la representación que elegiste sea
demasiado ineficiente.

Cada palabra es una tupla de 2, más la cadena, que asumiendo un promedio de
5 letras por palabra sería algo así como 74 bytes.

Asimismo, cada oración es una lista de, asumamos, promedio 25 palabras, o
sea 16 + (8 + 74) * 25 = 2066 bytes.

Asimismo, cada documento es una lista de oraciones, Ni idea cuántas, pero...
sabiendo que cada oración ocupa 2066 bytes en memoria y representa 150
letras de texto, si tu archivo de texto ocupa 200MB, es esperable que en
memoria todo te ocupe 2754MB (regla de tres). Eso son 2.7G. Muy ineficiente.

Algunas cosas que podés hacer para alivianar el uso de memoria es, por
ejemplo, aprovechar el hecho de que se van a repetir mucho algunos pares
(palabra, pos), y unificar. Por ejemplo, si aparece ('memoria', 'od') 1000
veces, no necesitás 1000 tuplas. Usando un diccionario, podés "canonizar" la
palabra:

palabras = {}

...
palabra = palabras.setdefault(palabra,palabra)

Claro que si no hay mucho reuso, el diccionario puede pesarte más de lo que
te ahorra.

En síntesis... tenés un problema de ineficiencia inherente a lo que querés
hacer, diría yo, más que nada. Probablemente deberías evitar tener todo en
memoria.
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.python.org.ar/pipermail/pyar/attachments/20110118/777e75c9/attachment.html>


More information about the pyar mailing list