用于基于列索引设置矩阵条目的显式 for 循环的替代方法

Alternative to explicit for loop for setting matrix entries based on column indexes

如何在不使用 for 循环的情况下实现与下面相同的效果?

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
}

这个

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 

但是请注意,

  • 两者都在使用因子水平而不是字符列名称
  • 你应该编写最清晰的代码而不是最快的代码,除非并且直到你确定真正的瓶颈

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

这是我通过创建一个函数来比较 R 和 C++ for 的基准测试(我对 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。这将需要很长时间才能完成。当我用 C++ 更改 R 时,它在几分钟内就完成了。

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