Re: [Python-es] Buscar, leer y escribir archivos grandes con Python

2011-06-04 Por tema Andrey Antoukh
Hola.
Me pareció muy interesante este hilo y he hecho unas cuantas pruebas con el
modulo IO de python3
Y en promedio me procesa un archivo de 70Mb en 1 segundo.

El código de la prueba: http://pastii.com.ar/1819

Andrei.
;)

El 4 de junio de 2011 04:18, Manuel Enrique González Ramírez 
maeng...@gmail.com escribió:



 El 3 de junio de 2011 14:19, Alexis Roda alexis.roda.villalo...@gmail.com
  escribió:

 En/na Kiko ha escrit:

 En el programa que mandaste en el primer mensaje parece implícito que la
 longitud del código es siempre de 9 caracteres. Esto hace innecesario el uso
 de rsplit o rfind.

 def procesa(entrada, salida) :

with open(entrada,'r') as input:
with open(salida,'w') as output:
for l in input :
output.write(l[-9:])

 In [1]: l = 1|2011-05-20 23:08:56|122711527|OPERADOR1|HOST
 TOHOST|212454|1|HOST CLIENTE|192630167

 In [2]: timeit l.rsplit(|, 1)[-1]
 100 loops, best of 3: 827 ns per loop

 In [3]: timeit l[l.rindex(|)+1:]
 100 loops, best of 3: 676 ns per loop

 In [4]: timeit l[l.rfind(|)+1:]
 100 loops, best of 3: 682 ns per loop

 In [5]: timeit l[-9:]
 100 loops, best of 3: 208 ns per loop

 Fíjate en que utilizar rfind (o rindex) como hacías originalmente es mas
 eficiente que utilizar rsplit. La explicación es que rsplit crea dos cadenas
 (la mitad izquierda y la derecha), una lista con las dos cadenas y
 finalmente accede al último elemento de la lista. En la versión con rindex
 se crea directamente la cadena derecha.

 Como curiosidad, en el caso de utilizar un método de l podrías arañar unos
 nanosegundos haciendo algo como:

 In [6]: rf=l.rfind

 In [7]: timeit l[rf(|)+1:]
 100 loops, best of 3: 602 ns per loop

 con esto evitas que el interprete tenga que buscar el método rfind de l en
 cada iteración.


  Claramente, rsplit parece que funciona mejor.  He hecho mi función
 (abrekiko) con una list comprehesion y también va un poquito más lenta
 que con el for a pelo y tenía entendido que usar list comprehensions era más
 efectivo.


 Las list comprehension sirven para crear listas. Lo que hace tu código es
 equivalente a:

 def abrelasi(entrada,salida):
lista = []

with open(entrada,'r') as input:
with open(salida,'w') as output:
for l in input :
lista.append(output.write(l.rsplit(',',1)[-1]))

 Al final lista contiene 30 valores None. No le veo el sentido.


  ¿Alguien tiene formas más rápidas de lectura de ficheros de texto?


 Yo hubiese utilizado cut -d\| -f9 entrada.txt  salida.txt

 Como ya te han dicho debes considerar el tiempo de desarrollo mas el
 tiempo de ejecución y valorar si el esfuerzo extra vale la pena. Dicho esto,
 si quieres aprender, te recomendaría probar el módulo cProfile:

  http://docs.python.org/library/profile.html#module-cProfile

 este modulo mide el tiempo de ejecución del programa y te ayudará a
 descubrir donde está el cuello de botella. Tal vez estés dedicando horas a
 optimizar algo que luego no tiene un impacto decisivo en el tiempo total de
 ejecución.

 En el caso de procesar el archivo tengo la impresión de que el problema
 estará en la E/S y no el el procesamiento de los datos en si (utilizando un
 programa razonable).



 Saludos

 ___
 Python-es mailing list
 Python-es@python.org
 http://mail.python.org/mailman/listinfo/python-es
 FAQ: http://python-es-faq.wikidot.com/


 Excelentísimos aportes de todos, si que se aprende!!

 De verdad muuchas gracias, he seguido el hilo, cambiado el código y he
 obtenido excelentes resultados.  Estos aportes están de lo máximo y si
 continúa bienvenido sea el aprendizaje


 --
 Manuel Enrique González Ramírez
 http://maengora.blogspot.com

 ___
 Python-es mailing list
 Python-es@python.org
 http://mail.python.org/mailman/listinfo/python-es
 FAQ: http://python-es-faq.wikidot.com/




