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

时间:2011-01-21 08:58:50

标签: r performance load benchmarking

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

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

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

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


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

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

4 个答案:

答案 0 :(得分:39)

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

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

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

> system.time(data <- read.spss('ESS_HUN_4.sav'))
   user  system elapsed 
  2.214   0.030   2.376 

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

> 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 

尝试 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 

尝试使用“微调” 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 

同样使用包 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 

还要从运行在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 

在这里,我认为我们应该添加两个system.time报告,因为在我们的案例中连接数据也很重要。如果我误解了什么,请评论。

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

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

这真的很棒!当然只是在用dbReadTable

加载表格之后

摘要:无需从二进制文件中读取整个数据,但只能从相同的数据库表中读取几列(或其他已过滤的数据)在一些特殊情况下加权。

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


更新(2011年1月24日):我添加了一种相当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)

然后我加载了两列数据:

> 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 

这看起来像一个“超快”的方法! :)注意:它加载比上面的最快(加载整个二进制对象)方法快<100>

我已经制作了一个非常小的包(名为saves),如果感兴趣,可以查看github以获取更多详细信息。


更新(06/03/2011):我的小包(saves)的新版本已上传到CRAN,可以更快地保存和加载变量 - 如果只有用户只需要数据框或列表中可用变量的子集。有关详细信息或vignette上的my homepage,请参阅软件包源代码中的{{3}},并让我介绍一些基准测试的好框图:

Comparison of different data frame/list loading mechanism by speed

此框图显示了使用保存包从基数load加载read.tableread.csvread.spss的变量子集的好处。来自国外或sqldfRMySQL个包裹。

答案 1 :(得分:19)

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

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

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

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

答案 2 :(得分:1)

我对RMySQL很满意。我不确定我的问题是否正确,但标签应该不是问题。有几个便捷函数只使用默认的SQL表和行名,但当然你可以使用一些SQL语句。

我想说(除了证明喧嚣的大数据集之外)使用RMySQL的一个主要原因是熟悉SQL语法而不是R数据杂耍函数。我个人更喜欢GROUP BY而不是聚合。请注意,使用R内部的存储过程并不是特别有效。

底线......设置MySQL本地主机并不是太费劲 - 试一试!我无法确切地说出速度,但我觉得它有可能更快。但是,我会尝试回到这里。

编辑:这是测试......获胜者是:spacedman

# SQL connection
source("lib/connect.R")

dbQuery <- "SELECT * FROM mytable"
mydata <- dbGetQuery(con,dbQuery)
system.time(dbGetQuery(con,dbQuery))
# returns
#user  system elapsed 
# 0.999   0.213   1.715 

save.image(file="speedtest.Rdata")
system.time(load("speedtest.Rdata"))
#user  system elapsed 
#0.348   0.006   0.358 

这里的文件大小只有大约1 MB。 MacBook Pro 4 GB Ram 2.4 GHZ Intel Core Duo,Mac OSX 10.6.4,MySQL 5.0.41 从来没有尝试过,因为我通常使用更大的数据集,加载不是问题,而是处理......如果有时间问题的话。 Q为+1!

答案 3 :(得分:1)

如果可能的话,将数据转换为csv或其他&#34;简单&#34;尽可能快地进行阅读的格式(参见Joris&#39;答案)。我使用csv函数导入apply个文件 en masse ,类似于:

list.of.files <- as.list(list.files("your dir"))
lapply(list.of.files, FUN = function(x) {
    my.object <- read.table(...) # or some other function, like read.spss
})