ordenar operaciones leer graficar exportar diccionario datos crear con como columnas archivos archivo python file csv random

operaciones - Lee líneas aleatorias de un gran archivo CSV en Python



leer columnas en python (10)

Tengo este gran archivo CSV (15 Gb) y necesito leer alrededor de 1 millón de líneas aleatorias de él. Hasta donde puedo ver, e implementar, la utilidad CSV en Python solo permite iterar secuencialmente en el archivo.

Dedica mucha memoria a leer todo el archivo en la memoria para usar una selección aleatoria y lleva mucho tiempo recorrer todo el archivo y descartar algunos valores y elegir otros, entonces, de todos modos , hay que elegir alguna línea aleatoria del archivo CSV y leer solo esa línea?

Lo intenté sin éxito

import csv with open(''linear_e_LAN2A_F_0_435keV.csv'') as file: reader = csv.reader(file) print reader[someRandomInteger]

Una muestra del archivo CSV:

331.093,329.735 251.188,249.994 374.468,373.782 295.643,295.159 83.9058,0 380.709,116.221 352.238,351.891 183.809,182.615 257.277,201.302 61.4598,40.7106


Tengo este gran archivo CSV (15 Gb) y necesito leer cerca de 1 millón de líneas aleatorias de él

Suponiendo que no necesita exactamente 1 millón de líneas y sepa de antemano el número de líneas en su archivo CSV, puede usar el muestreo de depósito para recuperar su subconjunto aleatorio. Simplemente itere a través de sus datos y para cada línea determine las posibilidades de que se seleccione la línea. De esta forma solo necesita una sola pasada de sus datos.

Esto funciona bien si necesita extraer las muestras aleatorias a menudo, pero el conjunto de datos real cambia con poca frecuencia (ya que solo necesitará realizar un seguimiento del número de entradas cada vez que cambie el conjunto de datos).

chances_selected = desired_num_results / total_entries for line in csv.reader(file): if random() < chances_selected: result.append(line)


En este método, generamos un conjunto de números aleatorios cuyo número de elementos es igual al número de líneas a leer, siendo su rango el número de filas presentes en los datos. Luego se clasifica de menor a mayor y se almacena.

Luego, el archivo csv se lee línea por línea y line_counter está en su lugar para indicar el número de fila. Este line_counter se verifica con el primer elemento de la lista de números aleatorios ordenados y si son iguales, esa línea específica se escribe en el nuevo archivo csv y el primer elemento se elimina de la lista y el segundo elemento anterior toma el lugar del primero y el ciclo continúa.

import random k=random.sample(xrange(No_of_rows_in_data),No_of_lines_to_be_read) Num=sorted(k) line_counter = 0 with open(input_file,''rb'') as file_handle: reader = csv.reader(file_handle) with open(output_file,''wb'') as outfile: a=csv.writer(outfile) for line in reader: line_counter += 1 if line_counter == Num[0]: a.writerow(line) Num.remove(Num[0]) if len(Num)==0: break


Otra solución es posible si conoce el número total de líneas: genere 1 millón de números aleatorios ( random.sample(xrange(n), 1000000) ) hasta el número total de líneas como un conjunto, luego use:

for i, line in enumerate(csvfile): if i in lines_to_grab: yield line

Esto le dará exactamente 1 millón de líneas de una manera imparcial, pero necesita tener el número de líneas de antemano.


Puede usar una variación del método probabilístico para elegir una línea aleatoria en un archivo.