-- 
http://twitter.com/andsux
http://www.niwi.be

http://www.freebsd.org/
http://www.postgresql.org/
http://www.python.org/
http://www.djangoproject.com/

Linux is for people who hate Windows, BSD is for people who love UNIX
Social Engineer - Because there is no patch for human stupidity
___
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/


Re: [Python-es] Buscar, leer y escribir archivos grandes con Python

2011-06-03 Por tema lasizoillo
El día 3 de junio de 2011 12:39, Kiko kikocorre...@gmail.com escribió:

 Usando ipython defino tres funciones:

 def abrekiko(entrada, salida):
     input = open(entrada, 'r')
     output = open(salida, 'w')
     for l in input:
         output.write(l.split(',')[-1])
     input.close()
     output.close()

 def abrejoe(entrada,salida):
     with open(entrada,'r') as input:
     with open(salida,'w') as output:
     [output.write(l.split(',')[-1]) for l in input]

 def abrelasi(entrada,salida):
     with open(entrada,'r') as input:
     with open(salida,'w') as output:
     [output.write(l.rsplit(',',1)[-1]) for l in input]

 Los resultados que me salen son:
 In [15]: timeit abrekiko(entrada,salida)
 1 loops, best of 3: 735 ms per loop

 In [16]: timeit abrejoe(entrada,salida)
 1 loops, best of 3: 766 ms per loop

 In [17]: timeit abrelasi(entrada,salida)
 1 loops, best of 3: 563 ms per loop

 Mi entrada es un fichero con 300.000 líneas y 8 columnas separadas por coma.

 Claramente, rsplit parece que funciona mejor. He hecho mi función (abrekiko)
 con una list comprehesion y también va un poquito más lenta que con el for a
 pelo y tenía entendido que usar list comprehensions era más efectivo.


list comprehensions genera una lista con todos los datos de la
iteración, lo cual no es muy bueno para el uso de la memoria. Usando
generadores (como list comprehensions pero usando parentesis en vez de
corchetes) se consume menos memoría, lo cual también es bueno.
Respecto a lo de que vaya un poquito más rápido o un poquito más lento
puede ser por temas varios. Si ejecutas el test dos veces verás que
hay cierta desviación, por lo que pequeñas mejoras no son
representativas.

 ¿La diferencia de rsplit con respecto a split es solo que empieza el split
 por la derecha?


Si, esa es la única diferencia. Pero el truquito en cuestión está en
el segundo parámetro. Ese 1 le indica que pare al cortar un elemento.
En este caso concreto solo queremos el último, por lo que no tiene
demasiado sentido seguir buscando en la cadena y troceando el resto de
los campos. Aparte del recorrido en la cadena, la creación de esas
nuevas cadenas para representar cada uno de los capos no es gratis.

 ¿Alguien tiene formas más rápidas de lectura de ficheros de texto?


Respuesta corta: Si, no, a veces.

Respuesta larga (me pongo en modo chapas así que dejar de leer si se quiere):

Moraleja 1: Si el cuello de botella es el acceso a disco poco hay por hacer

Un día me puse hacer una guerra de lenguajes implementando un wc
(programa para contar lineas) muy simple en c, haskell y python.

En C las pasé canutas porque la función readline del estandar C99 no
estaba en la librería estandar del OSX, por lo que tuve que hacer una
implementación que hiciera uso de buffers. Quedó un código muy largo y
me costo cierto tiempo hacerlo.

