【问题标题】:Fastest way in R to read and compare CSV filesR 中读取和比较 CSV 文件的最快方法
【发布时间】:2021-10-15 04:44:58
【问题描述】:

我知道关于堆栈溢出还有其他关于在 R 中读取 csv 文件的最快方法的问题 - 并且已经得到解答; data.table 似乎是要走的路。但我有额外的要求。

我需要想出一个脚本来设置两组向量之间的差异操作(以查找两个向量中匹配的值的计数)。两组向量都将从两个不同目录 dirA 和 dirB 中的 csv 文件中获取。将 dirA 中的每个向量与 dirB 中的所有向量进行比较,并记录匹配数。 dirA 有大约 50 个文件,而 dirB 有 3000 个不同大小的文件(1 到 60 MB)。

以下是我使用 R 进行的尝试。它没有我预期的那么快(与在 Pandas 中实现的类似解决方案相比,此代码慢了 30%)。一次读取 3000 个文件需要 120 多秒。是否有我遗漏的东西,或者这是我在 R 中能得到的最好的东西——我是通过巧妙地一次性使用矢量化和多重比较来实现的?任何帮助表示赞赏。谢谢。

  • 我正在使用 data.table 版本 1.13.6。
  • 我想将所有内容都读取为字符串(有前导零和其他一些异常)

代码:

path_dirA <- "data/processed_data_dirA"
path_dirB <- "data/processed_data_dirB"

fn_dirA <- list.files(here(path_dirA), pattern="csv")
fn_dirB <- list.files(here(path_dirB), pattern="csv")
v_count_matched <- integer()

for (fn1 in fn_dirA) {
  f1 <- data.table::fread(here(fn_dirA, fn1), colClasses = 'character')
 
  for (fn2 in fn_dirB) {
    f2 <- data.table::fread(here(fn_dirB, fn2), colClasses = 'character')
    v_count_matched <- c(v_count_matched, length( fintersect(f1[,1],f2[,1]) ) )

    }
  }
}

【问题讨论】:

  • 在某些情况下,vroom 在摄取文件方面比 data.table 更快,因为它为延迟加载编制索引。可能值得一试。 github.com/r-lib/vroom
  • 不是将length( fintersect(f1[,1],f2[,1]) )连接到v_count_matched循环的每次迭代,而是创建一个向量v_count_matched,它是fn_dirA的长度,并像v_count_matched[fn1] = length( fintersect(f1[,1],f2[,1]) )一样填充它。
  • 查看R Inferno 的第 2 圈。问题可能在于不断追加而不是读取文件。
  • 如果您只比较第一列,则只能读取该列(在fread 中带有select 参数)。
  • 尝试更新data.table,最近有一些性能改进可能会影响您的情况。

标签: r csv data.table


【解决方案1】:

我已经接受了基于以前有效的答案。但是,我可以通过简单地添加 setkey 来大大减少执行时间。整个过程现在需要 6 个小时而不是几天!

【讨论】:

    【解决方案2】:

    对于这种特殊情况,大部分时间都用于读取 CSV 文件。 如果您能够以更快的读取时间将这些 CSV 文件以另一种格式缓存在磁盘上,您将获得最大的节省。

    例如,如果您需要每天重复比较,但只更改了一个 CSV。

    您可以将这些 CSV 文件以fst 格式保存(缓存在磁盘上)。 https://www.fstpackage.org/

    【讨论】:

    • vroom 包在这种情况下没有用,因为它的优点是延迟加载。但是您确实需要从文件中读取所有内容。
    • 文件夹 B 中的文件集不会经常更改。将它们转换为 fst 很有帮助,实际上节省了最多的时间;接受这个答案。其他答案也有助于建立我的理解。所以谢谢大家。
    【解决方案3】:

    一种可能的加速方法是使用索引来添加数据而不是连接:

    fn_dirA <- list.files(here(path_dirA), pattern="csv")
    fn_dirB <- list.files(here(path_dirB), pattern="csv")
    v_count_matched <- vector(NA, length(fn_dirA)*length(n_dirA))
    
    
    counter = 0
    for (fn1 in fn_dirA) {
      f1 <- data.table::fread(here(fn_dirA, fn1), colClasses = 'character')
     
      for (fn2 in fn_dirB) {
        counter = counter + 1
        f2 <- data.table::fread(here(fn_dirB, fn2), colClasses = 'character')
        v_count_matched[counter] <- length( fintersect(f1[,1],f2[,1]))
    
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-07-31
      • 2015-09-13
      • 2014-09-26
      • 1970-01-01
      • 2017-11-10
      • 1970-01-01
      • 2017-01-24
      • 1970-01-01
      • 2016-11-12
      相关资源
      最近更新 更多