替代 cat() 和 sprintf() 以更快地将输出写入文件

Alternative of cat() and sprintf() to write output faster in a file

我是 R 的新手,正在预处理百万行的大数据以标记连接的组件并将输出发送到文件。但是使用 for 循环和 cat() 需要花费大量时间。有没有其他方法可以在 R 中以最快的方式写入输出文件?我正在分享一个代码示例。任何替代方法或使用使其更高效的函数重写它都将受到高度赞赏。

#Simple example of undirected graph
g <- graph_from_literal(a--b, a--c, b--c, d--e)
plot(g)

#Connected components
#The option, mode, is ignored for undirected graphs
comp <- components(g, mode = "weak")

#output to a file
fout <- file("output.txt", "w")
for (v in V(g)) {

  vn <- V(g)$name[v]
  comp_id <- comp$membership[vn][[1]]
  comp_size <- comp$csize[comp_id]
  cat(sprintf("%s\t%s\t%s\n", vn, comp_id, comp_size), file=fout)

}

close(fout)

(注意买者:我没有你的任何数据,所以这是未经测试的。)

不要在循环中每次 写入,而是生成一个字符串向量(每个一个文件行)并在最后写入一次。这种类型的文件 I/O 效率更高。

all_lines <- sapply(V(g), function(v) {
  vn <- V(g)$name[v]
  comp_id <- comp$membership[vn][[1]]
  comp_size <- comp$csize[comp_id]
  sprintf("%s\t%s\t%s\n", vn, comp_id, comp_size)
})
writeLines(all_lines, "output.txt")

sapply 的使用是 R 的一种效率,就像 "vectors of things" 一样。虽然这不是绝对必要的(这可以通过 for 循环来完成,但需要采取一些预防措施才能 而不是 非常低效,尤其是在处理百万行),一旦可以 "grok" 矢量力学的意图,它可能会变得更容易理解和处理。

似乎一切都被向量化了,不需要 for 循环。这给出相同的输出并使用 data.table::fwrite,这将比 cat.

快很多
vv = V(g)
vn = vv$name
comp_id = comp$membership[vv$name]
comp_size = comp$csize[comp_id]
data.table::fwrite(data.table(vn, comp_id, comp_size), "output.txt", col.names = FALSE, sep = "\t")

如果您不想要数据 table 依赖项,您可以使用 base::write.table,这仍然比您自己将带有制表符的字符串粘贴在一起更好。

我遇到了类似的问题,即如何将 300 万(短)行写入文本文件。我发现使用 writeChar 可以加快文件写入过程(从几分钟到几秒)。

下面,我在您的代码中将 cat 替换为 writeChar

g <- graph_from_literal(a--b, a--c, b--c, d--e)
plot(g)

#Connected components
#The option, mode, is ignored for undirected graphs
comp <- components(g, mode = "weak")


# first clean the file if it exists
fout <- file("output.txt", "wb")
close(fout)

# switch in appending mode
fout <- file("output.txt", "ab")

for (v in V(g)) {
  
  vn <- V(g)$name[v]
  comp_id <- comp$membership[vn][[1]]
  comp_size <- comp$csize[comp_id]
  # set eos = NULL to avoid NULL terminators
  writeChar(sprintf("%s\t%s\t%s\n", vn, comp_id, comp_size), con = fout, eos = NULL)
}

close(fout)