我有一个函数,它返回一个带有两个变量的数据帧。举个简单的例子,我们有:
test <- function(x) {y <- matrix( 5 , nrow= x , ncol = 2)
z<- data.frame(y)
return(z) }
我想找出这个函数给出错误的x值。 (在我们的例子中,我认为负值,但我只是想传达这个概念。)所以我尝试:
z <- rep(0)
testnumbers <- c(0,1,2,3,4,-1,5)
for (i in 1:length(testnumbers)) {
tempo <- tryCatch( testfun(testnumbers[i]) , error= function(e) return(0) )
if (tempo == 0 ) z[i] <- {testnumbers[i] next}
}
我的流程有什么问题,如何找到我的功能无效的地方?
答案 0 :(得分:2)
如果你想要运行testnumbers
的所有而不管其中任何一个失败,我建议稍微不同。
这借鉴了Rui对inherits
的使用,它更加强大和明确。它更进一步,不仅保留哪一个有错误,还保留实际的错误文本:
testfun <- function(x) {
y <- matrix(5, nrow = x, ncol = 2)
z <- as.data.frame(y)
z
}
testnumbers <- c(0, 1, 2, 3, 4, -1, 5)
rets <- setNames(
lapply(testnumbers, function(n) tryCatch(testfun(n), error=function(e) e)),
testnumbers
)
sapply(rets, inherits, "error")
# 0 1 2 3 4 -1 5
# FALSE FALSE FALSE FALSE FALSE TRUE FALSE
Filter(function(a) inherits(a, "error"), rets)
# $`-1`
# <simpleError in matrix(5, nrow = x, ncol = 2): invalid 'nrow' value (< 0)>
(setNames(lapply(...), ...)
是因为输入是数字,所以sapply(..., simplify=F)
没有保留名称,我认为这很重要。)
所有这一切都与一些人认为好的做法一致:如果你正在为很多“事情”做一个功能,那么就在list
中进行,因此在{*apply
中进行1}}函数。
tidyverse
purrr
中有一个函数可以将其形式化为safely
,它返回一个围绕其参数的函数。例如:
library(purrr)
safely(testfun)
# function (...)
# capture_error(.f(...), otherwise, quiet)
# <environment: 0x0000000015151d90>
它返回一个可以传递的函数。一次性通话看起来像下列之一:
safely(testfun)(0)
# $result
# [1] V1 V2
# <0 rows> (or 0-length row.names)
# $error
# NULL
testfun_safe <- safely(testfun)
testfun_safe(0)
# $result
# [1] V1 V2
# <0 rows> (or 0-length row.names)
# $error
# NULL
要在此处使用,您可以:
rets <- setNames(
lapply(testnumbers, safely(testfun)),
testnumbers
)
str(rets[5:6])
# List of 2
# $ 4 :List of 2
# ..$ result:'data.frame': 4 obs. of 2 variables:
# .. ..$ V1: num [1:4] 5 5 5 5
# .. ..$ V2: num [1:4] 5 5 5 5
# ..$ error : NULL
# $ -1:List of 2
# ..$ result: NULL
# ..$ error :List of 2
# .. ..$ message: chr "invalid 'nrow' value (< 0)"
# .. ..$ call : language matrix(5, nrow = x, ncol = 2)
# .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
Filter(Negate(is.null), sapply(rets, `[[`, "error"))
# $`-1`
# <simpleError in matrix(5, nrow = x, ncol = 2): invalid 'nrow' value (< 0)>
并获得所有运行的结果(包括错误运行):
str(sapply(rets, `[[`, "result"))
# List of 7
# $ 0 :'data.frame': 0 obs. of 2 variables:
# ..$ V1: num(0)
# ..$ V2: num(0)
# $ 1 :'data.frame': 1 obs. of 2 variables:
# ..$ V1: num 5
# ..$ V2: num 5
# $ 2 :'data.frame': 2 obs. of 2 variables:
# ..$ V1: num [1:2] 5 5
# ..$ V2: num [1:2] 5 5
# $ 3 :'data.frame': 3 obs. of 2 variables:
# ..$ V1: num [1:3] 5 5 5
# ..$ V2: num [1:3] 5 5 5
# $ 4 :'data.frame': 4 obs. of 2 variables:
# ..$ V1: num [1:4] 5 5 5 5
# ..$ V2: num [1:4] 5 5 5 5
# $ -1: NULL
# $ 5 :'data.frame': 5 obs. of 2 variables:
# ..$ V1: num [1:5] 5 5 5 5 5
# ..$ V2: num [1:5] 5 5 5 5 5
或只是未运行失败的结果:
str(Filter(Negate(is.null), sapply(rets, `[[`, "result")))
# List of 6
# $ 0:'data.frame': 0 obs. of 2 variables:
# ..$ V1: num(0)
# ..$ V2: num(0)
# $ 1:'data.frame': 1 obs. of 2 variables:
# ..$ V1: num 5
# ..$ V2: num 5
# $ 2:'data.frame': 2 obs. of 2 variables:
# ..$ V1: num [1:2] 5 5
# ..$ V2: num [1:2] 5 5
# $ 3:'data.frame': 3 obs. of 2 variables:
# ..$ V1: num [1:3] 5 5 5
# ..$ V2: num [1:3] 5 5 5
# $ 4:'data.frame': 4 obs. of 2 variables:
# ..$ V1: num [1:4] 5 5 5 5
# ..$ V2: num [1:4] 5 5 5 5
# $ 5:'data.frame': 5 obs. of 2 variables:
# ..$ V1: num [1:5] 5 5 5 5 5
# ..$ V2: num [1:5] 5 5 5 5 5
答案 1 :(得分:1)
你其实很亲密。我不知道到底是什么伎俩,但我
return(0)
更改为字符然后你得到了正确的结果。您可以尝试逐位更改代码以查看错误。
test <- function(x) {y <- matrix( 5 , nrow = x , ncol = 2)
z<- data.frame(y)
return(z) }
errored <- numeric()
testnumbers <- c(0,1,2,3,4,-1,5)
for (i in testnumbers) {
tempo <- tryCatch(test(i), error = function(e) "error")
if (length(tempo) == 1) {
if (tempo == "error") errored <- c(errored, i)
}
}
errored
> -1
答案 2 :(得分:1)
您需要tryCatch
才能返回错误,而不是零。
testfun <- function(x) {
y <- matrix(5, nrow = x, ncol = 2)
z <- as.data.frame(y)
z
}
testnumbers <- c(0, 1, 2, 3, 4, -1, 5)
z <- numeric(length(testnumbers))
for (i in seq_along(testnumbers)) {
tempo <- tryCatch(testfun(testnumbers[i]), error = function(e) e)
if (inherits(tempo, "error")) {
z[i] <- testnumbers[i]
}
}
z
#[1] 0 0 0 0 0 -1 0
另外,
matrix
data.frame
使用as.data.frame
。return
的调用,因为函数的最后一个值是其返回值。 rep(0)
与0
相同,由numeric(length(testnumbers))
取代。seq_along(testnumbers)
总是优于1:length(testnumbers)
。尝试使用长度为零的testnumbers
,看看会发生什么。