【问题标题】:faster than scan() with Rcpp?比使用 Rcpp 的 scan() 更快?
【发布时间】:2012-01-30 09:28:37
【问题描述】:

即使使用scan(..., what="numeric", nmax=5000) 或类似的技巧,在我的机器上将~5x10^6 数值从文本文件读取到R 中的速度相对较慢(几秒钟,我读取了几个这样的文件)。为此类任务尝试Rcpp 包装器是否值得(例如Armadillo 有一些实用程序可以读取文本文件)? 或者我可能会因为预期的接口开销而浪费我的时间以获得几乎没有性能提升?我不确定目前是什么限制了速度(机器内在性能,还是其他?)这是一项我每天重复多次的任务,通常,文件格式始终相同,1000 列,大约 5000 行。

如果需要,这里有一个示例文件可供使用。

nr <- 5000
nc <- 1000

m <- matrix(round(rnorm(nr*nc),3),nr=nr)

cat(m[1, -1], "\n", file = "test.txt") # first line is shorter
write.table(m[-1, ], file = "test.txt", append=TRUE,
            row.names = FALSE, col.names = FALSE)

更新:我尝试了 read.csv.sqlload("test.txt", arma::raw_ascii) 使用犰狳,两者都比 scan 解决方案慢。

【问题讨论】:

  • 在 sqldf 中尝试read.csv.sql 看看是否更快。它只是一行代码。 sqldf.googlecode.com
  • 我试过system.time(b &lt;- read.csv.sql("test.txt", header = FALSE, sep = " ")),它比system.time(a &lt;- scan("test.txt", what="numeric"))慢。另外,我认为将数据存储到矩阵中应该比 data.frame 更有效

标签: r rcpp armadillo


【解决方案1】:

我强烈建议在data.table 的最新版本中查看fread。 CRAN (1.8.6) 上的版本还没有fread(在本文发布时),因此如果您从 R-forge 的最新源安装,您应该能够获得它。见here

【讨论】:

    【解决方案2】:

    请记住,我不是 R 专家,但也许这个概念也适用于这里:通常读取二进制文件比读取文本文件快得多。如果您的源文件不经常更改(例如,您在同一数据上运行不同版本的脚本/程序),请尝试通过 scan() 读取它们一次并将它们以二进制格式存储(手册中有一个章节是关于导出二进制文件)。 从那里你可以修改你的程序来读取二进制输入。

    @Rcpp:scan() 和朋友可能会调用本机实现(如 fscanf()),因此通过 Rcpp 编写自己的文件读取函数可能不会提供巨大的性能提升。不过,您仍然可以尝试(并针对您的特定数据进行优化)。

    【讨论】:

    • re Rcpp,是的,这是我的担心:实现它只是为了看到它与scan() 执行相同。我希望有人可能已经弄清楚了。
    • 我希望它更快,但当然不那么通用。
    【解决方案3】:

    向巴蒂斯特致敬,

    数据输入/输出是一个巨大的话题,以至于 R 自带了自己的manual on data input/output

    R 的基本功能可能会很慢,因为它们非常通用。如果您知道您的格式,您可以轻松地为自己编写一个更快的导入适配器。如果你也知道你的尺寸,那就更容易了,因为你只需要一个内存分配。

    编辑: 作为第一个近似值,我会编写一个 C++ 十行代码。打开一个文件,读取一行,将其分解为标记,分配给vector&lt;vector&lt; double &gt; &gt; 或类似的东西。即使您在单个矢量元素上使用push_back(),您也应该与scan() 竞争,我想。

    我曾经有过一个简洁的 csv reader 类 C++,它基于 Brian Kernighan 自己的代码。相当通用(对于 csv 文件),相当强大。

    然后,您可以按您认为合适的方式压缩性能。

    进一步编辑: 这个SO question 有许多关于 csv 阅读案例的指针,以及对 Kernighan 和 Plauger 书的引用。

    【讨论】:

    • 我不知道确切的尺寸(好吧,一些 unix 工具可以找到),但 5000 是一个很好的粗略估计值
    【解决方案4】:

    是的,您几乎可以肯定可以创建比read.csv/scan 更快的东西。但是,对于高性能文件读取,有一些现有的技巧已经让你走得更快,所以你所做的任何事情都会与这些技巧竞争。

    正如 Mathias 所暗示的,如果您的文件不经常更改,那么您可以通过调用 save 缓存它们,然后使用 load 恢复它们。 (请务必使用ascii = FALSE,因为读取二进制文件会更快。)

    其次,正如 Gabor 所提到的,通过将文件读入数据库,然后从该数据库读入 R,通常可以显着提升性能。

    第三,可以通过HadoopStreaming包来使用Hadoop的文件读取能力。

    有关这些技术的更多想法,请参阅Quickly reading very large tables as dataframes in R

    【讨论】:

    • 谢谢。我想我已经使用了该 SO 线程中的所有提示,不,将数据保存为 .rda 或其他方式并不是一个真正的选择,因为它是第一个困扰我的导入。我会检查sqldf,我曾简要考虑过,但语法让我感到困惑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    • 2023-03-07
    • 1970-01-01
    相关资源
    最近更新 更多