Как пропустить ошибку в цикле
Я хочу пропустить ошибку (если она есть) в цикле и продолжить следующую итерацию. Я хочу вычислить 100 обратных матриц матрицы 2 на 2 с элементами, произвольно выбранными из {0, 1, 2}. Можно иметь сингулярную матрицу (например,
1 0
2 0
вот мой код
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
}
на третьей итерации матрица является сингулярной, и код перестает работать с сообщением об ошибке. На практике я хотел бы обойти эту ошибку и перейти к следующему петля. Я знаю, что мне нужно использовать try
или но я не знаю как их использовать. Подобные вопросы были заданы здесь, но все они действительно сложны, и ответы далеко за пределами моего понимания. Если кто-то может дать мне полный код специально для этого вопроса, я очень ценю это.
4 ответов
этой NULL
на inverses
для сингулярных матриц:
inverses[[count]] <- tryCatch(solve(x), error=function(e) NULL)
если первое выражение в вызове tryCatch
вызывает ошибку, он выполняет и возвращает значение функции, поставляемой в его
вместо 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
}
обновление:
однако можно избежать генерации сингулярных матриц. Определитель 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
}
эта процедура является гарантией того, что все полученные матрицы имеют обратные.
try
- это просто способ сказать R
: "Если вы совершаете ошибку в следующих скобках, то пропустите ее и двигайтесь дальше."
так что если вы беспокоитесь, что x <- matrix(sample(0:2, 4, replace = T), 2, 2)
может выдать вам ошибку, то все, что вам нужно сделать, это:
try(x <- matrix(sample(0:2, 4, replace = T), 2, 2))
имейте в виду то, что x
будет неопределенным, если вы это сделаете, и он не сможет вычислить ответ. Это может вызвать проблему, когда вы доберетесь до solve(x)
- поэтому вы можете либо определить x
до try
или просто "попробуйте" все это:
try(
{
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
inverses[[count]] <- solve(x)
}
)
документация для try объясняет вашу проблему довольно хорошо. Я предлагаю вам пройти через это полностью.
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))