Как пропустить ошибку в цикле

Я хочу пропустить ошибку (если она есть) в цикле и продолжить следующую итерацию. Я хочу вычислить 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))