R:存储包含循环(或删除循环)的函数的输出
R: Storing outputs from a function containing a loop (or removing the loop)
编辑:现在解决了,下面是解决方案。
我得到了一个 R 函数,我需要针对不同的输入多次 运行,并提取输出(稍后将进入数据框)。下面的可重现示例。
两个问题是:
- 我不知道如何将数据从下面的函数输出到可以读取的东西,比如矩阵、字符串、其他对象等。我读过关于将东西输出到列表的内容,但是 (以及无法捕获对象中的输出)这似乎与第二个问题不符,即:
- 该函数包含一个循环,因此当我尝试输出数字时,当我需要所有输出时,我通常只获得循环第一次迭代的输出(大多数时候只会是两组数字,但有时会有更多)。
有没有人能请教如何重新处理这个函数,以便它输出一个我可以从中读取值的对象?也许循环可以用 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
.
循环内增加对象
考虑为简化向量(因为所有元素都是数字)调用像 sapply
或 vapply
这样的应用函数来收集 returned 元素。您也许可以取消 rbind
和 t
调用。 (请注意以下未经测试。)
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
使用范围分配找到了非理想的解决方案并与原始问题一起发布 - 虽然我知道这不是最好的方法。
编辑:现在解决了,下面是解决方案。
我得到了一个 R 函数,我需要针对不同的输入多次 运行,并提取输出(稍后将进入数据框)。下面的可重现示例。
两个问题是:
- 我不知道如何将数据从下面的函数输出到可以读取的东西,比如矩阵、字符串、其他对象等。我读过关于将东西输出到列表的内容,但是 (以及无法捕获对象中的输出)这似乎与第二个问题不符,即:
- 该函数包含一个循环,因此当我尝试输出数字时,当我需要所有输出时,我通常只获得循环第一次迭代的输出(大多数时候只会是两组数字,但有时会有更多)。
有没有人能请教如何重新处理这个函数,以便它输出一个我可以从中读取值的对象?也许循环可以用 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
.
考虑为简化向量(因为所有元素都是数字)调用像 sapply
或 vapply
这样的应用函数来收集 returned 元素。您也许可以取消 rbind
和 t
调用。 (请注意以下未经测试。)
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
使用范围分配找到了非理想的解决方案并与原始问题一起发布 - 虽然我知道这不是最好的方法。