如何快速将数据加载到R?
我有一些R脚本,我必须尽快加载R中的几个dataframe。 这是非常重要的,因为读取数据是程序中最慢的部分。 例如:从不同的数据框绘图。 我以sav(SPSS)格式获取数据,但是我可以按照build议将其转换为任何格式。 不幸的是,合并数据框不是一个选项。
什么可能是加载数据的最快方法? 我在想以下几点:
- 第一次从sav转换成二进制R对象( Rdata ),后来总是加载这个,因为它比
read.spss
。 - 从sav转换到csv文件,并从本主题中讨论的参数中读取数据,
- 还是值得在本地主机上设置一个MySQL后端并从中加载数据呢? 它会更快吗? 如果是这样,我也可以保存variables的任何自定义
attr
值(例如从Spss导入的文件中的variable.labels )? 或者这应该在一个单独的表中完成?
任何其他的想法,欢迎。 预先感谢您的每一个build议!
我根据你给出的答案做了一个小实验,并且还添加了(24/01/2011)一个相当“黑客”,但真正快速的解决scheme,只从一个特殊的二进制文件加载几个variables/列。 后者似乎是我现在可以想象的最快的方法,这就是为什么我编了一个名为“ 保存”的小包来处理这个function。 该包是在“重”发展,任何build议是值得欢迎的!
我将很快发布一个精确的基准testing结果,借助microbenchmark软件包。
这取决于你想要做什么以及如何进一步处理数据。 在任何情况下,如果您始终需要相同的数据集,则从二进制R对象加载总是会更快。 这里的限制速度是硬盘驱动器的速度,而不是R.二进制forms是工作区中dataframe的内部表示,所以不再需要转换。
任何types的文本文件都是不同的故事,因为您总是包含一个开销:每次读入文本文件时,都必须将数据转换为二进制R对象。 我会忘记他们。 它们仅用于将数据集从一个应用程序移植到另一个应用程序。
如果您需要数据的不同部分或不同组合的不同子集,则设置MySQL后端非常有用。 特别是在处理大量数据集时,在开始select行/列之前,您不必加载整个数据集就可以获得相当长的一段时间。 但这只适用于庞大的数据集,因为读取二进制文件比search数据库快得多。
如果数据不是太大,可以将不同的dataframe保存在一个RData文件中,让您有机会简化一些事情。 我经常在列表或单独的环境中有一组数据框(另请参阅?environment
一些简单示例的?environment
)。 这允许lapply
或eapply
解决scheme来处理多个dataframe。
谢谢大家的提示和答案,我做了一些总结和实验的基础上。
下面用公共数据库( 匈牙利ESS 2008 )进行一些testing。 该数据库有1508个情况和508个variables,所以它可能是一个中等规模的数据。 这可能是一个很好的例子(对我来说),但当然有特殊的需求需要一个足够的数据的实验。
从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
还要从在本地主机上运行的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
报告,因为连接数据也算在我们的情况中。 请评论,如果我误解了一些东西。
但让我们看看是否只查询一些variables,例如。 而在大多数情况下绘制我们并不需要所有的dataframe,查询只有两个variables就足以创build一个很好的情节:
> query <-('SELECT c1, c19 FROM data') > system.time(data.sql <- dbGetQuery(con, query)) user system elapsed 0.030 0.000 0.112
这似乎真的很棒! 当然,在用dbReadTable
加载表dbReadTable
总结:没有什么可以从二进制文件中读取整个数据,但是在某些特殊情况下,只读取来自同一个数据库表的几列(或其他过滤的数据)也可能会被加权。
testing环境:采用低端SSD的HP 6715b笔记本电脑(AMD X2 2Ghz,4 Gb DDR2)。
UPDATE(24/01/2011) :我添加了一个相当骇人的,但相当“有创意”的方式只加载一个二进制对象的几列 – 看起来比任何上面检查的方法快得多。
请注意:代码看起来非常糟糕,但仍然非常有效:)
首先,我通过以下循环将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倍 。
我已经编写了一个非常小的包(名为: saving ),如果感兴趣,请在github中查看更多细节。
更新(2011年6月3日) :我的小软件包( 保存 )的新版本上传到CRAN,其中可以更快地保存和加载variables – 如果只有用户只需要一个可用variables的子集数据框或列表。 请参阅封装源代码中的小插图以获取详细信息,或者在我的主页上查看封面源代码,还可以介绍一些基准testing的完美boxplot:
这个boxplot显示了使用RMySQL
软件包只加载一部分variables的优点, 可以从base, read.spss
或者sqldf
或RMySQL
包中load
read.table
或read.csv
。
如果可能的话,把数据转换成csv
或其他“简单”的格式,尽可能快地阅读(参见Joris的回答)。 我使用apply
函数大量导入csv
文件,这些内容包括:
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 })
我对RMySQL很满意。 我不知道我是否以正确的方式得到了您的问题,但标签应该不是问题。 有几个简单的函数只使用默认的SQL表和行名,但是当然你可以使用一些SQL语句。
我会说(除了大数据集certificate这个喧嚣之外),使用RMySQL的主要原因之一是熟悉SQL语法比R数据杂耍函数更熟悉。 就我个人而言,我比GROUP BY更喜欢聚合。 请注意,使用R内部的存储过程并不能很好地工作。
底线…build立一个MySQL的本地主机是不是太多的努力 – 试试吧! 我不能准确的说出速度,但是我有这样的感觉,速度会更快。 不过,我会尽力回到这里。
编辑:这里是testing…和赢家是: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!