nls - ошибка сходимости

Для этого набора данных:

dat = structure(list(x = c(5L, 5L, 5L, 5L, 10L, 10L, 10L, 10L, 15L, 
15L, 15L, 15L, 17L, 17L, 17L, 17L, 20L, 20L, 20L, 20L, 20L, 20L, 
20L, 20L, 22L, 22L, 22L, 22L, 24L, 24L, 24L, 24L, 25L, 25L, 25L, 
25L, 27L, 27L, 27L, 27L, 30L, 30L, 30L, 30L, 35L, 35L, 35L, 35L), 
y = c(2.2, 2.2, 1.95, 1.9, 4.1, 3.95, 3.75, 3.4, 5.15, 4.6, 
4.75, 5.15, 3.7, 4.1, 3.9, 3.5, 7, 6.7, 6.7, 6.95, 4.95, 6, 6.45, 
6.4, 7, 4.45, 6.15, 6.4, 7, 6.6, 6.7, 7, 4.5, 4.7, 5.75, 4.35, 
5.4, 5.15, 5.7, 5.7, 0, 0, 0.5, 0, 0, 0, 0, 0)), .Names = c("x", "y"), 
row.names = c(6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 
15L, 16L, 17L, 34L, 35L, 36L, 37L, 18L, 19L, 20L, 21L, 38L, 39L, 
40L, 41L, 42L, 43L, 44L, 45L, 46L, 47L, 48L, 49L, 22L, 23L, 24L, 
25L, 50L, 51L, 52L, 53L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 33L), 
class = "data.frame")

Где «x» - это температура, а «y» - это переменная реакции биологического процесса.

Я пытаюсь приспособиться к этой функции

beta.reg<-function(x, Yopt,Tmin,Topt,Tmax, b1) {
Yopt*((x-Tmin)/(Topt-Tmin))^(b1*(Topt-Tmin)/(Tmax-Topt))*((Tmax-x) / (Tmax-Topt)) ^ b1
}

mod <- nls(y ~ beta.reg(x, Yopt,Tmin,Topt,Tmax, b1), data=dat,
       start=c(Yopt=6, Tmin=0.1, Topt=24, Tmax=30, b1=1),
       control=nls.control(maxiter=800))

Но у меня появляется это сообщение об ошибке:

Ошибка en numericDeriv (form [[3L]], names (ind), env): отсутствующее значение или бесконечность, полученная при оценке модели.

Я пробовал ту же функцию с другим аналогичным набором данных и подходит правильно ...

 rnorm<-(10)
 y <- c(20,60,70,49,10)
 rnorm<-(10)
 y <- c(20,60,70,49,10)
 dat<-data.frame(x = rep(c(15,20,25,30,35), times=5),
              rep = as.factor(rep(1:5, each=5)),
              y = c(y+rnorm(5), y+rnorm(5),y+rnorm(5),y+rnorm(5),y+rnorm(5)))

Может ли кто-нибудь помочь мне с этим?

Информация о сеансе:

R version 3.1.1 (2014-07-10)
Platform: x86_64-pc-linux-gnu (64-bit)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] nlme_3.1-118        latticeExtra_0.6-26 RColorBrewer_1.0-5  lattice_0.20-29    

loaded via a namespace (and not attached):
[1] grid_3.1.1  tools_3.1.1

person Juanchi    schedule 31.10.2014    source источник
comment
Это в R? Если это так, вам следует добавить тег r.   -  person John Saunders    schedule 01.11.2014


Ответы (2)


Здесь так много проблем, что я сомневаюсь, что они могут быть адекватно освещены в сообщении SO, но это должно помочь вам начать.

Во-первых, похоже, что вы хотите Tmax < max(dat$x), например ‹35. Это вызывает проблему, потому что тогда Tmax - x < 0 для некоторых значений x и когда вы пытаетесь возвести отрицательное число в степень (во втором члене вашей формулы), вы получаете NA's. Это причина сообщения об ошибке.

Во-вторых, сходимость нелинейной модели зависит от формулы модели, а также от данных, поэтому тот факт, что процесс сходится с одним набором данных, но не с другим, совершенно не имеет значения.

