anexar múltiples tablas de datos grandes; coerción de datos personalizada usando colClasses y fread; tuberías con nombre

[Este es un tipo de múltiples informes de errores / solicitudes de características en una publicación, pero no necesariamente tienen sentido de forma aislada. Disculpas por el monstruo puesto de antemano. Publicar aquí como lo sugiere la ayuda (tabla de datos). Además, soy nuevo en R; así que disculpas si no estoy siguiendo las mejores prácticas en mi código a continuación. Lo estoy intentando.]

1.rbindlist Fallo en archivos 6 * 8GB (tengo 128 GB de RAM)

Primero quiero informar que el uso de rbindlist para adjuntar data.tables grandes hace que R segfault (ubuntu 13.10, la versión 3.0.1-3ubuntu1 empaquetada, data.table instalada desde R desde CRAN). La máquina tiene 128 GiB de RAM; por lo tanto, no debería estar quedando sin memoria dado el tamaño de los datos.

Mi código:

append.tables <- function(files) {
    moves.by.year <- lapply(files, fread)
    move <- rbindlist(moves.by.year)
    rm(moves.by.year)
    move[,week_end := as.Date(as.character(week_end), format="%Y%m%d")]
    return(move)
}

Mensaje de error:

 append.tables crashes with this:
> system.time(move <- append.tables(files))
 *** caught segfault ***
address 0x7f8e88dc1d10, cause 'memory not mapped'

Traceback:
 1: rbindlist(moves.by.year)
 2: append.tables(files)
 3: system.time(move <- append.tables(files))

Hay 6 archivos, cada uno de aproximadamente 8 GiB o 100 millones de líneas con 8 variables, separadas por tabulaciones.

2. podríafread aceptar varios nombres de archivo?

En cualquier caso, creo que un mejor enfoque aquí sería permitir que fread tome archivos como un vector de nombres de archivos:

files <- c("my", "files", "to be", "appended")
dt <- fread(files)

Presumiblemente, puede ser mucho más eficiente en memoria bajo el capó que sin tener que mantener todos estos objetos alrededor al mismo tiempo que parece ser necesario para un usuario de R.

3.colClasses da un mensaje de error

Mi segundo problema es que necesito especificarun controlador de coerción personalizado para uno de mis tipos de datos, pero eso falla:

dt <- fread(tfile, colClasses=list(date="myDate"))
Error in fread(tfile, colClasses = list(date = "myDate")) : 
  Column name 'myDate' in colClasses not found in data

Sí, en el caso de las fechas, un simple:

    dt[,date := as.Date(as.character(date), format="%Y%m%d")]

trabajos.

Sin embargo, tengo un caso de uso diferente, que es quitar el punto decimal de una de las columnas de datos antes de que se convierta de un carácter. La precisión aquí es extremadamente importante (por lo tanto, nuestra necesidad de usar el tipo entero), y la coacción a un entero del tipo doble resulta en una precisión perdida.

Ahora, puedo solucionar esto con algunas llamadas al sistema () para agregar los archivos y canalizarlos a través de alguna magia sed (simplificada aquí) (donde tfile es otro archivo temporal):

if (has_header) {
    tfile2 <- tempfile()
    system(paste("echo fakeline >>", tfile2))
    system(paste("head -q -n1", files[[1]], ">>", tfile2))
    system(paste("tail -q -n+2", tfile2, paste(files, collapse=" "),
                 " | sed 's/\\.//' >>", tfile), wait=wait)
    unlink(tfile2)
} else {
    system(paste("cat", paste(files, collapse=" "), ">>", tfile), wait=wait)
}

pero esto implica un ciclo extra de lectura / escritura. Tengo 4 TiB de datos para procesar, que es MUCHO de lectura y escritura adicionales (no, no todos en una tabla de datos. Alrededor de 1000 de ellos).

4.fread piensa que las tuberías con nombre son archivos vacíos

Normalmente dejo esperar = VERDADERO. Pero estaba tratando de ver si podía evitar el ciclo adicional de lectura / escritura haciendo que el archivo fuera una tubería con nombresystem('mkfifo', tfile), configurando wait = FALSE, y luego ejecutando fread (tfile). Sin embargo, fread se queja de que la tubería es un archivo vacío:

system(paste("tail -q -n+2", tfile2, paste(files, collapse=" "),
             " | sed 's/\\.//' >>", tfile), wait=FALSE)
move <- fread(tfile)
Error in fread(tfile) : File is empty: /tmp/RtmpbxNI1L/file78a678dc1999

En cualquier caso, esto es un poco de un hack.

Código simplificado si tuviera mi lista de deseos

Idealmente, podría hacer algo como esto:

setClass("Int_Price")
setAs("character", "Int_Price",
    function (from) {
        return(as.integer(gsub("\\.", "", from)))
    }
)

dt <- fread(files, colClasses=list(price="Int_Price"))

Y luego tendría un buen tiempodata.table con datos debidamente coaccionados.

Respuestas a la pregunta(1)

Su respuesta a la pregunta