【问题标题】:Efficiently read data files where columns are arranged in rows高效读取列按行排列的数据文件
【发布时间】:2019-07-17 01:45:37
【问题描述】:

假设我有一个类似 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)) 中, list(col2 = c("A", : Item 5 的大小为 2,但最大大小为 3 (回收剩下 1 件)

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

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    一个更简单的选择是在读取数据集后转置,然后执行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)]
    

    【讨论】:

    • 在一些长而宽的数据上进行了测试,速度非常快。还使用丢失的数据进行了测试,它处理得很好。谢谢
    • @dww 我没有完全测试它。我猜代码有效
    • @dww 当然可以。
    • data.table方式可以使用转置函数,例如fread(x)[, setnames(transpose(.SD[,-1]), .SD[[1]])][, lapply(.SD, type.convert)]而不是t
    猜你喜欢
    • 1970-01-01
    • 2021-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 2021-10-05
    相关资源
    最近更新 更多