是否可以对每列使用不同向量的应用?

时间:2014-12-02 15:15:46

标签: r apply

向可怜的问题标题道歉。不太清楚如何在这里描述问题。
首先,我有以下代码。

# Data
set.seed(100)
x = matrix(runif(10000,0,1),100,100)
grpA = round(runif(100,1,5),0) # Group 1, 2, 3, 4, 5

# function
funA <-function(y, A){
  X = lm(y~A)
  return(X$residuals)
}

# Calculation  
A = apply(x,1,function(y) funA(y,grpA))

现在,我没有使用grpA,而是使用grpB,每个列的组都不同。除了循环每一列,我还可以使用apply来计算吗?如果是这样,怎么样? 我的实际funA计算要复杂得多,我需要多次计算funA,所以我试图使用for循环进行aviod。谢谢。

grpB = matrix(round(runif(10000,1,5),0),100,100)

3 个答案:

答案 0 :(得分:4)

首先,如果您的函数funA做了大量工作,那么使用for循环与apply不会影响性能。这是因为唯一的区别在于循环的开销,并且在任何一种情况下大部分工作都将在funA内进行。

事实上,即使funA很简单,forapply也不会有那么不同的表现。无论哪种方式,R内部都需要有一个带有多个R函数调用的循环。避免for循环的真正性能改进来自于内置R函数,它通过在底层C代码中循环执行所需的计算而没有R中多个函数调用的开销。这是一个说明性示例

x<-matrix(runif(10000,0,1),100,100)
require(microbenchmark)
f1<-function(z){
  ret<-rep(0,ncol(z))
  for(i in 1:ncol(z)){
      ret[i]<-sum(z[,i])
  }
  ret
}
f2<-function(z){
  apply(z,2,sum)
}
identical(f1(x),f2(x))
# [1] TRUE
identical(f1(x),colSums(x))
# [1] TRUE
microbenchmark(f1(x),f2(x),colSums(x))
# unit: microseconds
#       expr     min       lq   median       uq      max neval
#       f1(x) 559.934 581.4775 596.4645 622.1425  773.519   100
#       f2(x) 484.265 512.1570 526.5700 546.5010 1100.540   100
#  colSums(x)  23.844  25.7915  27.0675  28.7575   59.485   100

因此,在您的情况下,我不担心使用for循环。有一些方法可以避免循环,例如

sapply(1:ncol(x),function(i) fun(x[,i],y[,i]))

但它不会比for循环快得多。

答案 1 :(得分:0)

您可以轻松地使用sequence列数作为&#34;指标&#34;或者&#34;提取&#34;变量,并使用vapply代替apply,如下所示:

vapply(sequence(ncol(x)), 
       function(z) funA(x[, z], grpB[, z]), 
       numeric(nrow(x)))

答案 2 :(得分:0)

正如

的答案
  

我还可以使用apply来计算吗?如果是这样,怎么样?

答案是肯定的。您可以将xgrpB合并到array中,然后对结果数组使用apply。

# Data
set.seed(100)
x = matrix(runif(10000,0,1),100,100)
grpA = round(runif(100,1,5),0) # Group 1, 2, 3, 4, 5
# function
funA <-function(y, A){
  X = lm(y~A)
  return(X$residuals)
}
# Original calculation  
A <- apply(x, 1, funA, grpA)
# the array in this case
arr <- array(c(x, matrix(rep(grpA, 100), nrow=100, byrow=TRUE)), dim=c(nrow(x), ncol(x), 2))
# the new calculation 
res <- apply(arr, 1, function(y) funA(y[, 1], y[, 2]))
# comparing results
all.equal(A, res)
## TRUE
# 
# and for the new groupB
grpB = matrix(round(runif(10000,1,5),0),100,100)
# the array
arr <- array(c(x, grpB), dim=c(nrow(x), ncol(x), 2))
# the calculation (same as above)
res <- apply(arr, 1, function(y) funA(y[, 1], y[, 2]))

请参阅@ mrip的答案,原因可能不是一个好主意。