将循环转换为lapply最简单的方法是将for循环中的内容放入一个函数中。我们从内部循环开始。
foo_inner <- function(j) {
F[i+NOUT*(j-1)] = Y[j]-YTR[i,j]
}
然而这里有一个问题:你的函数应该返回一个值而不是分配它。在这种情况下,你想要返回Y[j]-YTR[i,j]
。
foo_inner <- function(j) {
return(Y[j]-YTR[i,j])
}
您可以将此函数应用于1:NOUT
。在这种情况下,根据您的帖子中缺乏信息(虽然我不能确定),似乎该返回值仅为一个数字,因此您可以直接创建向量而不是列表。在这种情况下,最好使用sapply
而不是lapply
('s'表示简化(为向量),而'l'表示列表):
sapply(1:NOUT, foo_inner)
现在必须在外层循环中分配此新向量。从您的代码中,似乎您希望将此向量分配给F [i + NOUT *(1:NOUT-1)]
。我只是将您的 j
值替换为 1:NOUT
,这是您的迭代器。因此,您的代码片段可以修改如下:
for (i in 1:NTR) {
X = as.vector(as.matrix(XTR[i,]))
YZ = FN(W, V, U, X)
Y = YZ$Y
Z = YZ$Z
F[i+NOUT*(1:NOUT-1)] <- sapply(1:NOUT, foo_inner)
}
现在让我们来处理外层循环。和之前一样,我们可以将内部内容放入一个函数中:
foo_outer <- function(i) {
X = as.vector(as.matrix(XTR[i,]))
YZ = FN(W, V, U, X)
Y = YZ$Y
Z = YZ$Z
F[i+NOUT*(1:NOUT-1)] <- sapply(1:NOUT, foo_inner)
}
这里有两个问题需要解决:首先,您的foo_inner
函数以i
作为参数。但是,由于foo_inner
在foo_outer
外定义,它将始终使用环境中定义的i
而不是foo_outer
的参数。有两种解决方案:要么在foo_outer
内定义foo_inner
:
foo_outer <- function(i) {
X = as.vector(as.matrix(XTR[i,]))
YZ = FN(W, V, U, X)
Y = YZ$Y
Z = YZ$Z
foo_inner <- function(j) {
return(Y[j]-YTR[i,j])
}
F[i+NOUT*(1:NOUT-1)] <- sapply(1:NOUT, foo_inner)
}
或者,修改你的 foo_inner
函数,使其接受 i
作为参数并返回一个正确的函数。然后在内部的 sapply
中应用函数 foo_inner(i)
而不是 foo_inner
:
foo_inner <- function(i) {
function(j) {
return(Y[j]-YTR[i,j])
}
}
foo_outer <- function(i) {
X = as.vector(as.matrix(XTR[i,]))
YZ = FN(W, V, U, X)
Y = YZ$Y
Z = YZ$Z
F[i+NOUT*(1:NOUT-1)] <- sapply(1:NOUT, foo_inner(i))
}
下一步需要修改的是确保你想要在函数中返回一个值而不是进行赋值操作:
foo_inner <- function(i) {
function(j) {
return(Y[j]-YTR[i,j])
}
}
foo_outer <- function(i) {
X = as.vector(as.matrix(XTR[i,]))
YZ = FN(W, V, U, X)
Y = YZ$Y
Z = YZ$Z
return(sapply(1:NOUT, foo_inner(i)))
}
您现在可以应用此函数:
lapply(1:NTR, foo_outer)
在这种情况下,我使用了
lapply
,因为每个元素返回的将是一个向量,所以我宁愿返回一个列表,之后再折叠它,因为我不确定在这种情况下
sapply
是否会这样做(并且现在懒得找出来,如果有人可以确认,我会纠正)。
所以现在你想要一个大向量,所以我只需折叠所有。
do.call(c, lapply(1:NTR, foo_outer))
我可以直接将这个值赋给F
:
F <- do.call(c, lapply(1:NTR, foo_outer))
很显然,如果不知道F
、YTR
、Y
和所有输入的内容,我无法确保这正是你想要的。但我希望它能让你走上正确的道路!
编辑:我认为你的最终向量顺序是错误的:使用以上方法将把所有i=1的"j"值放在一起,然后是所有i=2的"j"值......但回顾你的F
,看起来你想要的顺序是对于j=1
的所有i值......为了做到这一点,你只需要重新排列第二个lapply
的输出。这应该可以解决问题。
我想创建一个函数,从列表中获取所有的j
元素:
LL <- lapply(1:NTR, foo_outer)
get_j_values <- function(j) {
sapply(LL, function(x) x[[j]])
}
对于任何j
值,get_j_value
都会返回一个向量,其中包含LL
的所有第j
个元素。通过将此函数应用于所有可能的j
值,它会返回一个列表,第一个元素是:j=1
时所有"i"值,然后第二个元素是j=2
时所有"i"值...
LL2 <- lapply(1:NOUT, get_j_values)
我可以将此列表合并成一个大向量并进行分配。
F <- do.call(c, LL2)
编辑2:尽管使用apply
函数重新创建您的for循环是可能的,但这可能是其中一个时候,for循环实际上更好:没有结果的累积,因此apply
方法不应更快,而且我认为for循环会更清晰。当您循环遍历用于多个不同对象的索引时,通常情况下就是这种情况,因此您无法直接在任何特定对象上使用apply
,但需要将函数应用于索引向量...仅代表我个人观点...