Lectura de 40 GB de archivo csv en R usando bigmemory

El título es bastante explicativo aquí, pero lo elaboraré de la siguiente manera. Algunas de mis técnicas actuales para atacar este problema se basan en las soluciones presentadas en esta pregunta. Sin embargo, me enfrento a varios desafíos y limitaciones, por lo que me preguntaba si alguien podría intentar atacar este problema. Estoy tratando de resolver el problema usando el paquete bigmemory , pero he tenido problemas.

Restricciones actuales:

  • Usando un servidor linux con 16 GB de RAM
  • Tamaño de 40 GB CSV
  • Nº de filas: 67,194,126,114

Desafíos

  • Es necesario poder muestrear aleatoriamente conjuntos de datos más pequeños (5-10 millones de filas) a partir de una matriz de datos grande o equivalente.
  • Es necesario poder eliminar cualquier fila con una instancia única de NULL mientras se analiza en una estructura de datos big.matrix o equivalente.

Hasta ahora, los resultados no son buenos. Evidentemente, estoy fallando en algo o tal vez, simplemente no entiendo bastante bien la documentación de bigmemory . Entonces, pensé que preguntaría aquí para ver si alguien ha usado

¿Algún consejo, consejos sobre esta línea de ataque, etc.? ¿O debería cambiar a algo más? Me disculpo si esta pregunta es muy similar a la anterior, pero pensé que por escala de datos era aproximadamente 20 veces más grande que las preguntas anteriores. Gracias !

No sé sobre bigmemory , pero para satisfacer tus desafíos no necesitas leer el archivo. Simplemente canaliza algunos procesamientos bash / awk / sed / python / whatever para hacer los pasos que quieras, es decir, descartar líneas NULL y selecciona aleatoriamente N líneas, y luego lee eso en.

Aquí hay un ejemplo de uso de awk (suponiendo que desee 100 líneas aleatorias de un archivo que tenga líneas 1M).

 read.csv(pipe('awk -F, \'BEGIN{srand(); m = 100; length = 1000000;} !/NULL/{if (rand() < m/(length - NR + 1)) { print; m--; if (m == 0) exit; }}\' filename' )) -> df 

No era obvio para mí a qué se refería con NULL , así que usé su comprensión literal, pero debería ser fácil modificarlo para adaptarlo a sus necesidades.

Esta es una solución R pura al desafío de tomar muestras de un archivo de texto grande; tiene el mérito adicional de dibujar una muestra aleatoria de exactamente n. No es demasiado ineficiente, aunque las líneas se analizan en vectores de caracteres y esto es relativamente lento.

Comenzamos con una firma de función, donde proporcionamos un nombre de archivo, el tamaño de la muestra que queremos dibujar, una semilla para el generador de números aleatorios (¡para que podamos reproducir nuestra muestra aleatoria!), Una indicación de si hay un encabezado línea, y luego una función de “lector” que usaremos para analizar la muestra en el objeto visto por R, incluyendo argumentos adicionales ... que la función de lector podría necesitar

 fsample <- function(fname, n, seed, header=FALSE, ..., reader=read.csv) { 

La función inicia el generador de números aleatorios, abre una conexión y lee en la línea de encabezado (opcional)

  set.seed(seed) con <- file(fname, open="r") hdr <- if (header) { readLines(con, 1L) } else character() 

El siguiente paso es leer en un trozo de n líneas, inicializando un contador del número total de líneas vistas

  buf <- readLines(con, n) n_tot <- length(buf) 

Continúe leyendo en trozos de n líneas, deteniéndose cuando no haya más información

  repeat { txt <- readLines(con, n) if ((n_txt <- length(txt)) == 0L) break 

Para cada fragmento, dibuje una muestra de líneas n_keep , con el número de líneas proporcional a la fracción del total de líneas en el fragmento actual. Esto asegura que las líneas se muestrean uniformemente sobre el archivo. Si no hay líneas para guardar, pase al siguiente fragmento.

  n_tot <- n_tot + n_txt n_keep <- rbinom(1, n_txt, n_txt / n_tot) if (n_keep == 0L) next 

Elija las líneas que desea conservar y las líneas que debe reemplazar y actualice el búfer

  keep <- sample(n_txt, n_keep) drop <- sample(n, n_keep) buf[drop] <- txt[keep] } 

Cuando se realiza la entrada de datos, analizamos el resultado usando el lector y devolvemos el resultado

  reader(textConnection(c(hdr, buf), header=header, ...) } 

La solución podría ser más eficiente, pero un poco más complicada, al usar readBin y buscar saltos de línea como lo sugiere Simon Urbanek en la lista de distribución de R-devel. Aquí está la solución completa

 fsample <- function(fname, n, seed, header=FALSE, ..., reader = read.csv) { set.seed(seed) con <- file(fname, open="r") hdr <- if (header) { readLines(con, 1L) } else character() buf <- readLines(con, n) n_tot <- length(buf) repeat { txt <- readLines(con, n) if ((n_txt <- length(txt)) == 0L) break n_tot <- n_tot + n_txt n_keep <- rbinom(1, n_txt, n_txt / n_tot) if (n_keep == 0L) next keep <- sample(n_txt, n_keep) drop <- sample(n, n_keep) buf[drop] <- txt[keep] } reader(textConnection(c(hdr, buf)), header=header, ...) }