Как я могу избежать ошибки uniroot, которая останавливает цикл?

Я выполняю функцию в цикле, но получаю ошибку, и код останавливается. Код приведен ниже;

      func <-function(f) -a*b/c*0.5*d*e^2 + (d/f-1)*g*sin(h*(pi/180))-i
dat <- data.frame(a = c(0.99,0.99,0.99),
                  b = c(0.1986572,0.1986572,0.1986572),
                  c = c(237.5,237.5,237.5),
                  d = c(1028.372, 1028.711, 1028.372),
                  e = c(2.46261, 2.986461, 2.46261),
                  f = c(-1,-1,-1),
                  g = c(9.8,9.8,9.8),
                  h = c(-54.97964, -51.65978, -54.97964),
                  i = c(0.03699588, -0.0375189, 0.03699588))

for(j in 1:length(dat$a)){
   a <- dat$a[j]
   b <- dat$b[j]
   c <- dat$c[j]
   d <- dat$d[j]
   e <- dat$e[j]
   #f: this should be solved by uniroot
   g <- dat$g[j]
   h <- dat$h[j]
   i <- dat$i[j]
   sol <- uniroot(func,c(0, 2000),extendInt = "yes") 
   dat$f[j] <- sol$root
   print(j)
}

Запустив приведенный выше код, нажмите на ошибку ниже:

      [1] 1
Error in uniroot(func, c(0, 2000), extendInt = "yes") : 
      no sign change found in 1000 iterations

Код остановился на j=1, и не пошел j=2 & 3. Следовательно, dat$f показывает

      > dat$f
[1] 1526.566   -1.000   -1.000

Моя цель - когда возникает ошибка в заданном j, положил NA в dat$f[j], и продолжаем цикл до конца.

Если это сработает, dat$f[1] а также dat$f[3] должен иметь такое же значение (= 1526,566) с использованием вышеуказанного фрейма данных.

Посоветуйте, пожалуйста, как бороться с uniroot ошибка.

1 ответ

Код в вопросе будет работать, если нижняя граница установлена ​​​​на 1 вместо 0. Проблема в том, что если f равно 0, то функция не определена, поскольку f находится в знаменателе.

Хотя этого достаточно, рекомендуется внести следующие изменения:

  1. Используйте данные, указанные в примечании в конце, убедившись, что они НЕ включают f.
  2. определить функцию более компактно, как показано
  3. использовать tryразрешить uniroot продолжать работу, даже если есть ошибки (хотя в этом примере их нет)
  4. используйте нижнюю границу 1, так как func не определена в 0
  5. передать j-ю строку данных в func, используя аргумент uniroot
  6. поместите результаты в res (или NA, если эта итерация не удалась), чтобы не было путаницы в отношении того, что вводится, а что выводится.

Используйте показанную более компактную форму func и поместите результаты в res.

      func <- function(f, data) with(data, -a*b/c*0.5*d*e^2 + (d/f-1)*g*sin(h*(pi/180))-i)
nr <- nrow(dat)
res <- numeric(nr)
for(j in 1:nr){
   sol <- try(uniroot(func, c(1, 2000), data = dat[j, ], extendInt = "yes") )
   res[j] <- if (inherits(sol, "try-error")) NA else sol$root
   print(j)
}
## [1] 1
## [1] 2
## [1] 3
res
## [1] 1526.566 2014.476 1526.566

Примечание

      dat <- data.frame(a = c(0.99,0.99,0.99),
                  b = c(0.1986572,0.1986572,0.1986572),
                  c = c(237.5,237.5,237.5),
                  d = c(1028.372, 1028.711, 1028.372),
                  e = c(2.46261, 2.986461, 2.46261),
                  g = c(9.8,9.8,9.8),
                  h = c(-54.97964, -51.65978, -54.97964),
                  i = c(0.03699588, -0.0375189, 0.03699588))
Другие вопросы по тегам