替代显式for循环,用于根据列索引设置矩阵条目

时间:2015-09-11 18:00:38

标签: r loops apply rcpp

如果不使用for-loop,我怎样才能达到以下相同的效果?

df1 = data.frame( val = c("a", "c", "c", "b", "e") )  

m1 = matrix(0, nrow=nrow(df1), ncol=length( c("a", "b", "c", "d", "e") ) )
colnames(m1) = c("a", "b", "c", "d", "e")

for(i in 1:nrow(df1)){
  m1[i, df1[i, 1] ] = 1  #For each entry in dataframe, mark the respective column as 1
}

2 个答案:

答案 0 :(得分:4)

f<-function(m1,df) {
  for(i in 1:nrow(df1))
    m1[i, df1[i, 1] ] = 1
  return(m1)
}

相当于

g<-function(m1,df) {
  m1[cbind(seq_len(nrow(df)),df1[,1])]<-1
  return(m1)
}

对于这个特定的例子,后者更快

> microbenchmark(f(m1,df1),g(m1,df1))
Unit: microseconds
       expr     min      lq      mean  median      uq     max neval cld
 f(m1, df1) 167.085 174.885 194.58999 185.969 200.132 342.379   100   b
 g(m1, df1)  20.116  22.990  27.12403  24.222  27.300 158.053   100  a 

但请注意

  • 两者都使用因子级别而不是字符列名称
  • 除非确定真正的瓶颈,否则你应该编写最清晰而不是最快的代码

答案 1 :(得分:0)

您的代码中有几个奇怪的东西。首先不需要df1,因为data.frame不应该存储一维向量。 val = c("a", "c", "c", "b", "e")就够了。此外,正如其他人所说,有更紧凑(和一些更有效)的方法来实现同样的事情。但是,如果在实际问题中你使用了更多的数据并且发现它更容易用于循环,那么你应该考虑使用C ++代码(并且它的速度要快得多)。

这是我用来比较R和C ++ fors的基准测试,通过创建一个将添加前n个数字的函数(我做了n = 100K的测试)。

以下是代码:

library(Rcpp)
library(rbenchmark)

cppFunction(
  'int cppSum(int n) { 
    int s = 0;
    for(int i = 0; i <= n; i++) {
      s += i;
    }
    return s;
  }'
)

rSum <- function(n) {
  s = 0
  for (i in c(1:n)) {
    s = s + i
  }
  return(s)
}

n = 100000
benchmark(rSum(n), cppSum(n))

结果如下:

       test replications elapsed relative user.self sys.self user.child sys.child
2 cppSum(n)          100   0.008     1.00      0.00        0          0         0
1   rSum(n)          100   2.790   348.75      2.79        0          0         0

您可以在relative列中注意到R函数比C ++函数慢348.75倍。在计算密集型过程中,使用C ++进行循环是一个很好的优化。有一次,我一直在运行一个for inside其他循环。这需要永远完成。当我用C ++更改了R for,它在几分钟内完成。

[编辑] 此示例无法解决您的实际问题。原始问题寻找替代缓慢的R for循环,所以我建议你选择更快的循环,即C++ for循环。工作示例不使用您的数据,因为它对于任何基准测试来说都太小了。相反,我使用100K迭代循环,因此可以看到2个不同循环之间的差异。