¿Por qué nls () me da errores de "matriz de gradiente singular en las estimaciones iniciales de parámetros"?

21

Tengo algunos datos básicos sobre la reducción de emisiones y el costo por automóvil:

q24 <- read.table(text = "reductions  cost.per.car
    50  45
    55  55
    60  62
    65  70
    70  80
    75  90
    80  100
    85  200
    90  375
    95  600
    ",header = TRUE, sep = "")

Sé que esta es una función exponencial, por lo que espero poder encontrar un modelo que se ajuste a:

    model <- nls(cost.per.car ~ a * exp(b * reductions) + c, 
         data = q24, 
         start = list(a=1, b=1, c=0))

pero recibo un error:

Error in nlsModel(formula, mf, start, wts) : 
  singular gradient matrix at initial parameter estimates

He leído un montón de preguntas sobre el error que estoy viendo y estoy entendiendo que el problema es probablemente que necesito startvalores mejores / diferentes ( initial parameter estimatestiene un poco más de sentido) pero no estoy seguro, dado el datos que tengo, cómo haría para estimar mejores parámetros.

Amanda
fuente
Sugeriría comenzar su descifrado buscando en nuestro sitio el mensaje de error .
whuber
3
En realidad, hice eso y mi búsqueda del error completo arrojó una pregunta a medias con tres puntos de datos y sin respuesta. Pero su búsqueda más específica obtiene algunos resultados. Posiblemente porque tienes más experiencia aquí y sabes qué términos se destacan como relevantes.
Amanda
Una cosa que he encontrado sobre los errores de software es que una búsqueda del mensaje de error específico (generalmente entre comillas) es la forma más segura de averiguar si se ha discutido antes. (Esto es válido en todo Internet, no solo en los sitios de SE). Como dice nuestro mensaje "en espera", si su investigación adicional no resuelve su problema, por favor regrese y contáctenos un poco: esta pregunta está en La intersección de las estadísticas y la informática y podría exponer algunos temas de gran interés aquí.
whuber
1
El ajuste para sus valores iniciales está muy lejos de los datos; compare exp(50)y exp(95)con los valores de y en x = 50 yx = 95. Si establece c=0y toma el registro de y (haciendo una relación lineal), puede usar la regresión para obtener estimaciones iniciales para el registro ( ) yb que serán suficientes para sus datos (o si ajusta una línea a través del origen, puede dejar a en 1 y solo use la estimación para b ; eso también es suficiente para sus datos). Si b está muy fuera de un intervalo bastante estrecho alrededor de esos dos valores, se encontrará con algunos problemas. [Alternativamente, pruebe con un algoritmo diferente]ababb
Glen_b -Reinstate Monica
1
Gracias @Glen_b. Tenía la esperanza de poder usar R en lugar de una calculadora gráfica para trabajar a través de un libro de texto de introducción de estadísticas (y saltar el curso en sí), así que estoy comenzando con la visión estadística más simple, pero mucha experiencia haciendo otros cortes y cortes en R .
Amanda

Respuestas:

38

Encontrar automáticamente buenos valores iniciales para un modelo no lineal es un arte. (Es relativamente fácil para los conjuntos de datos únicos cuando solo puede trazar los datos y hacer algunas buenas suposiciones visuales). Un enfoque es linealizar el modelo y usar estimaciones de mínimos cuadrados.

En este caso, el modelo tiene la forma

E(Y)=aexp(bx)+c

para parámetros desconocidos . La presencia de lo exponencial nos anima a usar logaritmos, pero la adición de c hace que sea difícil hacerlo. Nótese, sin embargo, que si una es positiva entonces c será menor que el menor valor esperado de Y -y, por tanto, podría ser un poco menor que la más pequeña observada valor de Y . (Si a puede ser negativo, también tendrá que considerar un valor de c que sea un poco mayor que el mayor valor observado de Y ).a,b,ccacYYacY

Entonces, cuidemos de usando como estimación inicial c 0 algo así como la mitad del mínimo de las observaciones y i . El modelo ahora puede reescribirse sin ese término aditivo espinoso comocc0yi

E(Y)c0aexp(bx).

Que podemos tomar el registro de:

Iniciar sesión(mi(Y)-C0 0)Iniciar sesión(un)+siX.

Esa es una aproximación lineal al modelo. Tanto como b se pueden estimar con mínimos cuadrados.Iniciar sesión(un)si

Aquí está el código revisado:

c.0 <- min(q24$cost.per.car) * 0.5
model.0 <- lm(log(cost.per.car - c.0) ~ reductions, data=q24)
start <- list(a=exp(coef(model.0)[1]), b=coef(model.0)[2], c=c.0)
model <- nls(cost.per.car ~ a * exp(b * reductions) + c, data = q24, start = start)

Su salida (para los datos de ejemplo) es

Nonlinear regression model
  model: cost.per.car ~ a * exp(b * reductions) + c
   data: q24
        a         b         c 
 0.003289  0.126805 48.487386 
 residual sum-of-squares: 2243

Number of iterations to convergence: 38 
Achieved convergence tolerance: 1.374e-06

La convergencia se ve bien. Vamos a trazarlo:

plot(q24)
p <- coef(model)
curve(p["a"] * exp(p["b"] * x) + p["c"], lwd=2, col="Red", add=TRUE)

Figura

¡Funcionó bien!

Al automatizar esto, puede realizar algunos análisis rápidos de los residuos, como comparar sus extremos con la dispersión en los datos ( ). También es posible que necesite un código análogo para lidiar con la posibilidad a < 0 ; Lo dejo como ejercicio.yun<0 0


Otro método para estimar los valores iniciales se basa en comprender lo que significan, que puede basarse en la experiencia, la teoría física, etc. En mi respuesta se describe un ejemplo extendido de un ajuste no lineal (moderadamente difícil) cuyos valores iniciales se pueden determinar de esta manera. en /stats//a/15769 .

El análisis visual de un diagrama de dispersión (para determinar las estimaciones iniciales de los parámetros) se describe e ilustra en /stats//a/32832 .

En algunas circunstancias, se realiza una secuencia de ajustes no lineales donde puede esperar que las soluciones cambien lentamente. En ese caso, a menudo es conveniente (y rápido) usar las soluciones anteriores como estimaciones iniciales para las siguientes . Recuerdo haber usado esta técnica (sin comentarios) en /stats//a/63169 .

whuber
fuente
2

Esta biblioteca pudo resolver mi problema con nls singular gradient: http://www.r-bloggers.com/a-better-nls/ Un ejemplo:

library(minpack.lm)
nlsLM(function, start=list(variable=2,variable2=12))
joshring
fuente
Esa función parece llamarse nls.lmahora.
Matt
-1

Entonces ... creo que leí mal esto como una función exponencial. Todo lo que necesitaba erapoly()

model <- lm(cost.per.car ~ poly(reductions, 3), data=q24)
new.data <- data.frame(reductions = c(91,92,93,94))
predict(model, new.data)

plot(q24)
lines(q24$reductions, predict(model, list(reductions = q24$reductions)))

O, usando lattice:

xyplot(cost.per.car ~ reductions, data = q24,
       panel = function(x, y) {
         panel.xyplot(x, y)
         panel.lines(x, predict(model,list(reductions = x) ))
       }, 
       xlab = "Reductions", 
       ylab = "Cost per car")
Amanda
fuente
2
Esto no responde la pregunta que hizo: lo cambia a algo diferente (y bastante menos interesante, en mi humilde opinión).
whuber
66
Aunque puede resolver el problema de ajustar una función para representar los datos, sus respuestas aceptadas no son las esperadas para su pregunta. El Sr. @whuber le proporcionó una excelente explicación y merece la respuesta aceptada.
Lourenco