如何快速将数据加载到R?

dar*_*zig 36 performance benchmarking load r

我有一些R脚本,我必须尽快在R中加载几个数据帧.这非常重要,因为读取数据是程序中最慢的部分.例如:从不同的数据帧绘图.我以sav(SPSS)格式获取数据,但我可以将其转换为建议的任何格式.不幸的是,合并数据帧不是一个选项.

什么是加载数据的最快方法?我在考虑以下几点:

  • 第一次从sav转换为二进制R对象(Rdata),后来总是加载它,因为它看起来要快得多read.spss.
  • sav转换为csv文件并从主题中讨论的给定参数读取数据,
  • 或者是否值得在localhost上设置MySQL后端并从中加载数据?会更快吗?如果是这样,我还可以保存attr变量的任何自定义值(例如来自Spss导入文件的variable.labels)吗?或者这应该在一个单独的表中完成?

欢迎任何其他想法.感谢您提前提出的每一个建议!


我根据你给出的答案在下面做了一个小实验,并且还添加了(24/01/2011)一个非常"hackish"但非常快速的解决方案,只从一个特殊的二进制文件中加载几个变量/列.后者似乎是我现在能想象的最快的方法,这就是为什么我编写了一个名为save的小包来处理这个功能(05/03/2011:ver.0.3).该套餐正在"重"开发,欢迎任何推荐!

microbenchmark软件包的帮助下,我将很快发布一个具有准确基准测试结果的小插图.

dar*_*zig 39

谢谢大家的提示和答案,我做了一些总结和实验.

请参阅下面的公共数据库(匈牙利的ESS 2008)进行一些测试.该数据库有1508个案例和508个变量,因此它可能是一个中型数据.这可能是(对我而言)进行测试的一个很好的例子,但当然特殊需要需要进行足够数据的实验.

从SPSS sav文件中读取数据而不做任何修改:

> system.time(data <- read.spss('ESS_HUN_4.sav'))
   user  system elapsed 
  2.214   0.030   2.376 
Run Code Online (Sandbox Code Playgroud)

使用转换后的二进制对象加载:

> save('data',file='ESS_HUN_4.Rdata')
> system.time(data.Rdata <- load('ESS_HUN_4.Rdata'))
   user  system elapsed 
   0.28    0.00    0.28 
Run Code Online (Sandbox Code Playgroud)

尝试使用csv:

> write.table(data, file="ESS_HUN_4.csv")
> system.time(data.csv <- read.csv('ESS_HUN_4.csv'))
   user  system elapsed 
  1.730   0.010   1.824 
Run Code Online (Sandbox Code Playgroud)

尝试使用"微调" csv加载:

> system.time(data.csv <- read.table('ESS_HUN_4.csv', comment.char="", stringsAsFactors=FALSE, sep=","))
   user  system elapsed 
  1.296   0.014   1.362 
Run Code Online (Sandbox Code Playgroud)

还有包sqldf,它似乎加载csv文件更快:

> library(sqldf)
> f <- file("ESS_HUN_4.csv")
>  system.time(bigdf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F, sep="\t")))
   user  system elapsed 
  0.939   0.106   1.071 
Run Code Online (Sandbox Code Playgroud)

并且还从在localhost上运行的MySQL数据库加载数据:

> library(RMySQL) 
> con <- dbConnect(MySQL(), user='root', dbname='test', host='localhost', password='')
> dbWriteTable(con, "data", as.data.frame(data), overwrite = TRUE)
> system.time(data <- dbReadTable(con, 'data'))
   user  system elapsed 
  0.583   0.026   1.055 
> query <-('SELECT * FROM data')
> system.time(data.sql <- dbGetQuery(con, query))
   user  system elapsed 
  0.270   0.020   0.473 
Run Code Online (Sandbox Code Playgroud)

在这里,我认为我们应该添加两个system.time报告,因为在我们的情况下连接到数据也是重要的.如果我误解了什么,请评论.

但是让我们看看是否只查询一些变量,例如.在绘图时我们在大多数情况下不需要所有数据帧,只查询两个变量就足以创建一个很好的情节:

