R - 用于替换具有函数

时间:2016-09-04 13:32:24

标签: r for-loop apply nested-loops

我已经看过十几个网站可以学习申请,申请,lapply,但他们没有比教你如何获取行或列的总和或平均值更远的地方。我必须使用很多for循环,通常是嵌套的。请告诉我如何替换以下申请。

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

    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

非常感谢任何回复。

1 个答案:

答案 0 :(得分:5)

将循环转换为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) # return Y and Z
    Y = YZ$Y
    Z = YZ$Z
    F[i+NOUT*(1:NOUT-1)] <- sapply(1:NOUT, foo_inner)
} # i

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

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)
}

这里有两个问题需要克服:首先,您的foo_inner函数将i作为参数。但是,foo_innerfoo_outer之外定义,它将始终使用您环境中定义的i,而不是foo_outer的参数。有两种解决方案:在foo_inner内定义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)
}

或者,修改您的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))
}

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

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)))
}

您现在可以应用此功能:

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))

显然,如果不知道FYTRY以及您的所有输入,我无法确保这正是您想要的。但我希望它能让你开始走上正确的道路!

编辑:我认为我为你的最终向量创建了错误的顺序:上面它会为i= 1添加所有“j”值,然后为i = 2添加所有“j”值。但是回头看看你的F,看起来你想要的顺序是j=1所有“i”值...要做到这一点,你只需要重新安排第二个lapply的输出。 {1}}。这可行。

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

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

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

LL2 <- lapply(1:NOUT, get_j_values)

然后我可以在一个大向量中折叠此列表并分配它。

F <- do.call(c, LL2)

编辑2:虽然可以使用apply函数重新创建for循环,但这可能是for循环实际上更好的时候之一:没有积累结果所以{{ 1}}方法不应该更快,而且我认为for循环会更清晰。当您循环遍历多个不同对象的索引时,通常会出现这种情况,因此您不能直接在任何特定对象上使用apply,但需要将函数应用于索引向量...只是我的两分钱......