首页 文章

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

提问于
浏览
35

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

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

  • 在第一次从sav转换为二进制R对象(Rdata),之后总是加载它,因为它似乎比 read.spss 快得多 .

  • 从sav转换为csv文件,并从this主题中讨论的给定参数中读取数据,

  • 还是值得在localhost上设置MySQL后端并从中加载数据?会更快吗?如果是这样,我还可以保存变量的任何自定义 attr 值(例如来自Spss导入文件的variable.labels)吗?或者这应该在一个单独的表中完成?

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


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

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

4 回答

  • 1

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

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

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

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

  • 1

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

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

    尝试使用"fine-tuned" 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 加载表后

    Summary: 没有什么比从二进制文件读取整个数据更好了,但是从同一个数据库表中只读取几列(或其他过滤数据)也可能会在某些特殊情况下加权案例 .

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


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

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

    首先,我通过以下循环将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
    

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

    我已经制作了一个非常小的包(名为:saves),如果感兴趣的话,请查看github了解更多细节 .


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

    Comparison of different data frame/list loading mechanism by speed

    此框图显示了使用保存包仅从基础 loadread.tableread.csv 从基础, read.spss 从外部或 sqldfRMySQL 包加载变量子集的好处 .

  • 19

    如果可能的话,将数据转换为 csv 或其他"simple"格式,以便尽快读取(请参阅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
    })
    
  • 38

    我对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从未尝试过,因为我通常使用更大的数据集并且加载不是问题,而是处理...如果有时间问题一点都不1为Q!

相关问题