Pat*_* Li 26 error-handling r try-catch
我想在循环中跳过错误(如果有的话)并继续下一次迭代.我想计算具有从{0,1,2}随机采样的元素的2乘2矩阵的100个逆矩阵.可以有一个奇异矩阵(例如,
1 0
2 0
Run Code Online (Sandbox Code Playgroud)
这是我的代码
set.seed(1)
count <- 1
inverses <- vector(mode = "list", 100)
repeat {
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
inverses[[count]] <- solve(x)
count <- count + 1
if (count > 100) break
}
Run Code Online (Sandbox Code Playgroud)
在第三次迭代中,矩阵是单数的,代码停止运行并显示错误消息.在实践中,我想绕过这个错误并继续下一个循环.我知道我需要使用try或tryCatch功能,但我不知道如何使用它们.这里也提出了类似的问题,但它们都非常复杂,答案远远超出我的理解范围.如果有人能够专门为这个问题提供完整的代码,我真的很感激.
Mat*_*rde 29
这将使NULLs转换inverses为奇异矩阵:
inverses[[count]] <- tryCatch(solve(x), error=function(e) NULL)
Run Code Online (Sandbox Code Playgroud)
如果调用中的第一个表达式tryCatch引发错误,它将执行并返回提供给其error参数的函数的值.提供给errorarg 的函数必须将错误本身作为参数(这里我称之为e),但你不必对它做任何事情.
然后你可以删除NULL条目inverses[! is.null(inverses)].
或者,您可以使用较低级别try.选择真的是品味问题.
count <- 0
repeat {
if (count == 100) break
count <- count + 1
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
x.inv <- try(solve(x), silent=TRUE)
if ('try-error' %in% class(x.inv)) next
else inverses[[count]] <- x.inv
}
Run Code Online (Sandbox Code Playgroud)
如果表达式生成错误,则try返回带有类的对象try-error.它将打印消息到屏幕if silent=FALSE.在这种情况下,如果x.inv有类try-error,我们称之为next停止当前迭代的执行,并移动到下一个,否则我们添加x.inv到inverses.
你可以避免使用和使用repeat循环.replicatelapply
matrices <- replicate(100, matrix(sample(0:2, 4, replace=T), 2, 2), simplify=FALSE)
inverses <- lapply(matrices, function(mat) if (det(mat) != 0) solve(mat))
Run Code Online (Sandbox Code Playgroud)
有趣的是要注意第二个参数replicate被视为一个expression,意味着它会重新执行每个复制.这意味着你可以使用replicate作出list的任何数量的来自同一个表达式生成的随机对象的.
而不是使用tryCatch你可以简单地用函数计算矩阵的行列式det.当且仅当行列式为零时,矩阵才是奇异的.
因此,您可以测试行列式是否与零不同,并仅在测试为正时计算逆:
set.seed(1)
count <- 1
inverses <- vector(mode = "list", 100)
repeat {
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
# if (det(x)) inverses[[count]] <- solve(x)
# a more robust replacement for the above line (see comment):
if (is.finite(determinant(x)$modulus)) inverses[[count]] <- solve(x)
count <- count + 1
if (count > 100) break
}
Run Code Online (Sandbox Code Playgroud)
更新:
但是,可以避免生成奇异矩阵.2乘2矩阵的行列式mat定义为mat[1] * mat[4] - mat[3] * mat[2].您可以使用此知识对随机数进行采样.只是不要采样会产生奇异矩阵的数字.当然,这取决于之前采样的数字.
set.seed(1)
count <- 1
inverses <- vector(mode = "list", 100)
set <- 0:2 # the set of numbers to sample from
repeat {
# sample the first value
x <- sample(set, 1)
# if the first value is zero, the second and third one are not allowed to be zero.
new_set <- ifelse(x == 0, setdiff(set, 0), set)
# sample the second and third value
x <- c(x, sample(new_set, 2, replace = T))
# calculate which 4th number would result in a singular matrix
not_allowed <- abs(-x[3] * x[2] / x[1])
# remove this number from the set
new_set <- setdiff(0:2, not_allowed)
# sample the fourth value and build the matrix
x <- matrix(c(x, sample(new_set, 1)), 2, 2)
inverses[[count]] <- solve(x)
count <- count + 1
if (count > 100) break
}
Run Code Online (Sandbox Code Playgroud)
此过程可保证所有生成的矩阵都具有反转.
try只是一种说法R:"如果你在下面的括号内提交错误,那么跳过它然后继续."
因此,如果您担心x <- matrix(sample(0:2, 4, replace = T), 2, 2)可能会给您一个错误,那么您所要做的就是:
try(x <- matrix(sample(0:2, 4, replace = T), 2, 2))
Run Code Online (Sandbox Code Playgroud)
但是,请记住,x如果你这样做将是不确定的,它最终无法计算答案.当你到达时可能会导致问题solve(x)- 所以你可以在x之前定义try或者只是"尝试"整个事情:
try(
{
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
inverses[[count]] <- solve(x)
}
)
Run Code Online (Sandbox Code Playgroud)
试用文档很好地解释了你的问题.我建议你彻底完成它.
Edit:文档示例看起来非常简单,与op的问题非常相似.(还是)感谢你的建议.以下是文档页面中示例的答案:
# `idx` is used as a dummy variable here just to illustrate that
# all 100 entries are indeed calculated. You can remove it.
set.seed(1)
mat_inv <- function(idx) {
print(idx)
x <- matrix(sample(0:2, 4, replace = T), nrow = 2)
solve(x)
}
inverses <- lapply(1:100, function(idx) try(mat_inv(idx), TRUE))
Run Code Online (Sandbox Code Playgroud)