2017-04-24 117 views
3

我想多個CSV文件合併成一個單一的數據幀,並試圖操縱使用for循環生成的數據幀。結果數據幀的行數可能在1,500,000到2,000,000之間。優化對於嵌套的循環,如果R中

我使用了相同下面的代碼。

setwd("D:/Projects") 
library(dplyr) 
library(readr) 
merge_data = function(path) 
{ 
    files = dir(path, pattern = '\\.csv', full.names = TRUE) 
    tables = lapply(files, read_csv) 
    do.call(rbind, tables) 
} 


Data = merge_data("D:/Projects") 
Data1 = cbind(Data[,c(8,9,17)],Category = "",stringsAsFactors=FALSE) 
head(Data1) 

for (i in 1:nrow(Data1)) 
{ 
    Data1$Category[i] = "" 
    Data1$Category[i] = ifelse(Data1$Days[i] <= 30, "<30", 
         ifelse(Data1$Days[i] <= 60, "31-60", 
         ifelse(Data1$Days[i] <= 90, "61-90",">90")))  

} 

但是代碼運行時間很長。有更好更快的方式來做同樣的操作嗎?

回答

2

我們可以通過freaddata.table開始閱讀,然後使用cut/findInterval進行更優化。當它在多內核運行,這將變得更加明顯,其中fread利用所有的節點和服務器節點上執行並行

library(data.table) 
merge_data <- function(path) { 
    files = dir(path, pattern = '\\.csv', full.names = TRUE) 
    rbindlist(lapply(files, fread, select = c(8, 9, 17))) 
} 

Data <- merge_data("D:/Projects") 
Data[, Category := cut(Data1, breaks = c(-Inf, 30, 60, 90, Inf), 
     labels = c("<=30", "31-60", "61-90", ">90"))] 
+1

非常感謝!代碼工作正常,運行時間少於幾秒鐘:) –

1

您已經在使用dplyr,那麼爲什麼不只是:

Data = merge_data("D:/Projects") %>% 
    select(8, 9, 17) %>% 
    mutate(Category = cut(Days, 
         breaks = c(-Inf, 30, 60, 90, Inf), 
         labels = c("<=30", "31-60", "61-90", ">90")) 
0

Akrun確實是正確的,FREAD實質上更快read.csv。

然而,除了他的職位,我也補充一點,你的循環是完全不必要的。他用我不熟悉的cut/findInterval替換它。雖然在簡易R編程方面,對循環時,在計算一些因素被排改變是必要的。但是,在您的代碼中,情況並非如此,並且不需要for循環。

基本上你正在運行的計算達200萬次時,你只需要運行一次在列計算。

你可以像這樣的東西取代您的for循環:

Data1$category = ifelse(Data1$Days <= 30, "<=30", 
       ifelse(Data1$Days <= 60, "31-60", 
       ifelse(Data1$Days <= 90, "61-90",">90"))) 

,你的代碼將waaaaaay更快地運行