В-третьих, нелинейное моделирование итеративно минимизирует остаточную сумму квадратов как функцию параметров. Если поверхность RSS имеет локальные минимумы, а ваш start близок к единице, алгоритмы его найдут. Но только глобальный минимум является верным решением. У вашей проблемы много-много локальных минимумов.

В-четвертых, nls(...) по умолчанию использует метод Гаусса-Ньютона. Гаусс Ньютон, как известно, нестабилен со смещением параметров (параметры, которые добавляются или вычитаются из предиктора, поэтому Tmin и Tmax в вашем случае). К счастью, в пакете minpak.lm реализован метод Левенберга-Марквардта, который в этих условиях гораздо более устойчив. Функция nlsLM(...) в этом пакете использует ту же последовательность вызовов, что и nls(...), и возвращает объект типа nls, поэтому все методы для этого класса объекта также работают. Используйте это.

В-пятых, фундаментальное предположение нелинейной регрессии (фактически, все регрессии методом наименьших квадратов) состоит в том, что остатки распределены нормально. Таким образом, вы должны проверить любое решение, используя график Q-Q.

В-шестых, ваша модель обладает извращенным набором характеристик. Когда Tmin -> -Inf первый член модели приближается к 1. Оказывается, это дает более низкий RSS, чем любое другое значение Tmin меньше min(dat$x), поэтому все алгоритмы имеют тенденцию приводить Tmin к большим отрицательным значениям. В этом легко убедиться:

library(minpack.lm)
mod <- nlsLM(y ~ beta.reg(x, Yopt,Tmin,Topt,Tmax, b1), data=dat,
             start=c(Yopt=6,Tmin=0,Topt=24,Tmax=50, b1=1),
             control=nls.lm.control(maxiter=1024,maxfev=1024))
coef(summary(mod))
#         Estimate   Std. Error     t value     Pr(>|t|)
# Yopt    6.347019    0.2919686 21.73870235 8.055342e-25
# Tmin -155.530098 2204.0011003 -0.07056716 9.440694e-01
# Topt   21.157545    0.6702713 31.56564484 2.240134e-31
# Tmax   35.000000   11.4838614  3.04775537 3.933164e-03
# b1      3.321326    9.1844548  0.36162468 7.194035e-01
sum(residuals(mod)^2)
# [1] 50.24696

par(mfrow=c(1,2))
plot(y~x,dat)
with(as.list(coef(mod)),curve(beta.reg(x, Yopt,Tmin,Topt,Tmax, b1),add=TRUE))
qqnorm(residuals(mod))

Это выглядит довольно неплохо, но это не так: график Q-Q показывает, что остатки далеко не нормальны. Тот факт, что и Tmin, и b1 очень плохо оценены, а значение Tmin не имеет физического смысла, это проблемы с данными, а не с соответствием.

В-седьмых, оказывается, что приведенное выше соответствие на самом деле является локальным минимумом. Мы можем убедиться в этом, выполнив поиск по сетке по Tmin, Tmax и b1 (исключая Yopt и Topt, чтобы сэкономить время, и потому, что эти параметры хорошо оцениваются независимо от начальной точки).

init <- c(Yopt=6, Topt=24)
grid <- expand.grid(Tmin= seq(0,4,len=100),
                    Tmax= seq(35,100,len=10),
                    b1  = seq(1,10,len=10))
mod.lst <- apply(grid,1,function(gr){
  nlsLM(y ~ beta.reg(x, Yopt,Tmin,Topt,Tmax, b1), data=dat,
        start=c(init,gr),control=nls.control(maxiter=800)) })
rss <- sapply(mod.lst,function(m)sum(residuals(m)^2))
mod <- mod.lst[[which.min(rss)]]   # fit with lowest RSS
coef(summary(mod))
#        Estimate   Std. Error      t value     Pr(>|t|)
# Yopt   6.389238    0.2534551 25.208557840 2.177168e-27
# Topt  22.636505    0.5605621 40.381798589 7.918438e-36
# Tmin  35.000002  104.6221159  0.334537316 7.396005e-01
# Tmax  36.234602  133.4987344  0.271422809 7.873647e-01
# b1   -41.512912 7552.0298633 -0.005496921 9.956395e-01
sum(residuals(mod)^2)
# [1] 34.24019

