簡體   English   中英

將多個csv文件更快地讀入data.table R.

[英]Reading multiple csv files faster into data.table R

我有900000個csv文件,我想把它們組合成一個大的data.table 對於這種情況,我創建了一個for loop ,逐個讀取每個文件並將它們添加到data.table 問題是它的執行速度變慢,所用的時間呈指數級增長。 如果有人可以幫助我讓代碼運行得更快,那就太棒了。 每個csv文件都有300行和15列。 我到目前為止使用的代碼:

library(data.table)
setwd("~/My/Folder")

WD="~/My/Folder"
data<-data.table(read.csv(text="X,Field1,PostId,ThreadId,UserId,Timestamp,Upvotes,Downvotes,Flagged,Approved,Deleted,Replies,ReplyTo,Content,Sentiment"))

csv.list<- list.files(WD)
k=1

for (i in csv.list){
  temp.data<-read.csv(i)
  data<-data.table(rbind(data,temp.data))

  if (k %% 100 == 0)
    print(k/length(csv.list))

  k<-k+1
}

假設您的文件是傳統的csv,我會使用data.table::fread因為它更快。 如果您使用的是類Linux操作系統,我會使用它允許shell命令的事實。 假設您的輸入文件是我要執行的文件夾中唯一的csv文件:

dt <- fread("tail -n-1 -q ~/My/Folder/*.csv")

您需要手動設置列名稱。

如果你想把東西保存在R中,我會使用lapplyrbindlist

lst <- lapply(csv.list, fread)
dt <- rbindlist(lst)

你也可以使用plyr::ldply

dt <- setDT(ldply(csv.list, fread))

這樣做的好處是可以使用.progress = "text"來讀取讀取進度。

以上所有假設文件都具有相同的格式並具有標題行。

在使用plyr::ldply Nick Kennedy的答案的基礎上,通過啟用.parallel選項,同時讀取400 csv文件大約30-40 MB,大約提高了50%的速度。

帶進度條的原始答案

dt <- setDT(ldply(csv.list, fread, .progress="text")

使用文本進度條啟用.parallel

library(plyr)
library(data.table)
library(doSNOW)

cl <- makeCluster(4)
registerDoSNOW(cl)

pb <- txtProgressBar(max=length(csv.list), style=3)
pbu <- function(i) setTxtProgressBar(pb, i)
dt <- setDT(ldply(csv.list, fread, .parallel=TRUE, .paropts=list(.options.snow=list(progress=pbu))))

stopCluster(cl)

正如@Repmat所建議的那樣,使用rbind.fill。 正如@Christian Borck所建議的,使用fread來獲得更快的讀取速度。

require(data.table)
require(plyr)

files <- list.files("dir/name")
df <- rbind.fill(lapply(files, fread, header=TRUE))

或者你可以使用do.call,但rbind.fill更快( http://www.r-bloggers.com/the-rbinding-race-for-vs-do-call-vs-rbind-fill/

df <- do.call(rbind, lapply(files, fread, header=TRUE))

或者你可以使用data.table包, 看看這個

您正在for循環中增長數據表 - 這就是為什么它需要永遠。 如果要保持for循環不變,首先要創建一個空數據框(在循環之前),它具有您需要的尺寸(行x列),並將其放在RAM中。

然后在每次迭代中寫入此空幀。

否則使用包plyr中的rbind.fill - 並避免循環altogehter。 要使用rbind.fill:

require(plyr)
data <- rbind.fill(df1, df2, df3, ... , dfN)

要傳遞df的名稱,您可以/應該使用apply函數。

我使用@Repmat作為當前的解決方案,使用rbind()每次調用時都會在內存中復制整個data.table(這就是為什么時間呈指數級增長)。 雖然另一種方法是創建一個空的csv文件,首先只包含標題,然后只需將所有文件的數據附加到此csv文件中。

write.table(fread(i), file = "your_final_csv_file", sep = ";",
            col.names = FALSE, row.names=FALSE, append=TRUE, quote=FALSE)

這樣您就不必擔心將數據放入data.table中的正確索引。 另外作為提示: fread()是data.table文件閱讀器,它比read.csv快得多。

在generell中,R不會是我數據修改任務的首選。

一個建議是首先將它們合並為10個左右,然后合並這些組,依此類推。 這樣做的好處是,如果單個合並失敗,您就不會失去所有工作。 你現在這樣做的方式不僅會導致執行速度呈指數級增長,而且每次失敗都會讓你不得不從一開始就重新開始。

這種方式也將減少rbind調用中涉及的數據幀的平均大小,因為它們中的大多數將被附加到小數據幀,並且最后只有幾個大數據幀。 這應該消除指數增長的大部分執行時間。

我想無論你做什么,都會有很多工作要做。

在假設您可以信任所有輸入數據並且每條記錄肯定是唯一的情況下要考慮的一些事項:

  • 考慮創建導入的表而不使用索引。 隨着索引變得越來越大,在導入過程中管理它們的時間越來越長 - 所以聽起來這可能正在發生。 如果這是您的問題,稍后創建索引仍需要很長時間。

  • 或者,根據您正在討論的數據量,您可能需要考慮一種分區數據的方法(通常通過日期范圍完成)。 根據您的數據庫,您可以擁有單獨索引的分區 - 簡化索引工作。

  • 如果演示代碼無法解析為數據庫文件導入實用程序,則使用此類實用程序。

  • 在導入文件之前,可能需要將文件處理為更大的數據集。 例如,您可以在加載前將100個文件合並為一個較大的文件並比較時間來試驗這一點。

如果您無法使用分區(取決於環境和數據庫人員的經驗),您可以使用自制的方法將數據分隔到各種表中。 例如data201401到data201412。 但是,您必須使用自己的實用程序來跨邊界查詢。

雖然絕對不是一個更好的選擇,但你可以在緊要關頭做一些事情 - 它可以讓你輕松退休/過期老年記錄而無需調整相關指數。 如果需要,它還允許您通過“分區”加載預處理的傳入數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM