proyectos ejemplos python pandas random io import-from-csv

ejemplos - Lea una pequeña muestra aleatoria de un gran archivo CSV en un marco de datos de Python



django (8)

El archivo CSV que quiero leer no cabe en la memoria principal. ¿Cómo puedo leer algunas (~ 10K) líneas aleatorias y hacer algunas estadísticas simples en el marco de datos seleccionado?


¡Sin pandas!

import random from os import fstat from sys import exit f = open(''/usr/share/dict/words'') # Number of lines to be read lines_to_read = 100 # Minimum and maximum bytes that will be randomly skipped min_bytes_to_skip = 10000 max_bytes_to_skip = 1000000 def is_EOF(): return f.tell() >= fstat(f.fileno()).st_size # To accumulate the read lines sampled_lines = [] for n in xrange(lines_to_read): bytes_to_skip = random.randint(min_bytes_to_skip, max_bytes_to_skip) f.seek(bytes_to_skip, 1) # After skipping "bytes_to_skip" bytes, we can stop in the middle of a line # Skip current entire line f.readline() if not is_EOF(): sampled_lines.append(f.readline()) else: # Go to the begginig of the file ... f.seek(0, 0) # ... and skip lines again f.seek(bytes_to_skip, 1) # If it has reached the EOF again if is_EOF(): print "You have skipped more lines than your file has" print "Reduce the values of:" print " min_bytes_to_skip" print " max_bytes_to_skip" exit(1) else: f.readline() sampled_lines.append(f.readline()) print sampled_lines

Terminará con una lista de sampled_lines. ¿Qué tipo de estadísticas quieres decir?


Aquí hay un algoritmo que no requiere contar el número de líneas en el archivo de antemano, por lo que solo necesita leer el archivo una vez.

Digamos que quieres m muestras. Primero, el algoritmo mantiene las primeras m muestras. Cuando ve la i-ésima muestra (i> m), con probabilidad m / i, el algoritmo usa la muestra para reemplazar aleatoriamente una muestra ya seleccionada.

Al hacerlo, para cualquier i> m, siempre tenemos un subconjunto de m muestras seleccionadas al azar de las primeras i muestras.

Vea el código a continuación:

import random n_samples = 10 samples = [] for i, line in enumerate(f): if i < n_samples: samples.append(line) elif random.random() < n_samples * 1. / (i+1): samples[random.randint(0, n_samples-1)] = line


El siguiente código lee primero el encabezado y luego una muestra aleatoria en las otras líneas:

import pandas as pd import numpy as np filename = ''hugedatafile.csv'' nlinesfile = 10000000 nlinesrandomsample = 10000 lines2skip = np.random.choice(np.arange(1,nlinesfile+1), (nlinesfile-nlinesrandomsample), replace=False) df = pd.read_csv(filename, skiprows=lines2skip)


Esto no está en Pandas, pero logra el mismo resultado mucho más rápido a través de bash:

shuf -n 100000 data/original.tsv > data/sample.tsv

El comando shuf mezclará la entrada y el argumento y -n indica cuántas líneas queremos en la salida.

Pregunta relevante: https://unix.stackexchange.com/q/108581


La answer de @dlm es genial, pero desde v0.20.0, skiprows acepta un invocable . El invocable recibe como argumento el número de fila.

Si puede especificar qué porcentaje de líneas desea, en lugar de cuántas líneas , ni siquiera necesita obtener el tamaño del archivo y solo necesita leer el archivo una vez. Suponiendo un encabezado en la primera fila:

import pandas as pd import random p = 0.01 # 1% of the lines # keep the header, then take only 1% of lines # if random from [0,1] interval is greater than 0.01 the row will be skipped df = pd.read_csv( filename, header=0, skiprows=lambda i: i>0 and random.random() > p )

O bien, si quiere tomar cada n ésima línea:

n = 100 # every 100th line = 1% of the lines df = pd.read_csv(filename, header=0, skiprows=lambda i: i % n != 0)


Suponiendo que no hay un encabezado en el archivo CSV:

import pandas import random n = 1000000 #number of records in file s = 10000 #desired sample size filename = "data.txt" skip = sorted(random.sample(xrange(n),n-s)) df = pandas.read_csv(filename, skiprows=skip)

Sería mejor si read_csv tuviera un keeprows, o si skiprows tomara un func de devolución de llamada en lugar de una lista.

Con encabezado y longitud de archivo desconocida:

import pandas import random filename = "data.txt" n = sum(1 for line in open(filename)) - 1 #number of records in file (excludes header) s = 10000 #desired sample size skip = sorted(random.sample(xrange(1,n+1),n-s)) #the 0-indexed header will not be included in the skip list df = pandas.read_csv(filename, skiprows=skip)


usar subsample

pip install subsample subsample -n 1000 file.csv > file_1000_sample.csv


class magic_checker: def __init__(self,target_count): self.target = target_count self.count = 0 def __eq__(self,x): self.count += 1 return self.count >= self.target min_target=100000 max_target = min_target*2 nlines = randint(100,1000) seek_target = randint(min_target,max_target) with open("big.csv") as f: f.seek(seek_target) f.readline() #discard this line rand_lines = list(iter(lambda:f.readline(),magic_checker(nlines))) #do something to process the lines you got returned .. perhaps just a split print rand_lines print rand_lines[0].split(",")

algo así debería funcionar, creo