En haskell, quizá por ser un lenguaje que tampoco domino, me quedó un
programa corto y eficiente, pero cada caracter del codigo había que
pensarlo con cautela. La forma de hacer el plegado de funciones para
que la evaluación perezosa no fuese un problema, la forma de que la
lectura usará bien buffers, ... todo eso hizo que me costara horrores
escribir unas pocas lineas de código.

En python el programa era ligeramente más largo que haskell, pero me
salió solito y sin pensarlo mucho.

Los resultados fueron curiosos. Cuando el fichero no estaba en cache
de disco, el cuello de botella era el acceso a este, por lo que los
tres códigos tardaban lo mismo en ejecutarse. Estando el fichero en
cache (cosa que tampoco sería demasiado normal, supongo) la versión c
y haskell eran mucho más rápidas que la versión en python. La
diferencia entre c y haskell no era muy grande siendo la primera algo
más rápida.



Moraleja 2: Depende de la estructura de ese fichero de texto.

Si en vez de tener que leer el último campo en el ejemplo de este
correo, se hubiera tenido que leer uno de en medio la optimización
realizada sería menos evidente.
Si el fichero tiene alguna cadena larga fácil de buscar, algoritmos
como el de Boyer-Moore[1] pueden ayudar bastante.
Si el fichero en vez del tipo csv fuese uno con campos fijos, se
podría hacer un mmap y acceder directamente a las zonas de memoria
donde estan los datos, evitando un recorrido sobre el fichero.
Si el trabajo a hacer sobre el fichero es pesado (cuello de botella en
cpu) se puede probar a parelizar con multiproceso. Eso si, a veces la
sincrinización/comunicación entre procesos puede quitar más
rendimiento del que aporta.
Si ...
Por desgracia no conozco recetas mágicas para usar en todos los casos.
Pero si que hay algunas herramientas que se pueden tener en reserva
para aplicar en casos concretos. De ahí que la respuesta corta fuese
si, no, a veces ;-)

[1] http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm




Moraleja 3: No centrarse solo en la ejecución del código.

Si el objetivo es tener el resultado de una ejecución concreta, desde
que eres 

Re: [Python-es] Buscar, leer y escribir archivos grandes con Python

2011-06-03 Por tema Kiko
 Respuesta corta: Si, no, a veces.


Me imaginaba algo así :-D

Muchas gracias por la extensión de la explicación.

Exploraré mmap (aunque creo que para lo que lo estoy pensando ahora será
menos útil) y multiprocesos y lo que pille por ahí.

Como bien has dicho, no merece la pena programar dos horas para 2s de
proceso. Pero esos 2s los tengo que repetir muchas veces todos los días. Si
no consigo mejorar nada por lo menos habré aprendido algo (o no, que soy muy
zoquete).
___
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/


Re: [Python-es] Buscar, leer y escribir archivos grandes con Python

2011-06-03 Por tema Alexis Roda

En/na Kiko ha escrit:

En el programa que mandaste en el primer mensaje parece implícito que la 
longitud del código es siempre de 9 caracteres. Esto hace innecesario el 
uso de rsplit o rfind.


def procesa(entrada, salida) :
with open(entrada,'r') as input:
with open(salida,'w') as output:
for l in input :
output.write(l[-9:])

In [1]: l = 1|2011-05-20 23:08:56|122711527|OPERADOR1|HOST 
TOHOST|212454|1|HOST CLIENTE|192630167


In [2]: timeit l.rsplit(|, 1)[-1]
100 loops, best of 3: 827 ns per loop

In [3]: timeit l[l.rindex(|)+1:]
100 loops, best of 3: 676 ns per loop

In [4]: timeit l[l.rfind(|)+1:]
100 loops, best of 3: 682 ns per loop

In [5]: timeit l[-9:]
100 loops, best of 3: 208 ns per loop

