2011-01-21 129 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包的變量的子集。