我有一个带有两个参数的函数。第一个参数采用向量,第二个参数采用标量。我想将此函数应用于矩阵的每一行,但此函数每次都会使用不同的第二个参数。我试过以下,它没有用。我希望计算每一行的p.value,然后将p.value除以行号。我期望结果是一个向量,但我得到了一个矩阵。这是一个伪示例,但它说明了我的目的。
> foo = matrix(rnorm(100),ncol=20)
> f = function (x,y) t.test(x[1:10],x[11:20])$p.value/y
> goo = 1:5
> apply(foo,1,f,y=goo)
[,1] [,2] [,3] [,4] [,5]
[1,] 0.9406881 0.6134117 0.5484542 0.11299535 0.20420786
[2,] 0.4703440 0.3067059 0.2742271 0.05649767 0.10210393
[3,] 0.3135627 0.2044706 0.1828181 0.03766512 0.06806929
[4,] 0.2351720 0.1533529 0.1371135 0.02824884 0.05105196
[5,] 0.1881376 0.1226823 0.1096908 0.02259907 0.04084157
以下for循环策略产生预期结果,对于实际数据预期会非常慢。
> res = numeric(5)
> for (i in 1:5){
res[i]=f(foo[i,],i)
}
> res
[1] 0.94068810 0.30670585 0.18281807 0.02824884 0.04084157
任何建议都将不胜感激!
答案 0 :(得分:2)
如果你的真实目的与你的榜样相似,你可以对分工进行矢量化:
f <- function(x) t.test(x[1:10], x[11:20])$p.value
apply(foo, 1, f) / goo
根据评论,上述内容并不恰当。
在该示例的情况下,您可能会观察到返回矩阵的对角线是期望的结果:
f = function (x,y) t.test(x[1:10],x[11:20])$p.value/y
goo = 1:5
diag(apply(foo,1,f,y=goo))
除了在时间或空间上效率低下之外,这还有另一个问题。这是对y
进行矢量化操作的结果,这对于示例来说是正确的。在这种情况下,前一种解决方案更好。所以我怀疑在你的实际问题中,你的操作没有矢量化。
有时候for
循环确实是最好的答案。 apply
函数族不是神奇的;它们仍然是循环。
这是一个sapply
解决方案。它的时间不会超过for
(可能也不会失败),但它没有很高的空间开销。我们的想法是应用行索引并使用它来提取foo
行和goo
的元素以传递给f
sapply(seq(nrow(foo)), function(i) f(foo[i,], goo[i]))
答案 1 :(得分:1)
f <- function (x,y) t.test(x[1:10],x[11:20])$p.value/y
f2 <- function(a, b){
tt <- t.test(x = a[1:10], y = a[11:20])$p.value
tt/b
}
f3 <- function() {
res <- numeric(5)
for (i in 1:5){
res[i] <- f(foo[i,],i)
}
res
}
f4 <- function(x) t.test(x[1:10], x[11:20])$p.value
set.seed(101)
foo <- matrix(rnorm(100),ncol=20)
goo <- 1:5
library(rbenchmark)
benchmark(
apply(foo, 1, f4) / goo,
mapply(f,split(foo,row(foo)),goo),
f2(foo,goo),
f3(),replications=1000,
sapply(seq(nrow(foo)), function(i) f(foo[i,], goo[i])),
columns=c("test","replications","elapsed","relative"))
## test replications elapsed relative
## 1 apply(foo, 1, f4)/goo 1000 1.581 5.528
## 3 f2(foo, goo) 1000 0.286 1.000
## 4 f3() 1000 1.458 5.098
## 2 mapply(...) 1000 1.599 5.591
## 5 sapply(...) 1000 1.486 5.196
直接划分最好(但实际上并不适用);对于此示例,其他解决方案之间没有太大差异,但for
循环优于sapply
,优于mapply
。你应该在一个更现实的例子中尝试这个,看看它将如何扩展你的问题。