En lugar de simplemente mantener un número único que se elige, puede mantener un buffer de tamaño C Para cada número de línea, n , en el archivo con N líneas, desea elegir esa línea con probabilidad C/n (en lugar de la 1/n original. Si se selecciona el número, entonces elige una ubicación aleatoria desde el C- buffer de longitud para desalojar.

Así es como funciona:

import random C = 2 fpath = ''somelines.txt'' buffer = [] f = open(fpath, ''r'') for line_num, line in enumerate(f): n = line_num + 1.0 r = random.random() if n <= C: buffer.append(line.strip()) elif r < C/n: loc = random.randint(0, C-1) buffer[loc] = line.strip()

Esto requiere una sola pasada a través del archivo (por lo que es tiempo lineal) y devuelve exactamente líneas C del archivo. Cada línea tendrá una probabilidad C/N de ser seleccionada.

Para verificar que todo lo anterior funciona, creé un archivo con 5 líneas que contienen a, b, c, d, e. Ejecuté el código 10.000 veces con C = 2. Esto debería producir una distribución uniforme de los 5 elegir 2 (así que 10) opciones posibles. Los resultados:

a,b: 1046 b,c: 1018 b,e: 1014 a,c: 1003 c,d: 1002 d,e: 1000 c,e: 993 a,e: 992 a,d: 985 b,d: 947


Puede volver a escribir el archivo con registros de longitud fija y luego realizar un acceso aleatorio en el archivo intermedio más adelante:

ifile = file.open("inputfile.csv") ofile = file.open("intermediatefile.csv",''w'') for line in ifile: ofile.write(line.rstrip(''/n'').ljust(15)+''/n'')

Entonces, puedes hacer:

import random ifile = file.open("intermediatefile.csv") lines = [] samples = random.sample(range(nlines)) for sample in samples: ifile.seek(sample) lines.append(ifile.readline())

Requiere más espacio en disco y el primer programa puede tardar un poco en ejecutarse, pero permite el acceso aleatorio ilimitado posterior a los registros con el segundo.


Si las líneas son realmente formato .csv y NO campo fijo, entonces no, no las hay. Puede rastrear el archivo una vez, indexando los desplazamientos de bytes para cada línea, luego, cuando más tarde solo necesite usar el conjunto de índices, pero no hay manera de predecir a priori la ubicación exacta del carácter / n de terminación de línea para archivos csv arbitrarios.


Si puede colocar estos datos en una base de datos sqlite3, seleccionar un número de filas aleatorias es trivial. No necesitará prelectura o líneas de pad en el archivo. Dado que los archivos de datos sqlite son binarios, su archivo de datos será 1/3 a 1/2 más pequeño que el texto CSV.

Puede usar un script como THIS para importar el archivo CSV o, mejor aún, simplemente escriba sus datos en una tabla de base de datos en primer lugar. SQLITE3 es parte de la distribución de Python.

Luego use estas declaraciones para obtener 1,000,000 de filas aleatorias:

mydb=''csv.db'' con=sqlite3.connect(mydb) with con: cur=con.cursor() cur.execute("SELECT * FROM csv ORDER BY RANDOM() LIMIT 1000000;") for row in cur.fetchall(): # now you have random rows...


Si quiere agarrar líneas aleatorias muchas veces (por ejemplo, mini lotes para aprendizaje automático), y no le importa escanear el enorme archivo una vez (sin cargarlo en la memoria), entonces puede crear una lista de líneas indecentes y use busque agarrar rápidamente las líneas (basado en la respuesta de Maria Zverina).

# Overhead: # Read the line locations into memory once. (If the lines are long, # this should take substantially less memory than the file itself.) fname = ''big_file'' s = [0] linelocs = [s.append(s[0]+len(n)) or s.pop(0) for n in open(fname)] f = open(fname) # Reopen the file. # Each subsequent iteration uses only the code below: # Grab a 1,000,000 line sample # I sorted these because I assume the seeks are faster that way. chosen = sorted(random.sample(linelocs, 1000000)) sampleLines = [] for offset in chosen: f.seek(offset) sampleLines.append(f.readline()) # Now we can randomize if need be. random.shuffle(sampleLines)


# pass 1, count the number of rows in the file rowcount = sum(1 for line in file) # pass 2, select random lines file.seek(0) remaining = 1000000 for row in csv.reader(file): if random.randrange(rowcount) < remaining: print row remaining -= 1 rowcount -= 1


import random filesize = 1500 #size of the really big file offset = random.randrange(filesize) f = open(''really_big_file'') f.seek(offset) #go to random position f.readline() # discard - bound to be partial line random_line = f.readline() # bingo! # extra to handle last/first line edge cases if len(random_line) == 0: # we have hit the end f.seek(0) random_line = f.readline() # so we''ll grab the first line instead

Como señaló @AndreBoos, este enfoque conducirá a una selección sesgada. Si conoce la longitud mínima y máxima de la línea, puede eliminar este sesgo haciendo lo siguiente:

Supongamos (en este caso) que tenemos min = 3 y max = 15

1) Encuentra la longitud (Lp) de la línea anterior.

Entonces, si Lp = 3, la línea es más parcial. Por lo tanto, debemos tomarlo el 100% del tiempo Si Lp = 15, la línea es más sesgada hacia. Solo deberíamos tomarlo el 20% del tiempo ya que es 5 * más probable que esté seleccionado.

Logramos esto manteniendo aleatoriamente la línea X% del tiempo donde:

X = min / Lp

Si no mantenemos la línea, hacemos otra selección aleatoria hasta que nuestra tirada de dados sea buena. :-)