Quiero iterar sobre cada línea de un archivo completo. Una forma de hacerlo es leer todo el archivo, guardarlo en una lista y luego pasar la línea de interés. Este método usa mucha memoria, por lo que estoy buscando una alternativa.
Mi código hasta ahora:
for each_line in fileinput.input(input_file):
do_something(each_line)
for each_line_again in fileinput.input(input_file):
do_something(each_line_again)
La ejecución de este código da un mensaje de error: device active
.
¿Alguna sugerencia?
El propósito es calcular la similitud de cadena en pares, es decir, para cada línea en el archivo, quiero calcular la distancia de Levenshtein con cada otra línea.
Respuestas:
La forma correcta y totalmente pitónica de leer un archivo es la siguiente:
La
with
instrucción se encarga de abrir y cerrar el archivo, incluso si se genera una excepción en el bloque interno. Losfor line in f
trata el objeto archivof
como un iterable, que utiliza automáticamente búfer de E / S y la gestión de memoria por lo que no tiene que preocuparse de archivos de gran tamaño.fuente
for line in f:
está funcionando? Quiero decir, ¿cómo es posible iterar sobre un objeto de archivo?__iter__
, que le dice qué hacer. Los objetos de archivo definen este método especial para devolver un iterador sobre las líneas. (Aproximadamente.)Dos formas eficientes de memoria en orden de clasificación (la primera es la mejor):
with
- compatible con python 2.5 y superioryield
si realmente desea tener control sobre cuánto leer1. uso de
with
with
es la forma pitónica agradable y eficiente de leer archivos grandes. ventajas - 1) el objeto de archivo se cierra automáticamente después de salir delwith
bloque de ejecución. 2) manejo de excepciones dentro delwith
bloque. 3) elfor
bucle de memoria recorre elf
objeto de archivo línea por línea. internamente almacena E / S en búfer (optimizado para operaciones costosas de E / S) y gestión de memoria.2. uso de
yield
A veces, uno podría desear un control más detallado sobre cuánto leer en cada iteración. En ese caso, use iter y rendimiento . Tenga en cuenta que con este método se necesita cerrar explícitamente el archivo al final.
Las trampas y en aras de la exhaustividad : los métodos a continuación no son tan buenos ni tan elegantes para leer archivos grandes, pero lea para obtener una comprensión completa.
En Python, la forma más común de leer líneas de un archivo es hacer lo siguiente:
Sin embargo, cuando se hace esto, la
readlines()
función (lo mismo se aplica a laread()
función) carga todo el archivo en la memoria y luego lo repite. Un enfoque un poco mejor (los dos primeros métodos mencionados son los mejores) para archivos grandes es usar elfileinput
módulo, de la siguiente manera:la
fileinput.input()
llamada lee líneas secuencialmente, pero no las guarda en la memoria después de haberlas leído o simplemente así, ya quefile
en python es iterable.Referencias
fuente
for line in open(...).readlines(): <do stuff>
. ¡¿Por que lo harias?! Acaba de perder todo el beneficio del iterador IO con memoria intermedia inteligente de Python sin ningún beneficio.readlines
y explicando por qué no es algo bueno (porque lee el archivo en la memoria), luego explica qué hace elfileinput
módulo y por qué es posible que desee usarlo sobre los otros métodos, luego explicar cómo fragmentar el archivo mejora el IO y dar un ejemplo de la función de fragmentación (pero menciona que Python ya lo hace por usted, por lo que no es necesario). Pero dar cinco maneras de resolver un problema simple, cuatro de las cuales están mal en este caso, no es bueno.Para quitar nuevas líneas:
Con el apoyo de nueva línea universal de todas las líneas de archivo de texto parecen ser terminada con
'\n'
, cualesquiera que sean los terminadores en el archivo,'\r'
,'\n'
, o'\r\n'
.EDITAR: para especificar el soporte universal de nueva línea:
open(file_path, mode='rU')
- requerido [gracias @Dave ]open(file_path, mode='rU')
- opcionalopen(file_path, newline=None)
- opcionalEl
newline
parámetro solo es compatible con Python 3 y su valor predeterminado esNone
. Elmode
parámetro predeterminado es'r'
en todos los casos. ElU
está en desuso en Python 3. En Python 2 en Windows aparece algún otro mecanismo para traducir\r\n
a\n
.Documentos:
Para preservar los terminadores de línea nativos:
El modo binario aún puede analizar el archivo en líneas con
in
. Cada línea tendrá los terminadores que tenga en el archivo.Gracias a la respuesta de @katrielalex , el documento open () de Python y los experimentos de iPython .
fuente
open(file_path, 'rU')
que habilitar nuevas líneas universales.Esta es una posible forma de leer un archivo en Python:
no asigna una lista completa. Se itera sobre las líneas.
fuente
with open(input_file) as f:
. Esto le ahorraf.close()
y se asegura de que no olvide accidentalmente cerrarlo. Evita pérdidas de memoria y todo, muy importante al leer archivos.Algún contexto por adelantado de dónde vengo. Los fragmentos de código están al final.
Cuando puedo, prefiero usar una herramienta de código abierto como H2O para hacer lecturas de archivos CSV paralelos de súper alto rendimiento, pero esta herramienta tiene un conjunto de características limitado. Terminé escribiendo mucho código para crear canalizaciones de ciencia de datos antes de alimentar al clúster H2O para el aprendizaje supervisado propiamente dicho.
He estado leyendo archivos como el conjunto de datos HIGGS de 8 GB del repositorio UCI e incluso archivos CSV de 40 GB para fines de ciencia de datos significativamente más rápido al agregar mucho paralelismo con el objeto de grupo de la biblioteca de multiprocesamiento y la función de mapa. Por ejemplo, la agrupación con búsquedas vecinas más cercanas y también los algoritmos de agrupación DBSCAN y Markov requieren cierta delicadeza de programación paralela para evitar algunos problemas de memoria y tiempo de reloj de pared muy desafiantes.
Por lo general, me gusta dividir el archivo en hileras en partes usando herramientas gnu primero y luego glob-filemask a todos para encontrarlos y leerlos en paralelo en el programa python. Yo uso algo así como más de 1000 archivos parciales comúnmente. Hacer estos trucos ayuda enormemente con la velocidad de procesamiento y los límites de memoria.
El pandas dataframe.read_csv tiene un solo subproceso, por lo que puede hacer estos trucos para hacer que los pandas sean bastante más rápidos ejecutando un mapa () para ejecución paralela. Puede usar htop para ver que con pandas secuenciales antiguos simples dataframe.read_csv, 100% de CPU en un solo núcleo es el cuello de botella real en pd.read_csv, no el disco en absoluto.
Debo agregar que estoy usando un SSD en el bus de tarjeta de video rápido, no un HD giratorio en el bus SATA6, más 16 núcleos de CPU.
Además, otra técnica que descubrí que funciona muy bien en algunas aplicaciones es que el archivo CSV paralelo lee todo dentro de un archivo gigante, comenzando cada trabajador con un desplazamiento diferente en el archivo, en lugar de dividir previamente un archivo grande en muchos archivos de partes. Use el archivo de búsqueda de python () y tell () en cada trabajador paralelo para leer el archivo de texto grande en tiras, en diferentes ubicaciones de inicio de byte y final de byte de desplazamiento en el archivo grande, todo al mismo tiempo al mismo tiempo. Puede hacer un finge regex en los bytes y devolver el recuento de saltos de línea. Esta es una suma parcial. Finalmente, sume las sumas parciales para obtener la suma global cuando la función de mapa regrese después de que los trabajadores hayan terminado.
A continuación se muestran algunos puntos de referencia de ejemplo que utilizan el truco de desplazamiento de byte paralelo:
Yo uso 2 archivos: HIGGS.csv es de 8 GB. Es del repositorio de aprendizaje automático UCI. all_bin .csv tiene 40.4 GB y es de mi proyecto actual. Utilizo 2 programas: el programa GNU wc que viene con Linux y el programa puro python fastread.py que desarrollé.
Eso es alrededor de 4.5 GB / s, o 45 Gb / s, velocidad de extracción de archivos. Eso no es un disco duro giratorio, amigo mío. Eso es realmente un SSD Samsung Pro 950.
A continuación se muestra el punto de referencia de velocidad para el mismo archivo que cuenta gnu wc, un programa compilado en C puro.
Lo que es genial es que puedes ver que mi programa de Python puro esencialmente coincidía con la velocidad del programa C compilado por gnu wc en este caso. Python se interpreta pero C se compila, por lo que esta es una hazaña de velocidad bastante interesante, creo que estaría de acuerdo. Por supuesto, wc realmente necesita ser cambiado a un programa paralelo, y luego realmente superaría a mi programa Python. Pero tal como está hoy, gnu wc es solo un programa secuencial. Haces lo que puedes y Python puede hacerlo en paralelo hoy. La compilación de Cython podría ayudarme (en algún otro momento). Además, los archivos asignados a la memoria aún no se exploraron.
Conclusión: la velocidad es buena para un programa de Python puro en comparación con un programa en C. Sin embargo, no es lo suficientemente bueno para usar el programa Python puro sobre el programa C, al menos con el propósito de contar líneas. En general, la técnica se puede utilizar para otro procesamiento de archivos, por lo que este código de Python sigue siendo bueno.
Pregunta: ¿Compilar la expresión regular solo una vez y pasarla a todos los trabajadores mejorará la velocidad? Respuesta: El precompilación de Regex NO ayuda en esta aplicación. Supongo que la razón es que la sobrecarga de la serialización y creación de procesos para todos los trabajadores es dominante.
Una cosa más. ¿La lectura de archivos CSV paralelos incluso ayuda? ¿Es el disco el cuello de botella o es la CPU? Muchas de las llamadas respuestas mejor calificadas en stackoverflow contienen la sabiduría de desarrollo común de que solo necesita un hilo para leer un archivo, lo mejor que puede hacer, dicen. ¿Están seguros, sin embargo?
Vamos a averiguar:
Oh si, si lo hace. La lectura de archivos paralelos funciona bastante bien. ¡Bueno, allá vas!
PD. En caso de que algunos de ustedes quisieran saber, ¿qué pasaría si el balanceFactor fuera 2 cuando utilizara un solo proceso de trabajo? Bueno, es horrible.
Partes clave del programa python fastread.py:
La definición para PartitionDataToWorkers es simplemente un código secuencial ordinario. Lo dejé fuera en caso de que alguien más quiera practicar algo sobre cómo es la programación paralela. Regale gratuitamente las partes más difíciles: el código paralelo probado y en funcionamiento, para su beneficio de aprendizaje.
Gracias a: El proyecto de código abierto H2O, de Arno y Cliff y el personal de H2O por su excelente software y videos instructivos, que me han inspirado para este lector de desplazamiento de byte paralelo de alto rendimiento de Python puro como se muestra arriba. H2O realiza la lectura paralela de archivos usando java, es ejecutable por los programas python y R, y es una locura rápida, más rápida que cualquier otra cosa en el planeta al leer grandes archivos CSV.
fuente
Katrielalex proporcionó la manera de abrir y leer un archivo.
Sin embargo, según su algoritmo, lee el archivo completo para cada línea del archivo. Eso significa que la cantidad total de lectura de un archivo, y el cálculo de la distancia de Levenshtein , se realizará N * N si N es la cantidad de líneas en el archivo. Como le preocupa el tamaño del archivo y no desea mantenerlo en la memoria, me preocupa el tiempo de ejecución cuadrático resultante . Su algoritmo está en la clase O (n ^ 2) de algoritmos que a menudo se pueden mejorar con especialización.
Sospecho que ya conoce la compensación de memoria versus tiempo de ejecución aquí, pero tal vez desee investigar si hay una manera eficiente de calcular múltiples distancias de Levenshtein en paralelo. Si es así, sería interesante compartir su solución aquí.
¿Cuántas líneas tienen sus archivos y en qué tipo de máquina (potencia de memoria y CPU) tiene que funcionar su algoritmo y cuál es el tiempo de ejecución tolerado?
El código se vería así:
Pero las preguntas son: ¿cómo almacena las distancias (matriz?) Y puede obtener una ventaja de preparar, por ejemplo, la línea externa para el procesamiento, o el almacenamiento en caché de algunos resultados intermedios para su reutilización.
fuente
Si desea, por ejemplo, verificar una línea específica para una longitud mayor a 10, trabaje con lo que ya tiene disponible.
fuente
De la documentación de Python para fileinput .input ():
Además, la definición de la función es:
leyendo entre líneas, esto me dice que
files
puede ser una lista para que puedas tener algo como:Ver aquí para más información.
fuente
Recomiendo encarecidamente no utilizar la carga de archivos predeterminada, ya que es terriblemente lenta. Debería examinar las funciones numpy y las funciones IOpro (por ejemplo, numpy.loadtxt ()).
http://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html
https://store.continuum.io/cshop/iopro/
Luego puede dividir su operación por pares en trozos:
¡Casi siempre es mucho más rápido cargar datos en fragmentos y luego realizar operaciones matriciales en él que hacerlo elemento por elemento!
fuente
¿Necesita leer con frecuencia un archivo grande desde la última lectura de posición?
He creado un script utilizado para cortar un archivo Apache access.log varias veces al día. Entonces necesitaba establecer un cursor de posición en la última línea analizada durante la última ejecución . Para este fin, utilicé
file.seek()
yfile.seek()
métodos que permiten el almacenamiento del cursor en el archivo.Mi código :
fuente
La mejor manera de leer archivos grandes, línea por línea es usar la función de enumeración de Python
fuente