将for循环转换为apply/lappy/sapply:基于列的操作

将for循环转换为apply/lappy/sapply:基于列的操作,r,for-loop,vectorization,R,For Loop,Vectorization,假设我有以下for循环代码,它非常有效: for (i in 1:nrow(Dir)) { if (is.na(Dir[i, 3]) == TRUE) { Dir[i, 3] = Dir[i, 5]/Dir[i, 4] } } 它所做的是检查每一行的列元素,如果有NA,它将用一个数字替换NA,该数字是将5列元素除以4列元素得到的 如何将基于列元素的循环的此循环和类似的转换为使用apply/lappy/sapply的代码 如需了解更多有关apply/lappy/s

假设我有以下
for循环
代码,它非常有效:

for (i in 1:nrow(Dir)) {
    if (is.na(Dir[i, 3]) == TRUE) {
        Dir[i, 3] = Dir[i, 5]/Dir[i, 4]
    }
}
它所做的是检查每一行的列元素,如果有
NA
,它将用一个数字替换
NA
,该数字是将
5列
元素除以
4列
元素得到的

如何将基于列元素的循环的此循环和类似的
转换为使用
apply/lappy/sapply
的代码


如需了解更多有关
apply/lappy/sapply
的信息,请提供任何综合资源。谢谢。

如果您真的想在此处使用
apply
,您可以执行以下操作:

n_rows = 20
Dir = data.frame(
    a = sample(1:100, n_rows),
    b = sample(1:100, n_rows),
    c = sample(c(NA, 1, 2), n_rows, replace = TRUE),
    d = sample(1:100, n_rows),
    e = sample(1:100, n_rows)
)

# MARGIN = 1: apply along the rows (MARGIN = 2 for columns)
Dir$c = apply(Dir, MARGIN = 1, FUN = function(row) {
    if (is.na(row[3])) {
        return(row[5] / row[4])
    } else {
        return(row[3])
    }
})
但是:
应用
对于
循环并不一定比
更快或更有效。矢量化代码,如巴蒂斯特的建议

Dir[ , 3] = ifelse(is.na(Dir[ , 3]), Dir[, 5]/Dir[, 4], Dir[ , 3])

通常比两者都快,只要你的数据足够大,足以使差异变得重要,而且一旦你了解了它的工作原理,就不需要太多的打字就可以写得更少。

Dir[,3]=ifelse(is.na(Dir[,3]),Dir[,5]/Dir[,4],Dir[,3])
是数据帧还是矩阵?您可能甚至不需要使用任何类似于
apply
的方法来完成此操作。我还建议您使用列名而不是列号,除非您有令人信服的理由这样做。这是一种误解,即for循环应该始终由*apply函数代替;在某些情况下,for循环与*apply替代方法一样好:它可以更具可读性,并且不会明显减速。然而,在许多情况下,以不同的方式思考问题会提出一个向量化的解决方案,这是一个更好的选择。我不知道是否在任何删除的注释中提到过它,只是为了进一步理解:
is.na()
操作返回一个布尔向量
TRUE/FALSE
结果。因此,在
if
-语句中使用
is.na()
(或
is.
类的任何其他运算符)时,不需要将所需结果澄清为
==TRUE
。如果要检查
na==TRUE
状态和
,请使用
is.na()!is.na()
如果要检查
na==FALSE
状态。你可以在@Marius的回答中看到这一点。