> query <-('SELECT c1, c19 FROM data')
> system.time(data.sql <- dbGetQuery(con, query))
   user  system elapsed 
  0.030   0.000   0.112 
Run Code Online (Sandbox Code Playgroud)

这真的很棒!当然只是在加载表后dbReadTable

总结:从二进制文件中读取整个数据没什么可读的,但在某些特殊情况下,也可能只从同一个数据库表中读取几列(或其他过滤数据).

测试环境:配备低端SSD的HP 6715b笔记本电脑(AMD X2 2Ghz,4 Gb DDR2).


更新(24/01/2011):我添加了一个相当hackish但非常"创造性"的方式来加载二进制对象的几列 - 这看起来比上面检查的任何方法快得多.

请注意:代码看起来非常糟糕,但仍然非常有效:)

首先,我通过以下循环将data.frame的所有列保存到不同的二进制对象中:

attach(data)
for (i in 1:length(data)) {
    save(list=names(data)[i],file=paste('ESS_HUN_4-', names(data)[i], '.Rdata', sep=''))
}
detach(data)
Run Code Online (Sandbox Code Playgroud)

然后我加载两列数据:

> system.time(load('ESS_HUN_4-c19.Rdata')) + 
>     system.time(load('ESS_HUN_4-c1.Rdata')) + 
>     system.time(data.c1_c19 <- cbind(c1, c19))
    user  system elapsed 
    0.003   0.000   0.002 
Run Code Online (Sandbox Code Playgroud)

这看起来像一个"超快"的方法!:)注意:它加载速度比上面的最快(加载整个二进制对象)方法快100倍.

我已经组成了一个非常小的包(命名为:save),如果有兴趣的话,请查看github以获取更多详细信息.


更新(06/03/2011):我的小包(保存)的新版本被上传到CRAN,在该版本中可以更快地保存和加载变量 - 如果只有用户只需要可用变量的一部分数据框或列表.请参阅包源中的插图以获取详细信息或我主页上的插图,并让我介绍一些基准测试的好框图:

不同数据帧/列表加载机制的速度比较

这箱线图显示使用的好处可以节省包只加载变量的一个子集对loadread.tableread.csv从基地,read.spss从国外或sqldfRMySQL包.

  • 感谢您运行测试并展示结果.这与我先入为主的观念是一致的,但作为一个猖獗的经验主义者,看到测试是很棒的. (5认同)
  • 你披露了结果很酷.但是,您不应该在一次试验中得出结论.我经常写一个剧本,重复一遍,出去散步,然后在我回来时收紧数据.=)无论如何......`read.csv`明显变慢了,如果你提供`colClasses`参数,你可以让它执行得更快,否则函数会检查每列的类!这是一个阻力.此外,如果绕过`stringsAsFactors`的默认行为,您的对象将占用更多内存.无论如何,谢谢你的细节!=) (4认同)

Jor*_*eys 19

这取决于您想要做什么以及如何进一步处理数据.在任何情况下,只要您始终需要相同的数据集,从二进制R对象加载总是会更快.这里的限制速度是硬盘的速度,而不是R.二进制形式是工作空间中数据帧的内部表示,因此不再需要转换.

任何类型的文本文件都是不同的故事,因为你总是包含一个开销:每次读入文本文件时,数据都必须转换为二进制R对象.我会忘记他​​们.它们仅用于将数据集从一个应用程序移植到另一个应用程序.

如果您需要不同的数据部分或不同组合的不同子集,则设置MySQL后端非常有用.特别是在处理大型数据集时,在开始选择行/列之前不需要加载整个数据集这一事实可以获得相当长的时间.但这仅适用于大型数据集,因为读取二进制文件比搜索数据库要快得多.

如果数据不是太大,您可以将不同的数据帧保存在一个RData文件中,这样您就有机会简化一些事情.我经常在列表或单独的环境中有一组数据帧(另请参阅?environment一些简单示例).这允许lapply/ eapplysolutions一次处理多个数据帧.

  • +1表示"一个RData文件中的不同数据帧".并添加:`my_data <-new.env(); load("my_data.RData",my_data)`是安全的方式(不擦除现有对象)将对象加载到R. (5认同)