代码之家  ›  专栏  ›  技术社区  ›  dww Jarretinha

高效读取列按行排列的数据文件

  •  1
  • dww Jarretinha  · 技术社区  · 5 年前

    假设我有一个类似csv的数据文件,如下所示,其中数据的“列”排列为行:

    col1,1.1,1.2,3.3
    col2,A,B,C
    col3,TRUE,TRUE,FALSE
    col4,1,2,3
    col5,1,2,3
    col6,1,2,3
    col7,1,2,3
    col8,1,2,3
    col9,1,2,3
    col10,1,2,3
    col11,1,2,3
    col12,1,2,3
    col13,1,2,3
    col14,1,2,3
    col15,1,2,3
    

    如何高效、可靠地将这样的文件读入r中。理想情况下,我希望使用类似于 data.table::fread 它自动确定数据类型。

    对于上面的例子(如果它在一个名为 test.csv ,我可以执行以下操作:

    library(data.table)    
    dt = strsplit(read_lines('test.csv'),',') %>%
      lapply(function(r) fread(paste0(r, collapse ='\n'))) %>%
      as.data.table()
    
    str(dt)
    # Classes ‘data.table’ and 'data.frame':    3 obs. of  15 variables:
    # $ col1 : num  1.1 1.2 3.3
    # $ col2 : chr  "A" "B" "C"
    # $ col3 : logi  TRUE TRUE FALSE
    # $ col4 : int  1 2 3
    # $ col5 : int  1 2 3
    # $ col6 : int  1 2 3
    # $ col7 : int  1 2 3
    # $ col8 : int  1 2 3
    # $ col9 : int  1 2 3
    # $ col10: int  1 2 3
    # $ col11: int  1 2 3
    # $ col12: int  1 2 3
    # $ col13: int  1 2 3
    # $ col14: int  1 2 3
    # $ col15: int  1 2 3
    # - attr(*, ".internal.selfref")=<externalptr> 
    #
    

    不过,这也有一些缺点。除了失去了fread的速度和效率,并且需要提前知道分离器外,它也不是很健壮。

    例如,线

    col4,"hello, world","hello, world","hello, world"
    

    会中断它,因为strsplit不知道逗号是分隔符还是字符串的一部分。

    丢失的数据也有问题:

    col5,1,2,
    

    生产

    警告消息:在data.table(list(col1=c(1.1,1.2,3.3))中, 列表(col2=c(“a”):项5的大小为2,但最大大小为3 (循环使用,剩余1项)

    有没有更好的方法来读取这样的数据?

    1 回复  |  直到 5 年前
        1
  •  2
  •   akrun    5 年前

    一个更简单的选择是在读取数据集之后进行转置,然后执行 type.convert

    dat <- read.csv("test.csv", header = FALSE, stringsAsFactors = FALSE)
    dat2 <- type.convert(setNames(as.data.frame(t(dat[-1]),
            stringsAsFactors = FALSE), dat$V1), as.is = TRUE)
    row.names(dat2) <- NULL
    
    str(dat2)
    #'data.frame':  3 obs. of  15 variables:
    # $ col1 : num  1.1 1.2 3.3
    # $ col2 : chr  "A" "B" "C"
    # $ col3 : logi  TRUE TRUE FALSE
    # $ col4 : int  1 2 3
    # $ col5 : int  1 2 3
    # $ col6 : int  1 2 3
    # $ col7 : int  1 2 3
    # $ col8 : int  1 2 3
    # $ col9 : int  1 2 3
    # $ col10: int  1 2 3
    # $ col11: int  1 2 3
    # $ col12: int  1 2 3
    # $ col13: int  1 2 3
    # $ col14: int  1 2 3
    # $ col15: int  1 2 3
    

    或者我们一起读 fread 然后做同样的转置

    library(data.table)
    dt <- fread("test.csv", header = FALSE)
    type.convert(setNames(as.data.frame(t(dt[, -1, with = FALSE]), 
           stringsAsFactors = FALSE), dt[[1]], as.is = TRUE)
    

    或者正如@frank建议的那样

    fread("test.csv")[, setnames(transpose(.SD[,-1]), .SD[[1]])][, 
            lapply(.SD, type.convert)]