2014-02-20 20 views
0

我想加快基於字符數組調用另一個函數(fn1)的以下函數(fndf)。如何利用`apply/lapply/sapply`而不是`for`循環來提高性能?

fndf - 新功能
list_s - 字符數組 - chr [1:400]
rdata_i - 空數據幀(初始化)
fn1 - 另一個自定義功能
rdata2 - 與3000 obs of 40 variables
mdata數據幀 - data.frame
nm - character

fndf = function(list_s, rdata2){ 
       rdata_i = df <- data.frame(Date=as.Date(character()), 
         File=character(), 
         User=character(), 
         stringsAsFactors=FALSE) 
       for(i in 1:length(list_s)) 
       { 
        rdata = fn1(list_s[i], rdata2) 
        rdata_i = rbind(rdata, rdata_i) 
       } 
       return(unique(rdata_i)) 
      } 

我們是否也可以提高以下function的性能?

fn1 = function(nm, mdata){ 
       n0 = mdata[mdata$Sign==nm,] 
       cn0 = unique(c(n0$Name)) 
       repeat{ 
         n1c = mdata[mdata$Mgr %in% cn0,] 
         n0 = unique(rbind(n0,n1c)) 
         if(nrow(n1c)==0){ 
           return(n0) 
           break 
           } 
         cn0= unique(c(n1c$Name)) 
         } 
       } 
+2

您的放緩可能是由於'rdata_i = rbind(rdata,rdata_i)';在for循環中增長對象通常是不好的做法(太多複製和移動數據)。查看「R地獄」書,它對此有一些建議。 – baptiste

+2

試試這個,'ld = lapply(list_s,fn1,rdata2); do.call(rbind,ld)' – baptiste

+0

您需要讓您的問題具有可重現性。可能,你甚至不需要循環。 – Roland

回答

3

這確實很難說如何最好地將您的循環爲*apply聲明,甚至更難說這是否會加快速度。但從根本上說,下面的轉換就是你所追求的,它絕對使得函數更簡單,更易讀。這也很可能對應一個顯着的性能增益,由於反覆rbind的損失,由巴蒂斯特指出:

fndf = function (list_s, rdata2) 
    as.data.frame(do.call(rbind, unique(lapply(list_s, fn1, rdata2)))) 

(是的,這是一個單獨的語句)

另外請注意,我現在將unique直接應用於列表而不是data.frame。這改變了語義 - unique專門針對data.frame s - 但可能適合您的目的,並且效率會更高,因爲這意味着我們不會構建帶冗餘行的不必要的大data.frame

+0

這會將時間縮短到15秒。謝謝。 – BigDataScientist

1

很難沒有你的數據/功能的說法,但這裏是plyr的解決方案和一些佔位數據:

list_s<-LETTERS 
rdata2<-data.frame(a=rep(LETTERS,2),b=runif(52),c=runif(52)*10) 
fn1<-function(a,b=rdata2)b[rdata2$a==a,] 
fn1("A") 

require(plyr) # for ldply function, which takes a list and returns a dataframe 
result<-ldply(1:length(list_s),function(x)fn1(list_s[x],rdata2)) 
head(result) 

    a   b   c 
1 A 0.281940237 2.7774933 
2 A 0.023611392 0.6067029 
3 B 0.456547803 9.4219258 
4 B 0.645783746 5.3094864 
5 C 0.475949523 4.8580622 
6 C 0.006063407 2.5851738