【问题标题】:Exit a function within *apply退出 *apply 中的函数
【发布时间】:2015-12-11 09:52:49
【问题描述】:

sapplyreplicate(等)运行指定的次数。放入sapply(1:N, function(n){expr}) 将执行expr N 次。假设我希望 sapply 在 m 运行后停止。这可能不会出错吗? break 不起作用,forwhile 循环在我的上下文中会太慢。

类似于:

sapply(1:N, function(n){
  #some expression
  if(identical(n, m)) break
})

除了 break 不起作用。

我正在尝试做的事情:

创建一个函数来读取具有已定义结构但长度未知的大型(二进制)数据文件。将replicatearray(readBin(...), ...) 一起使用是我发现的最佳方法,但我希望在开始返回NA 时停止它(即到达文件末尾)。

【问题讨论】:

  • 据我所知,R 中支持for 循环,并且 可以 使用,尽管名声不好。认为sapplyfor 循环更快是一种常见的误解。
  • 我的经验是forapply 家庭慢得多,我曾尝试使用for 完成此任务(在我真正了解*apply 之前)。有没有一些技巧可以让for 工作得更快?
  • for 并不比*apply很多。它通常(有点)比lapplyvapply 慢。视情况而定,可能比sapply 慢或快。它通常比apply。前提是您正确编写循环并且(比其他事情更多)避免增长对象并正确预分配。更详细地了解您的尝试,您可能会得到帮助。
  • @nicola for 本身实际上应该比其他循环更快(包括vapply)。你在里面做的事情会让它变慢。
  • @nicola 是的,但是您可以使用没有返回值的for 循环,这就是它获胜的地方。这就是我的意思,循环本身很快。

标签: r function apply exit


【解决方案1】:

可以以全局控制变量的形式使用部分解决方法

i<-TRUE
unlist( sapply(1:10, function(x){if(i){ if(x>=4)(i<<-FALSE); 2*x;}}) ) 

虽然还是运行n次,但至少不会每次都执行,节省资源。 而且我不能完全弄清楚为什么简化没有一路奏效,我不得不使用 unlist。

【讨论】:

  • 谢谢 - 这是个好主意。我认为它不会在 sapply 中简化,因为它想保留 NULL 值。
  • 试过了,它比使用 for/ while/ repeat 循环要快得多。 0.25 秒与 4.8 秒相比。当我输入更大的文件时会产生很大的不同。我仍然相信for 可以与*apply 竞争。
  • 很高兴能为您提供帮助。
  • @Bazz 在 R 中编写 for 循环时,您显然犯了一个严重错误。我的赌注是在不断增长的对象上(这很容易避免)。
  • 或者当其他人不得不在某个时候理解你的代码时。恕我直言,for 循环也更容易调试。
【解决方案2】:

除了for*apply 的战斗之外,如果您的问题是使用readBin 直到到达文件末尾,请记住:

  • 您可以对n(要读取的元素数量)使用(小)高估;
  • 可以通过file.info(filename)$size知道文件的大小;然后您可以自己估计文件中包含多少元素。

例如,假设您正在读取整数(四个字节)值。试试看:

readBin(con,"int",n=file.info(filename)$size/4+10)

一次性读取所有文件。 +10 有点高估了。

【讨论】:

  • 谢谢。这很有帮助。但是,另一个复杂之处是文件中还有 16 字节的字符串,它们说明了每个数组代表的内容,文件中的 4 字节整数以及元数据。有两个整数 (4)、一个字符串 (16)、三个整数 (4) 给出数组的维度,然后是一个双精度数组,重复次数不详。确实可以大致知道有多少阵列,所以我现在可以进步。请参阅water.usgs.gov/ogw/modflow/MODFLOW-2005-Guide -> FAQ -> L 了解更多详情。
【解决方案3】:

我想我会发布我为此提出的想法。 cbb 是正在构建的数组。在不好的示例中,cbb 使用abind 逐步构建为一个数组。在每一步,cbb 都必须重新评估,因此每个连续的步骤都会变慢 - 一个不断增长的对象。在这个很好的例子中,cbb 被构建为一个列表,并且每一步都声明一个新的列表条目。 R 不需要每次都重新评估现有列表。数组最后用do.call(abind, c(cbb, list(along = 4)))绑定在一起。

我发现有用的一件事是将cat(".") 放入循环中。如果点打印速度减慢,则可能表明对象正在增长。在这个很好的例子中,点的打印速度或多或少是恒定的。好例子比坏例子快十倍左右。

不好:

cbb <- array(NA, c(N1, N2, N3, 0))
repeat{ 
    sptsnew <- readBin(to.read, "integer", 2L, 4L)
    if(identical(sptsnew, integer(0))){cat("\nend of file\n"); break}
    ... #reading array metadata
    cbb <- abind(cbb, array(readBin(to.read, "double", N1*N2*N3, 4L), c(N1, N2, N3, 1)), along = 4)
    cat(".")
}

好:

i <- 1
cbb <- list()
repeat{ 
    sptsnew <- readBin(to.read, "integer", 2L, 4L)
    if(identical(sptsnew, integer(0))){cat("\nend of file\n"); break}
    ... #reading array metadata
    cbb[[i]] <- array(readBin(to.read, "double", N1*N2*N3, 4L), c(N1, N2, N3, 1))
    i <- i + 1
    cat(".")
}
cbb <- do.call(abind, c(cbb, list(along = 4)))

【讨论】:

    猜你喜欢
    • 2020-04-06
    • 1970-01-01
    • 2011-04-09
    • 2022-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多