“应用”功能的优点是什么?什么时候比“ for”循环更好用,什么时候不? [重复]

|                                                                                                                   这个问题已经在这里有了答案:                                                      
已邀请:
        有几个原因导致人们可能更喜欢“ 0”族函数而不是“ 1”循环,反之亦然。 首先,ѭ2executed和
apply()
sapply()
如果正确执行,通常将彼此一样快。 “ 5”在R内部执行的编译代码操作比其他功能更多,因此比这些功能更快。当对数据的“循环”动作是计算时间的重要部分时,速度优势似乎最大。在许多常规日常使用中,您不太可能从本来较快的
lapply()
获得很多收益。最后,所有这些都将调用R函数,因此需要对其进行解释然后再运行。
for()
循环通常更容易实现,特别是如果您来自循环较普遍的编程背景。与强制将迭代计算放入“ 0”族函数之一相比,循环工作更自然。但是,要正确使用
for()
循环,您需要做一些额外的工作来设置存储并管理再次将循环的输出重新插入在一起。
apply
功能为您自动完成。例如。:
IN <- runif(10)
OUT <- logical(length = length(IN))
for(i in IN) {
    OUT[i] <- IN > 0.5
}
那是一个愚蠢的例子,因为
>
是向量化运算符,但我想指出一点,即必须管理输出。最主要的是,对于
for()
循环,在开始循环之前,您始终分配足够的存储空间以容纳输出。如果您不知道需要多少存储空间,则分配一个合理的存储空间,然后在循环中检查是否耗尽了该存储空间,然后再固定另一个大存储空间。 在我看来,使用
apply
系列功能之一的主要原因是为了使代码更优雅,更易读。与其管理输出存储并建立循环(如上所示),我们不如让R处理这个问题,并简洁地要求R对数据的子集运行一个函数。速度通常不参与决策,至少对我而言。我使用最适合情况的函数,并且将导致简单易懂的代码,因为如果我不记得要做什么,那么我总是选择最快的函数,比我节省的时间要多得多代码将在一天或一周或更长时间之后执行! “ 0”族适用于标量或矢量运算。
for()
循环通常会使用相同的索引
i
进行多次迭代操作。例如,我编写了使用
for()
循环对对象进行k折或自举交叉验证的代码。由于每个CV迭代都需要多次操作,访问当前帧中的许多对象并填充几个保存迭代输出的输出对象,因此我可能永远不会用ѭ0系列之一来做到这一点。 关于最后一点,关于为什么5可能比2或3更快,您需要意识到可以在解释的R代码或编译的代码中执行\“ loop \”。是的,两者都仍将调用需要解释的R函数,但是如果您正在循环并直接从已编译的C代码(例如ѭ5calling)进行调用,则性能可以从ѭ3以上获得,例如可以归结为实际的R代码中有一个“ 2”循环。请参阅
apply()
的源代码,以了解它是
for()
循环的包装器,然后查看
lapply()
的代码,即:
> lapply
function (X, FUN, ...) 
{
    FUN <- match.fun(FUN)
    if (!is.vector(X) || is.object(X)) 
        X <- as.list(X)
    .Internal(lapply(X, FUN))
}
<environment: namespace:base>
并且应该了解为什么
lapply()
for()
以及其他
apply
系列功能之间的速度会有所不同。 ѭ33是R \调用R本身使用的已编译C代码的一种方式。除了操作和on34 a的健全性检查以外,整个计算都在C中完成,调用R函数
FUN
。将其与ѭ3的来源进行比较。     
摘自Burns'R Inferno(pdf),第25页:   每次使用显式
for
循环   迭代是一项艰巨的任务。但是一个   简单的循环可以更清晰地显示   用ѭ0表示   功能。至少有一个   此规则的例外...如果结果将   成为列表和一些组件   可以是
NULL
,那么for循环是   麻烦(大麻烦)和
lapply
给   预期的答案。     

要回复问题请先登录注册