R:存储包含循环(或删除循环)的函数的输出

R: Storing outputs from a function containing a loop (or removing the loop)

编辑:现在解决了,下面是解决方案。

我得到了一个 R 函数,我需要针对不同的输入多次 运行,并提取输出(稍后将进入数据框)。下面的可重现示例。

两个问题是:

  1. 我不知道如何将数据从下面的函数输出到可以读取的东西,比如矩阵、字符串、其他对象等。我读过关于将东西输出到列表的内容,但是 (以及无法捕获对象中的输出)这似乎与第二个问题不符,即:
  2. 该函数包含一个循环,因此当我尝试输出数字时,当我需要所有输出时,我通常只获得循环第一次迭代的输出(大多数时候只会是两组数字,但有时会有更多)。

有没有人能请教如何重新处理这个函数,以便它输出一个我可以从中读取值的对象?也许循环可以用 map/lapply 函数或类似函数代替,但我真的很难集中精力编写这些。

可重现的例子(注意,需要 cmprsk 和 survival 包):

numbercruncher<-function(y,ev)
{
  est<-round(y$est*100,1)
  low<-round((exp(log(y$est)-1.96*sqrt(y$var)/y$est))*100,1)
  up<-round((exp(log(y$est)+1.96*sqrt(y$var)/y$est))*100,1)
  d<-nrow(est)/2
  for (i in 1:d){
    rws<-i+d*(ev-1)
    cat("group",i,fill=TRUE)
    out<-t(rbind(est[rws,],low[rws,],up[rws,]))
    colnames(out)<-c("value1","value2","value3")
    print(out)
  }
}

set.seed(1234)
v <-sample(0:2, 1500, replace = TRUE)
t <-sample(0:90, 1500, replace = TRUE)
g <- sample(0:4, 1500, replace = TRUE)

incidence.model <- cuminc(t, v, g, cencode = 0)

incidence.y<-timepoints(incidence.model,times=c(90))

numbercruncher(incidence.y,1)

输出:

     value1 value2 value3
[1,]   48.3   41.7     56
group 2
     value1 value2 value3
[1,]   46.9     40     55
group 3
     value1 value2 value3
[1,]   50.1   42.1   59.6
group 4
     value1 value2 value3
[1,]   49.7   41.2     60
group 5
     value1 value2 value3
[1,]   43.6   37.3   50.9

在这个例子中,理想情况下我会得到一个包含所有 value1 的向量,另一个包含所有 value2,一个包含所有 value3。

感谢您的宝贵时间和帮助!

已解决,使用“<<”

numbercruncher<-function(y,ev)
{
  out.final <<- numeric()
  est<-round(y$est*100,1)
  low<-round((exp(log(y$est)-1.96*sqrt(y$var)/y$est))*100,1)
  up<-round((exp(log(y$est)+1.96*sqrt(y$var)/y$est))*100,1)
  d<-nrow(est)/2
  for (i in 1:d){
    rws<-i+d*(ev-1)
    cat("group",i,fill=TRUE)
    out<-t(rbind(est[rws,],low[rws,],up[rws,]))
    colnames(out)<-c("value1","value2","value3")
    print(out)
    out.final <<- append(out.final, out)
  }
}

set.seed(1234)
v <-sample(0:2, 1500, replace = TRUE)
t <-sample(0:90, 1500, replace = TRUE)
g <- sample(0:4, 1500, replace = TRUE)

incidence.model <- cuminc(t, v, g, cencode = 0)

incidence.y<-timepoints(incidence.model,times=c(90))

numbercruncher(incidence.y,1)

这给出了一个数值向量,可以使用以下方法将其转换为矩阵:

out.final.matrix <- matrix(out.final, ncol = 3, byrow = TRUE)

根据您已解决的解决方案,建议在 R 中避免范围赋值运算符 <<-,由于调试和副作用的原因,这可能很难维护代码。此外,避免在 append.

循环内增加对象

考虑为简化向量(因为所有元素都是数字)调用像 sapplyvapply 这样的应用函数来收集 returned 元素。您也许可以取消 rbindt 调用。 (请注意以下未经测试。)

numbercruncher <- function(y, ev)
{
  est <- round(y$est * 100, 1)
  low <- round((exp(log(y$est) - 1.96 * sqrt(y$var) / y$est)) * 100, 1)
  up <- round((exp(log(y$est) + 1.96 * sqrt(y$var) / y$est)) * 100, 1)
  d <- nrow(est) / 2

  results <- sapply(1:d, function(i) {
    rws <- i+d*(ev-1)
    cat("group",i,fill=TRUE)

    # RETURN NAMED VECTOR
    out <- c(value1=est[rws,], value2=low[rws,], value3=up[rws,])
    return(out)  # REDUNDANT LINE BUT ILLUSTRATIVE
  })

  return(results)  # REDUNDANT LINE BUT ILLUSTRATIVE
}

out.final2 <- numbercruncher(incidence.y,1)

尝试将 sapply 换成 vapply 以获得更快的 return(同样,未经测试):

results <- vapply(1:d, function(i) {
    rws <- i+d*(ev-1)
    cat("group",i,fill=TRUE)

    # RETURN NAMED VECTOR
    out <- c(value1=est[rws,], value2=low[rws,], value3=up[rws,])
    return(out)

}, numeric(3))

上面的输出与 OP 的内容相同。上面的结果不是 15 的向量,而是 3 X 5 的矩阵,可以很容易地转换为向量。

out.final
#  [1] 48.3 41.7 56.0 46.9 40.0 55.0 50.1 42.1 59.6 49.7 41.2 60.0 43.6 37.3 50.9

out.final2
#        [,1] [,2] [,3] [,4] [,5]
# value1 48.3 46.9 50.1 49.7 43.6
# value2 41.7 40.0 42.1 41.2 37.3
# value3 56.0 55.0 59.6 60.0 50.9

identical(out.final, as.vector(out.final2))
# [1] TRUE

使用范围分配找到了非理想的解决方案并与原始问题一起发布 - 虽然我知道这不是最好的方法。