plot(y~x,dat)
with(as.list(coef(mod)),curve(beta.reg(x, Yopt,Tmin,Topt,Tmax, b1),add=TRUE))
qqnorm(residuals(mod))

С математической точки зрения это явно превосходное соответствие: RSS ниже, а остатки распределены гораздо ближе к нормальному. Опять же, тот факт, что параметры плохо оценены и не имеют физического смысла, является проблемой с данными (и, возможно, с формулой модели), а не с процессом подбора.

Все вышесказанное говорит о том, что с вашей моделью что-то не так. С математической точки зрения одна проблема заключается в том, что функция не определена для x за пределами (Tmin,Tmax). Поскольку у вас есть данные до x=35, алгоритм подгонки никогда не даст Tmax < 35 (если он сходится). Подход, чтобы справиться с этим, немного изменяет функцию вашей модели, чтобы обрезать до 0 за пределами этого диапазона. (Хотя я понятия не имею, законно ли это, исходя из физики вашей проблемы ...).

beta.reg<-function(x, Yopt,Tmin,Topt,Tmax, b1) {
  ifelse(x>Tmax,0,
    ifelse(x<Tmin,0,
      Yopt*((x-Tmin)/(Topt-Tmin))^(b1*(Topt-Tmin)/(Tmax-Topt))*((Tmax-x) / (Tmax-Topt)) ^ b1
  ))
}

Выполнение приведенного выше кода с этой функцией дает:

coef(summary(mod))
#         Estimate   Std. Error     t value     Pr(>|t|)
# Yopt   6.1470413   0.21976766   27.970636 3.202940e-29
# Tmin -52.8172658 184.16899439   -0.286787 7.756528e-01
# Topt  23.0777898   0.63750721   36.200045 7.638121e-34
# Tmax  30.0039413   0.02529877 1185.984187 1.038918e-98
# b1     0.5966129   0.32439982    1.839128 7.280793e-02

sum(residuals(mod)^2)
# [1] 28.10144

par(mfrow=c(1,2))
plot(y~x,dat)
with(as.list(coef(mod)),curve(beta.reg(x, Yopt,Tmin,Topt,Tmax, b1),add=TRUE))
qqnorm(residuals(mod))
qqline(residuals(mod))

Фактически поиск по сетке дает точно такой же результат независимо от начальной точки. Обратите внимание, что RSS ниже, чем любой из результатов с более ранней моделью, и что b1 гораздо лучше оценен (и очень отличается от оценки с более ранней функцией модели). Остатки по-прежнему ненормальные, но в этом случае я хотел бы проверить данные на наличие выбросов.

person jlhoward    schedule 02.11.2014
comment
Отлично @jlhoward! Я также думаю, что в наборе данных много проблем, но это биология ... Я прокомментирую каждую точку вашего ответа: 1-е - Очевидно, если я проверю температуру ›30 ° C, ответ будет около 0. Я подумал об исключении Точка 35 ° C, чтобы иметь Tmax < max(x); 2-й - я просто привожу второй пример, чтобы показать, что функция действительно работает, и дать представление о форме кривой; 4-е - я действительно не знал этот пакет, он хорошо выглядит! 6-В будущих экспериментах я включу понижения T ° C, чтобы избежать подобных ошибок Tmin < min(dat$x) - person Juanchi; 03.11.2014
comment
Ваша последняя модель, кажется, имеет лучший биологический смысл, не считая Tmin. Думаю, с этой моделью и набором данных будет сложно оценить Tmin. Что вы думаете о подборе линейной модели с подмножеством x's ‹Topt для оценки Tmin? Может быть решение? - person Juanchi; 03.11.2014
comment
Прежде чем я это сделал, я бы просмотрел данные вокруг x ~ 17. В этих репликах есть что-то странное: трудно объяснить, почему ваш ответ такой же, как на x ~ 10, плюс эти моменты объясняют большую часть отклонения от нормальности в остатках. Вы можете исключить эти реплики и переоборудовать. - person jlhoward; 03.11.2014
comment
У меня появляется это сообщение об ошибке при установке пакета minpak.lm: [Предупреждение в install.packages: пакет «minpak.lm» недоступен (для R версии 3.1.2)] - person Juanchi; 03.11.2014
comment
Это minpack.lm с буквой "c". - person jlhoward; 04.11.2014

