2011-01-21 97 views
35

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

什么是加载数据的最快方式?我想下面的:

  • SAV在第一时间转换为二进制[R对象(RDATA),后来一直加载这个,因为它似乎比read.spss快了很多。
  • SAV变换CSV文件和读取数据,从那些在this话题讨论给定的参数,
  • 还是值得设置从使localhost和负载数据MySQL后端?它会更快吗?如果是这样,我是否也可以保存变量的任何自定义attr值(例如,从Spss导入的文件中的variable.labels)?或者这应该在一个单独的表中完成?

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


我做了一个小实验below根据您已经给出了答案,并且还增加了从一个特殊(24/01/2011)相当“的hackish”,但真正迅速解决装载只有几个变量/列二进制文件。后者似乎是我现在所能想象的最快速的方法,这就是为什么我做了(05/03/2011:版本0.3)小型封装命名saves处理此功能。该软件包正处于“重度”开发阶段,欢迎任何推荐!

我很快会上传与microbenchmark包的帮助下准确的基准测试结果一个小插曲。

+2

恭喜你:你有一个闪亮的新SSD的商业案例! – 2011-01-21 12:00:21

+1

@Richie Cotton:你是对的:)但是要告诉你实话:我在附有SSD的机器上运行我的脚本,我想微调代码。 – daroczig 2011-01-21 12:36:51

回答

19

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

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

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

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

+5

对于“一个RData文件中的不同数据帧”+1。并添加:`my_data <-new.env(); load(“my_data.RData”,my_data)`是安全的方法(不消除现有对象)将对象加载到R. – Marek 2011-01-21 10:41:28

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英特尔酷睿双核,Mac OSX版10.6.4中,MySQL 5.0.41 只是从来没有尝试过,因为我通常是更大的数据集和装载工作不是问题,而处理......如果有时间问题。 Q为+1!

+3

我无法想象RDBMS将如何比从本地硬盘拾取.RData文件更快(如果是SSD,则更是如此)。迫不及待地想看看一些真正的测试。必须将各种开销从MySQL的线路格式转换为R. – Spacedman 2011-01-21 09:56:18

+0

也要感谢您的答案和测试!我也做了一些实验,看看我的答案。看起来好像是二进制数据赢得了:) – daroczig 2011-01-21 12:17:56

1

如果完全有可能,请将数据转换为csv或其他“简单”格式以尽可能快地阅读(请参阅Joris的回答)。我导入csv文件集体apply功能,沿着线的东西:

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 
}) 
36

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

请参阅下面的公共数据库(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 

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

> 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 

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

T以 “微调” CSV rying加载:

> 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 

而且还加载从数据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)。


UPDATE(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) 

然后我加载数据的两列:

> 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查看更多详情。


UPDATE(2008.02.04):我的小封装(saves)的新版本被上传到CRAN,其中可以保存和加载变量甚至更快 - 只要用户只需要数据框或列表中可用变量的一个子集。具体细节看包的来源或my homepage的一个vignette,并且还让我介绍一些基准的一个很好的箱线完成:

Comparison of different data frame/list loading mechanism by speed

这箱线图显示使用的利益节省包加载仅基于loadread.tableread.tableread.csv的变量的子集,来自外部的read.spss或来自sqldfRMySQL包的变量的子集。

相关问题