我试图优化r中的循环,该循环计算向量中每个元素的字符串匹配数量,这与数据帧中的每一行有关。在小型数据集中,它工作得很好(约15分钟; 11列,914行)。但是,在大型数据集(914列,18.000行)中运行需要数天时间。这是我非常基本的循环:
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] ])
}
}
我想知道是否有人知道如何使用其他方法(例如矢量化)优化此循环。任何解决方案都将非常感谢!
更新 这是一个小数据集。这是最快的一个
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] ])
}
}
答案 0 :(得分:3)
以下是使用lapply
的方法(更快见下文):
richa <- lapply( X = vec, FUN = function(x) rowSums( df == x ) )
richa <- do.call( cbind, richa )
您提供的小型数据集上的快速microbenchmark
显示此信息比您的for
循环方法快10倍左右。
只是添加,使用parallel::mclapply
或plyr::laply
(parallel = TRUE
),这对于非常大的数据集来说也很容易实现多线程。这需要一些额外的工作,但对于你已经获得的18000 x 914个数据集可能是值得的。
编辑添加:因为你已经有一些for循环(因为我学习Rcpp,并且热衷于练习),这里使用{{1}更快的解决方案}。这是函数定义(需要编译一次):
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 )
在这里非常快。您的非常小的样本上的Microbenchmark显示它比我上面的Rcpp
解决方案快3倍以上,比R中的lapply
循环快约38倍。
有趣的是,将输入数据扩展到for
大小为4000x4000,长度为df
,vec
和Rcpp
方法都可以完成工作相似的时间(分别为3.4秒和3.9秒)。在您提到的数据集上(18000行x 914列,lapply
长度为2),两种解决方案都不到1秒。不管怎样都不错!