En R, ¿hay una manera eficiente de leer un archivo transpuesto .csv?

Por ejemplo, considere el siguiente archivo de texto:

Name,Peter,Paul,Marry
Age,40,9,38

Esto podría leerse en un data.table con clases de columna útiles usando:

library(data.table)    
file <-  tempfile("tmp.txt")
writeLines("Name,Peter,Paul,Mary\nAge,40,5,38\n", file)    

lines <- readLines(file)
lines <- lapply(lines, function(x) gsub(pattern=",", replacement="\n", x, fixed=TRUE))
lines <- lapply(lines[-3], fread)
do.call(cbind,lines)
#>     Name Age
#> 1: Peter  40
#> 2:  Paul   5
#> 3:  Mary  38

¿Hay una manera más simple de lograr esto? ¿Existe una versión más eficiente (mi archivo es de 1 GB)?

Tenga en cuenta que dicho almacenamiento en columnas principales debería ser más fácil de leer para un almacenamiento en columnas como en data.table.

6
jan-glx 2 mar. 2018 a las 21:38

4 respuestas

Esta es una implementación del enfoque sugerido por @Dirk Eddelbuettel en los comentarios.

> library(data.table)                                                                                                          
> aTbl = fread("file.csv", colClasses="character", header=F)
> aTbl

     V1    V2   V3   V4
1: Name Peter Paul Mary
2:  Age    40    5   38     

> aTbl[, .SD
       ][, transpose(.SD)
       ][, setnames(.SD, .SD[1, t(.SD)])                                                                                                                   
       ][2:.N                                                                                                                  
       ][, fread(paste0(capture.output(write.csv(.SD, stdout(), row.names=F, quote=F)), collapse='\n'))                        
       ][, {bTbl <<- copy(.SD); .SD}                                                                                           
       ]  

    Name Age                                                                                                                   
1: Peter  40                                                                                                                   
2:  Paul   5                                                                                                                   
3:  Mary  38  

> lapply(bTbl, class)     

$Name                                                                                                                          
[1] "character"                                                                                                                

$Age                                                                                                                           
[1] "integer"                                                                                                                  

> 
3
Clayton Stanley 2 mar. 2018 a las 20:18

Para extender el comentario de @lmo para usar iotools:

  dt <- iotools::chunk.tapply(file(file, "rb"),  function(x) {
    fread(paste0(apply(iotools::mstrsplit(x, sep=","), 2, paste0, collapse = ","), collapse = "\n"))
  }, CH.MERGE = cbind)

Esto es un poco más eficiente que las otras soluciones actuales.

2
jan-glx 4 mar. 2018 a las 22:30

Para extender el comentario de @ngm para usar herramientas de línea de comandos:

  1. descarga: transpose.c
  2. compilar: gcc transpose.c -o transpose
  3. uso: fread(paste0("transpose -t -l 205x20005 --fsep , \"", file, "\""))

Esto requiere conocer el tamaño aproximado de la tabla y requiere terminaciones de línea de un solo carácter, es decir, \n. Es bastante inconveniente, pero más rápido que las otras soluciones.

1
jan-glx 4 mar. 2018 a las 21:39
DT=setDT(read.table(text=do.call(paste,transpose(fread(file,h=F))),h=T,stringsAsFactors = F))
DT
    Name Age
1: Peter  40
2:  Paul   5
3:  Mary  38



sapply(DT,class)
       Name         Age 
"character"   "integer" 
3
Onyambu 2 mar. 2018 a las 19:45