Добавление еще одного возможного решения к @jlhoward ...

Я нашел этот nls2 пакет:

library("nls2")

Исключение x~17,35 из исходного набора данных:

newdat <- subset(dat, x!=17 & x!=35 )

Применение функции к сокращенному набору данных:

beta.reg<-with(newdat,  
           y ~ Yopt*((x-Tmin)/(Topt-Tmin))^(b1*(Topt-Tmin)/(Tmax-Topt))*((Tmax-x) / Tmax-Topt))^b1
           )

Создание набора стартеров:

st1 <- expand.grid(Yopt = seq(4, 8, len = 4),
                   Tmin = seq(0, 4, len = 4), 
                   Topt = seq(15, 25, len = 4),
                   Tmax= seq(28, 38, len = 4),
                   b1 = seq(0, 4, len = 4))

Примерка модели:

mod <- nls2(beta.reg, start = st1, algorithm = "brute-force")

Коэффициенты извлечения:

round(coef(summary(mod)),3)

#     Estimate Std. Error t value Pr(>|t|)
# Yopt    6.667      0.394  16.925    0.000
# Tmin    0.000     12.023   0.000    1.000
# Topt   21.667      0.746  29.032    0.000
# Tmax   31.333      1.924  16.289    0.000
# b1      1.333      1.010   1.320    0.197

Диагностика:

sum(residuals(mod)^2)

# [1] 50.18246

И, наконец, скорректированная функция и график QQ-normal:

par(mfrow=c(1,2))
with(newdat,plot(y~x,xlim=c(0,35))) 
points(fitted(mod)~I(newdat$x), pch=19)
with(as.list(coef(mod)),
 curve(
  Yopt*((x-Tmin)/(Topt-Tmin))^(b1*(Topt-Tmin)/(Tmax-Topt))*((Tmax-x) / (Tmax-Topt)) ^ b1,
   add=TRUE, col="red"))

qqnorm(residuals(mod))
qqline(residuals(mod))

person Juanchi    schedule 03.11.2014
comment
Для записи nls2(...) (как вы его используете) не минимизирует RSS, он вычисляет RSS в каждой из 4 ^ 5 = 1024 точек сетки и сообщает точку с самым низким RSS. Вот почему вы получаете Tmin=0; более низкие значения Tmin приведут к более низкому значению RSS, но это самое низкое значение в вашей сетке. - person jlhoward; 04.11.2014
comment
Это так. Таким образом, я попытался ограничить оценку Tmin некоторой биологической смысловой ценностью, жертвуя RSS. Это такие же ограничения, как у вашей прошлой модели? beta.reg<-function(x, Yopt,Tmin,Topt,Tmax, b1) { ifelse(x>Tmax,0, ifelse(x<Tmin,0, Yopt*((x-Tmin)/(Topt-Tmin))^(b1*(Topt-Tmin)/(Tmax-Topt))*((Tmax-x) / (Tmax-Topt)) ^ b1 )) } - person Juanchi; 04.11.2014
comment
Нет. Модель выше просто ограничивает функцию возвращать 0, если x находится вне диапазона (Tmin,Tmax). Он вообще не ограничивает Tmin или Tmax. Что вы сделали, так это нашли минимальный RSS (более или менее, это очень грубая сетка) с учетом выбранного пространства параметров. Это лучше всего подходит в смысле RSS, но вы должны знать, что статистика соответствия (значения se для параметров и т. Д.) Совершенно бессмысленна, когда вы делаете это таким образом. - person jlhoward; 04.11.2014
comment
Кроме того, все методы рассказывают одну и ту же историю о Tmin - его невозможно точно оценить с учетом ваших данных и этой модели. В последней модели в другом ответе Tmin ~ -52 +/- 360, поэтому это может быть что угодно. Обратите внимание, однако, на то, что разные подходы дают очень разные оценки b1. - person jlhoward; 04.11.2014