R-申请用功能代替循环

use*_*024 -1 for-loop r apply nested-loops

我已经看到了十二个要学习应用,应用,应用的站点,但是它们没有比教您如何获取行或列的总和或平均值更有效的方法。我必须使用很多for循环,通常是嵌套的。请在下面说明如何用Apply替换。

for (i in 1:NTR) {
    X = as.vector(as.matrix(XTR[i,]))
    YZ = FN(W, V, U, X) # return Y and Z
    Y = YZ$Y
    Z = YZ$Z
    for (j in 1:NOUT) {
        F[i+NOUT*(j-1)] = Y[j]-YTR[i,j]
    } # j
} # i
Run Code Online (Sandbox Code Playgroud)

    for (k in 1:NOUT) {
        for (iwt in 1:NWT) {
            m = NHID*(NNLIN+1) 
            if (iwt <= m) { 
                i = (iwt-1) %/% (NNLIN+1) + 1
                j = (iwt-1) %% (NNLIN+1)
                EVZ = V[k,i+1]*Z[i]*(1-Z[i]) 
                if (j>0) EVZ = EVZ*X[j] 
                J[k+(n-1)*NOUT,iwt] = EVZ
            }
        } # iwt     
    } # k
Run Code Online (Sandbox Code Playgroud)

非常感谢您的任何答复。

Cho*_*ubi 7

将循环转换为延迟的最简单方法是获取for循环中的内容并将其插入函数中。让我们从您的内循环开始。

foo_inner <- function(j) {
    F[i+NOUT*(j-1)] = Y[j]-YTR[i,j]
}
Run Code Online (Sandbox Code Playgroud)

但是这里有一个问题:您的函数应该返回一个值而不是赋值。在这种情况下,您想返回Y[j]-YTR[i,j]

foo_inner <- function(j) {
    return(Y[j]-YTR[i,j])
}
Run Code Online (Sandbox Code Playgroud)

然后,您只需将此功能应用于即可1:NOUT。在这种情况下,(虽然我不能确定您的帖子中缺少信息),但此返回值只是一个数字,因此您可以直接创建矢量而不是列表。在这种情况下,最好使用sapply而不是lapply(“ s”代表简化(表示向量),而“ l”代表列表):

sapply(1:NOUT, foo_inner)
Run Code Online (Sandbox Code Playgroud)

现在必须在您的外部循环中分配此新向量。从您的代码看来,您想要将此向量分配给F[i+NOUT*(1:NOUT-1)]。我只是用您的迭代器替换了您的j1:NOUT。因此,您的代码段可以像下面这样修改:

for (i in 1:NTR) {
    X = as.vector(as.matrix(XTR[i,]))
    YZ = FN(W, V, U, X) # return Y and Z
    Y = YZ$Y
    Z = YZ$Z
    F[i+NOUT*(1:NOUT-1)] <- sapply(1:NOUT, foo_inner)
} # i
Run Code Online (Sandbox Code Playgroud)

现在让我们解决外部循环。和以前一样,我们可以插入函数中的内容:

foo_outer <- function(i) {
    X = as.vector(as.matrix(XTR[i,]))
    YZ = FN(W, V, U, X) # return Y and Z
    Y = YZ$Y
    Z = YZ$Z
    F[i+NOUT*(1:NOUT-1)] <- sapply(1:NOUT, foo_inner)
}
Run Code Online (Sandbox Code Playgroud)

这里有两个需要克服的问题:首先,您的foo_inner函数以i参数为参数。但是,foo_inner在外部进行定义时foo_outer,它将始终使用i您的环境中定义的内容,而不是的参数foo_outer。有两种解决方案:要么foo_inner在inside 中定义foo_outer

foo_outer <- function(i) {
    X = as.vector(as.matrix(XTR[i,]))
    YZ = FN(W, V, U, X) # return Y and Z
    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)
}
Run Code Online (Sandbox Code Playgroud)

或者,修改foo_inner函数,使其以i参数为参数并返回正确的函数。然后,您将foo_inner(i)在内部sapply而不是在内部应用函数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) # return Y and Z
    Y = YZ$Y
    Z = YZ$Z
    F[i+NOUT*(1:NOUT-1)] <- sapply(1:NOUT, foo_inner(i))
}
Run Code Online (Sandbox Code Playgroud)

接下来要做的修改是确保您要返回一个值,而不是在函数内部进行赋值:

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) # return Y and Z
    Y = YZ$Y
    Z = YZ$Z
    return(sapply(1:NOUT, foo_inner(i)))
}
Run Code Online (Sandbox Code Playgroud)

您现在可以应用此功能:

lapply(1:NTR, foo_outer)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我使用了一个,lapply因为返回的每个元素都是一个向量,所以我宁愿返回一个列表并将其折叠起来,因为我不确定sapply在这种情况下是否会这样做(而且太懒了,无法找到此刻,如果有人可以确认,我会纠正)。

所以您现在想要一个大向量,所以我将全部折叠。

do.call(c, lapply(1:NTR, foo_outer))
Run Code Online (Sandbox Code Playgroud)

然后,我可以F直接将此值分配给:

F <- do.call(c, lapply(1:NTR, foo_outer))
Run Code Online (Sandbox Code Playgroud)

显然,如果不知道,和所有输入内容F,就无法确保这正是您想要的。但我希望它能使您走上正确的道路!YTRY

编辑:我想我为您的最终向量创建了错误的顺序:通过上述操作,它将放所有的“ j”值,i= 1然后放所有的“ j”值i = 2...但是回头看,您F的顺序看起来像您want是j=1所有“ i”值的...为此,您只需要重新排列第二个输出lapply。这行得通。

我想创建一个j将从列表中获取所有元素的函数:

LL <- lapply(1:NTR, foo_outer)
get_j_values <- function(j) {
    sapply(LL, function(x) x[[j]])
}
Run Code Online (Sandbox Code Playgroud)

对于任何j值,均get_j_value在向量中返回的所有j元素LL。通过将此函数应用于所有可能的j值,它将返回包含第一个元素的列表:j=1第二个元素的所有“ i”值,然后第二个元素的所有“ i”值j=2...

LL2 <- lapply(1:NOUT, get_j_values)
Run Code Online (Sandbox Code Playgroud)

然后,我可以将此列表折叠到一个大向量中并进行分配。

F <- do.call(c, LL2)
Run Code Online (Sandbox Code Playgroud)

编辑2:尽管可以使用apply函数来重新创建for循环,但这可能是其中一次for循环实际上更好的情况之一:没有结果的累积,因此该apply方法不应该更快并且for循环我相信会更清楚。当您遍历在多个不同对象上使用的索引时,通常是这种情况,这样您就不能apply直接在任何特定对象上使用on,而是需要将函数应用于索引向量...仅需两美分。 ..