Fíjate en que utilizar rfind (o rindex) como hacías originalmente es mas 
eficiente que utilizar rsplit. La explicación es que rsplit crea dos 
cadenas (la mitad izquierda y la derecha), una lista con las dos 
cadenas y finalmente accede al último elemento de la lista. En la 
versión con rindex se crea directamente la cadena derecha.


Como curiosidad, en el caso de utilizar un método de l podrías arañar 
unos nanosegundos haciendo algo como:


In [6]: rf=l.rfind

In [7]: timeit l[rf(|)+1:]
100 loops, best of 3: 602 ns per loop

con esto evitas que el interprete tenga que buscar el método rfind de l 
en cada iteración.



Claramente, rsplit parece que funciona mejor.  He hecho mi función
(abrekiko) con una list comprehesion y también va un poquito más lenta 
que con el for a pelo y tenía entendido que usar list comprehensions era 
más efectivo.


Las list comprehension sirven para crear listas. Lo que hace tu código 
es equivalente a:


def abrelasi(entrada,salida):
lista = []
with open(entrada,'r') as input:
with open(salida,'w') as output:
for l in input :
lista.append(output.write(l.rsplit(',',1)[-1]))

Al final lista contiene 30 valores None. No le veo el sentido.


¿Alguien tiene formas más rápidas de lectura de ficheros de texto?


Yo hubiese utilizado cut -d\| -f9 entrada.txt  salida.txt

Como ya te han dicho debes considerar el tiempo de desarrollo mas el 
tiempo de ejecución y valorar si el esfuerzo extra vale la pena. Dicho 
esto, si quieres aprender, te recomendaría probar el módulo cProfile:


  http://docs.python.org/library/profile.html#module-cProfile

este modulo mide el tiempo de ejecución del programa y te ayudará a 
descubrir donde está el cuello de botella. Tal vez estés dedicando horas 
a optimizar algo que luego no tiene un impacto decisivo en el tiempo 
total de ejecución.


En el caso de procesar el archivo tengo la impresión de que el problema 
estará en la E/S y no el el procesamiento de los datos en si (utilizando 
un programa razonable).




Saludos
___
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/


[Python-es] Buscar, leer y escribir archivos grandes con Python

2011-06-02 Por tema Manuel Enrique González Ramírez
Hola a tod@s,

Tengo la siguiente situación:

Un archivo de 29Mb que contiene 281.351 lineas.  El archivo tiene la
siguiente estructura:

1|2011-05-20 23:08:56|122711527|OPERADOR1|HOST TO HOST|212454|1|HOST
CLIENTE|192630167
2|2011-05-20 23:09:08|122711530|OPERADOR12|HOST TO
HOST|57212454|1000|HOST CLIENTE|192630168
3|2011-05-20 23:09:42|122711538|OPERADOR1|HOST TO
HOST|454545454545|2000|HOST CLIENTE|192630169
4|2011-05-20 23:10:03|122711544|OPERADOR1|HOST TO
HOST|121221211|2|HOST CLIENTE|192630170
5|2011-05-20 23:10:09|122711547|OPERADOR1|HOST TO HOST
ESPECIAL|4545|5000|HOST CLIENTE|192630171
6|2011-05-20 23:10:46|122711554|OPERADOR1|HOST TO HOST
ESPECIAL|545454445|5000|HOST CLIENTE|192630172
.
.
Del cual debo capturar la última sección, es decir, el número que me
representa una secuencia (192630167, 192630168, etc).

Lo hago así:

fc = open('archivo.txt','r')

for linea in fc:
b = linea.rfind('|')
posi = b + 1
posf = posi + 9
secuenciac = linea[posi:posf]
print secuenciac

Esto tarda en promedio 3 minutos (que es demasiado comparado con el tiempo
que tarda [1min en promedio] con el script que me pasaron en Perl).

Ahora, para sumarle al problema del tiempo que tarda dicha proceso, el
resultado del ciclo anterior debe escribirse en otro archivo (datos.csv);
eso lo hago así:

