是否可以使用不同的向量应用于每列?
问题描述:
道歉的问题标题不佳。不太确定如何描述这里的问题。
首先,我有下面的代码。是否可以使用不同的向量应用于每列?
# 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,所以我试图用for循环来避开。谢谢。
grpB = matrix(round(runif(10000,1,5),0),100,100)
答
只是作为一个答案
我还可以使用该应用来计算呢?如果是这样,怎么样?
答案是肯定的。您可以将x
和grpB
合并成一个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的答案,原因可能不是一个好主意。
答
你可以很容易使用的列数的sequence
作为“指标”或“提取”的变量,并使用vapply
代替apply
,像这样:
vapply(sequence(ncol(x)),
function(z) funA(x[, z], grpB[, z]),
numeric(nrow(x)))
答
首先,如果你的功能funA
做了很多工作,然后使用for
循环与apply
不会对性能产生太大影响。这是因为唯一的区别在于循环的开销,并且在任何情况下,大部分工作都将在funA
之内发生。
实际上,即使funA
很简单,for
和apply
也不会在性能方面有所不同。无论哪种方式,都需要在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循环快得多。
没错。可以使用'lm(t(x)〜groupA)'来避免R级的循环。如果需要循环,也可以使用'lm.fit'。课程:如果可能,避免使用R循环。如果不优化循环内的代码。 – Roland 2014-12-02 15:38:19