2016-11-29 116 views
0

我试图优化r中的一个循环,该循环计算向量中关于数据帧中每一行的每个元素的字符串匹配数量。在小数据集中,它工作得很好(〜15分钟; 11列,914行)。但是,运行庞大的数据集需要数天(914列,18.000行)。这是我非常基本的循环:加速r循环字符串匹配(矢量与数据帧)

for (j in 1: dim(pddbnh)[1]){ 
    for (i in 1:dim(pidf)[1]){ 
    richa[i,j] <- length(pidf[i,][pidf[i,] == row.names(pddbnh)[j] ]) 
    } 
} 

我想知道是否有人知道如何使用其他方法(如矢量化)优化此循环。任何解决方案将非常感谢!

UPDATE 这是一个小数据集。这是最快的国家之一

df<-data.frame(replicate(10,sample(c("sp1", "sp2"),10,rep=TRUE))) 
vec<-c("sp1", "sp2") 
richa <- data.frame() 

    for (j in 1:length(vec)){ 
    for (i in 1:dim(df)[1]){ 
    richa[i,j] <- length(df[i,][df[i,] == vec[j] ]) 
    } 
    } 
+1

是的,我可能知道如何做到这一点。请为测试提供一个最小可重现的示例。 – Roland

+0

谢谢!以下是两个文件:https://www.dropbox.com/s/vvksp7c1kerqjbq/pddbnh.csv?dl=0 https://www.dropbox.com/s/zjt9shku0gjf03t/pidf.csv?dl=0 – CristianR

+0

(显然你还没有对SO进行彻底搜索,因为有许多问答关于提高for循环的性能。)询问'['处理'[pidf [i,] == row.names(pddbnh)[ j]]似乎注定要失败。该参数的结果将在强制后为0或1(因此应该出现关于长度为零的替换的错误)。也许你应该解释你实际尝试的是什么。 –

回答

3

下面是使用lapply的方法(参见下面的更快):

richa <- lapply(X = vec, FUN = function(x) rowSums(df == x)) 
richa <- do.call(cbind, richa) 

快速microbenchmark上的小数据集您提供展示了这个约10倍比你的快for循环方法。

只需要添加一下,对于真正的大数据集,使用parallel::mclapplyplyr::laply(与parallel = TRUE)可以很容易地为多线程。它需要一些额外的工作,但对于那些18000 x 914数据集可能是值得的。

编辑要添加:因为你有几个循环去那里(并且因为我正在学习Rcpp,并且渴望练习),所以这里有一个更快的解决方案,使用Rcpp。下面是函数的定义(这需要进行一次编译):

Rcpp::cppFunction(' IntegerMatrix charCrossCheck(CharacterMatrix df, 
          CharacterVector vec) { 

       IntegerMatrix output(df.nrow(), vec.size()); 

       for (int j=0; j < vec.size(); ++j){ 
        for (int i=0; i < df.nrow(); ++i){ 
         int count = 0; 
         for(int k=0; k < df.ncol(); k++){ 
          if(df(i,k) == vec[j]) { 
           count++; 
          } 
         } 
         output(i,j) = count; 
        } 
       } 
       return output; 

       } ') 

然后你就可以调用函数:

richa <- charCrossCheck(as.matrix(df), vec) 

Rcpp是非常快的在这里。你的非常小的样本微基准展示了3倍比我lapply解决方案比你for循环中R.更更快以上,约38X快

有趣的是,扩大了输入数据输出到df尺寸4000x4000,并且vec的长度为10时,Rcpplapply方法都在非常相似的时间(分别为3.4秒和3.9秒)完成作业。在您提到的数据集(18000行×914列,长度为vec,长度为2)的数据集中,两种解决方案均低于1秒。这两种方法都不错!

+0

两种方法都比较快!这太神奇了,帮助我很多。我会试图弄清楚两个实现的细节。我很惊讶! – CristianR

+0

@CristianR太棒了!如果能帮助解决您的问题,请将答案标记为已接受。 – rosscova