# Abro un archivo para edición
fdif = open('datos.csv','a')
fdif.writelines(''+secuenciac+'; \n')
fdif.close()

Y esto eleva exponencialmente el tiempo.  :(

Estuve buscando en San Google y en un hilo anterior (así como en e foro de
majibu) obtuve documentación donde se habla de lectura de archivos enormes
con python usando un mínimo de tiempo:

http://effbot.org/zone/wide-finder.htm

def process(file, chunk):
f = open(file)
f.seek(chunk[0])
d = defaultdict(int)
for page in pat.findall(f.read(chunk[1])):
d[page] += 1
return


Perdón pero no acabo de entender cómo implementar algo que me funcione
utilizando el mínimo de tiempo como dicen que sucede por ejemplo con el
process anterior.

Se que se puede mejorar dichas situaciones pero lo poco que aún se de Python
no me deja ser más eficiente (.. y es que mi ignorancia es infinita)

Alguien me puede colaborar???


Muchas gracias.



-- 
Manuel Enrique González Ramírez
http://maengora.blogspot.com
___
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/


Re: [Python-es] Buscar, leer y escribir archivos grandes con Python

2011-06-02 Por tema Jose Caballero



 fc = open('archivo.txt','r')

 for linea in fc:
 b = linea.rfind('|')
 posi = b + 1
 posf = posi + 9
 secuenciac = linea[posi:posf]
 print secuenciac





Has probado

fc = open(.)
for linea in fc:
secuenciac = linea.split('|')[-1]

?
___
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/


Re: [Python-es] Buscar, leer y escribir archivos grandes con Python

2011-06-02 Por tema joe di castro
Mejor aún, kiko:

with open(archivo.txt, r) as entrada:
with open(salida.txt, w) as salida:
for linea in entrada:
salida.write( + linea.split('|')[-1] + ;\n)

Saludos


El jue, 02-06-2011 a las 23:45 +0200, Kiko escribió:
 
 
 2011/6/2 Jose Caballero jcaballero@gmail.com
 
 
 
 fc = open('archivo.txt','r')
 
 
 for linea in fc:
 b = linea.rfind('|')
 posi = b + 1
 posf = posi + 9
 secuenciac = linea[posi:posf]
 print secuenciac
 
 
 
 
 
 
 Has probado 
 
 fc = open(.)
 for linea in fc:
 secuenciac = linea.split('|')[-1]
 
 
  
 Yo abro todos los días ficheros de ese pelo y no me tarda tanto.
 Prueba lo siguiente y dime a ver si te funciona:
 
 
 ficheroentrada = open('archivo.txt','r')
 ficherosalida = open('salida.txt','w')
 for linea in ficheroentrada:
 ficherosalida.write( + linea.split('|')[-1] + ;\n)
 ficheroentrada.close()
 ficherosalida.close()
 
 
 ___
 Python-es mailing list
 Python-es@python.org
 http://mail.python.org/mailman/listinfo/python-es
 FAQ: http://python-es-faq.wikidot.com/


___
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/


Re: [Python-es] Buscar, leer y escribir archivos grandes con Python

2011-06-02 Por tema lasizoillo
El día 2 de junio de 2011 23:32, Manuel Enrique González Ramírez
maeng...@gmail.com escribió:
 Hola a tod@s,
 Tengo la siguiente situación:
 Un archivo de 29Mb que contiene 281.351 lineas.  El archivo tiene la
 siguiente estructura:
 1|2011-05-20 23:08:56|122711527|OPERADOR1|HOST TO HOST|212454|1|HOST
 CLIENTE|192630167
 2|2011-05-20 23:09:08|122711530|OPERADOR12|HOST TO
 HOST|57212454|1000|HOST CLIENTE|192630168
 3|2011-05-20 23:09:42|122711538|OPERADOR1|HOST TO
 HOST|454545454545|2000|HOST CLIENTE|192630169
 4|2011-05-20 23:10:03|122711544|OPERADOR1|HOST TO
 HOST|121221211|2|HOST CLIENTE|192630170
 5|2011-05-20 23:10:09|122711547|OPERADOR1|HOST TO HOST
 ESPECIAL|4545|5000|HOST CLIENTE|192630171
 6|2011-05-20 23:10:46|122711554|OPERADOR1|HOST TO HOST
 ESPECIAL|545454445|5000|HOST CLIENTE|192630172
 .
 .
 Del cual debo capturar la última sección, es decir, el número que me
 representa una secuencia (192630167, 192630168, etc).
 Lo hago así:
 fc = open('archivo.txt','r')
 for linea in fc:
     b = linea.rfind('|')
     posi = b + 1
     posf = posi + 9
     secuenciac = linea[posi:posf]
     print secuenciac

Supongo que esto es muy lento y que con el split habrás notado una
buena mejoría. Pero todavía se puede hacer mejor, rsplit es lo suyo:

In [9]: linea = 1|2011-05-20 23:08:56|122711527|OPERADOR1|HOST TO
HOST|212454|1|HOST CLIENTE|192630167

In [10]: timeit linea.split('|')[-1]
100 loops, best of 3: 1.2 us per loop

In [11]: timeit linea.rsplit('|',1)[-1]
100 loops, best of 3: 695 ns per loop

In [12]: linea.rsplit('|',1)[-1]
Out[12]: '192630167'

Para hacer esos mini-benchmarks tan chulos, se puede hacer facilmente
con ipython. Para un profiling mejor busca por san google temas de
python profiling e incluso python profiling kcachegrind. Lo suyo para
optimizar es poder medir en que estas gastando el tiempo ;-)

 Esto tarda en promedio 3 minutos (que es demasiado comparado con el tiempo
 que tarda [1min en promedio] con el script que me pasaron en Perl).
 Ahora, para sumarle al problema del tiempo que tarda dicha proceso, el
 resultado del ciclo anterior debe escribirse en otro archivo (datos.csv);
 eso lo hago así:
 # Abro un archivo para edición
     fdif = open('datos.csv','a')
     fdif.writelines(''+secuenciac+'; \n')
     fdif.close()
 Y esto eleva exponencialmente el tiempo.  :(

No alcanzo a entender el uso de writelines:
http://docs.python.org/library/stdtypes.html#file.writelines

Supongo que no abres y cierras el fichero cada vez, pero tengo que
preguntarlo, ¿lo haces? Si lo estás haciendo, un profiler gritaría que
ese es el primer punto a optimizar.

 Estuve buscando en San Google y en un hilo anterior (así como en e foro de
 majibu) obtuve documentación donde se habla de lectura de archivos enormes
 con python usando un mínimo de tiempo:
 http://effbot.org/zone/wide-finder.htm

 def process(file, chunk):
 f = open(file)
 f.seek(chunk[0])
 d = defaultdict(int)
 for page in pat.findall(f.read(chunk[1])):
 d[page] += 1
 return

 Perdón pero no acabo de entender cómo implementar algo que me funcione
 utilizando el mínimo de tiempo como dicen que sucede por ejemplo con el
 process anterior.
 Se que se puede mejorar dichas situaciones pero lo poco que aún se de Python
 no me deja ser más eficiente (.. y es que mi ignorancia es infinita)
 Alguien me puede colaborar???


Creo que lo mejor es olvidarse un poco de conseguir la solución más
eficiente por ahora. Primero juega con python y cuando tengas soltura
irás haciendo el código más óptimo de forma fácil. Por ejemplo, la
optimización del rsplit no se me hubiera podido ocurrir sin conocer la
existencia del rsplit. Para saber por qué va más rápido hay que pensar
en la cantidad de objetos a crear/destruir en una y otra solución,
aparte de que una requiere un recorrido mayor de la cadena que la
otra.

Espero que el correo te haya resultado útil.

Un saludo:

Javi
___
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/