【问题标题】:Read in rows from a CSV using data.table's fread BY GROUP使用 data.table 的 fread BY GROUP 从 CSV 中读取行
【发布时间】:2021-12-29 18:56:49
【问题描述】:

我有一个非常大的 CSV 文件,其中包含数百万行,它是来自多个来源的组合数据集。我有一个字符列/变量来指示行/观察的来源,我想使用 data.table 的 fread 从每个组中读取行的子集。

现在我正在尝试读取 20,000 行来测试我的代码,但前几百万行都来自一个来源,因此我无法从多个来源获取行。有没有办法说从每个 SOURCE 级别读取 20,000 行?所以基本上从每个 BY GROUP 中读取 20,000 行(来源)?

【问题讨论】:

    标签: r data.table grouping fread


    【解决方案1】:

    我想知道在 R 之外做一些事情是否会更好。以awk 为例,在awkgroup.csv 中使用此数据:

    "something","group"
    1,"A"
    2,"A"
    3,"A"
    4,"A"
    5,"A"
    6,"B"
    7,"B"
    8,"B"
    9,"B"
    10,"B"
    11,"C"
    12,"C"
    13,"C"
    14,"C"
    15,"C"
    16,"D"
    17,"D"
    18,"D"
    19,"D"
    20,"D"
    

    我们可以的

    $ awk -F, '$2==inp{line++;if(line<3)print($0)}; $2!=inp{inp=$2;line=0;print($0)};' awkgroup.csv > newdata.csv
    $ cat newdata.csv
    "something","group"
    1,"A"
    2,"A"
    3,"A"
    6,"B"
    7,"B"
    8,"B"
    11,"C"
    12,"C"
    13,"C"
    16,"D"
    17,"D"
    18,"D"
    

    基本演练(尽管我不认为自己是 awk 向导):

    • $2==inp(以及类似的$2!=inp)测试第二列(我们的分组变量)自上一行以来是否发生了变化。 inp 最初未初始化,因此默认为空字符串。

      NB:假设数据是按组排序的。

    • line++;if(line&lt;3)print($0) 是大部分工作,它测试line(我们在当前组中跟踪行的方法)是否小于3(我们在这里使用基于0的line)并打印如果是这样的话。这为我们提供了每组的前 3 行。

    • inp=$2;line=0;print($0) 类似,但在组内的第一行运行;它重置line 计数器,通过分配给inp 设置我们认为当前组的内容,并始终打印(因为这是组中的第一行)。

    我无法让它在 fread(cmd="...") 中正常工作,可能是因为它(出于某些原因)使用 shell 代替了公认的也坏了(但不是 这里system可以使用system 并控制输出的去向,然后正常读取,也许

    system2("awk", c("-F, '$2==inp{line++;if(line<3)print($0);};$2!=inp{inp=$2;line=0;print($0)};'",
                     "awkgroup.csv"),
            stdout="awkout.csv" )
    fread("awkout.csv")
    #     something  group
    #         <int> <char>
    #  1:         1      A
    #  2:         2      A
    #  3:         3      A
    #  4:         6      B
    #  5:         7      B
    #  6:         8      B
    #  7:        11      C
    #  8:        12      C
    #  9:        13      C
    # 10:        16      D
    # 11:        17      D
    # 12:        18      D
    

    仅供参考,system2 并不比system 好:它只是将引用的(好!)command= 与所有未引用的args(坏!)连接起来:

      command <- paste(c(shQuote(command), env, args), collapse = " ")
    

    这就是为什么我能够稍微作弊并将所有awkargs= 组合成一个向量。

    从这里开始,你需要控制两件事:

    • $2(在三个位置)更改为分组变量的列号;
    • &lt; 3 更改为您想要的任何限制(请记住,它是从0 开始的,所以&lt; 3 为您提供3 个条目,而不是2 个)。

    【讨论】:

      【解决方案2】:

      一种可能的解决方案是使用vroom package 仅读取“组”列,即

      library(tidyverse)
      library(vroom)
      df <- vroom("file.csv", col_select = group)
      

      然后在“块”中对行号进行采样,按组分组:

      df2 <- df %>%
        mutate(rownumber = row_number()) %>%
        group_by(group) %>% 
        slice_head(n = 20000) %>%
        ungroup() %>%
        select(rownumber)
      

      然后使用this approach 选择每个块中的行(每个块调用一次 fread)并将它们绑定在一起,即

      library(data.table)
      s <- df2$rownumber
      v <- (1:1e5 %in% s)
      idx  <- c(0, cumsum(seq$lengths))[which(seq$values)] + 1
      indx <- data.frame(start=idx, length=seq$length[which(seq$values)])
      result <- do.call(rbind,apply(indx,1, function(x) return(fread("test.csv",nrows=x[2],skip=x[1]))))
      

      我没有任何大文件来测试这个,但如果这种方法不适合你,我可以帮助解决问题。如果您的数据集太大,也可以考虑使用外部程序(例如 AWK)作为解决方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-22
        • 1970-01-01
        • 2018-02-11
        • 2015-10-14
        相关资源
        最近更新 更多