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 start
valores mejores / diferentes ( initial parameter estimates
tiene un poco más de sentido) pero no estoy seguro, dado el datos que tengo, cómo haría para estimar mejores parámetros.
r
self-study
exponential
starting-values
Amanda
fuente
fuente
exp(50)
yexp(95)
con los valores de y en x = 50 yx = 95. Si establecec=0
y 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]Respuestas:
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
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,c c a c Y Y a c Y
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 comoc c0 yi
Que podemos tomar el registro de:
Esa es una aproximación lineal al modelo. Tanto como b se pueden estimar con mínimos cuadrados.Iniciar sesión( a ) si
Aquí está el código revisado:
Su salida (para los datos de ejemplo) es
La convergencia se ve bien. Vamos a trazarlo:
¡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.y a < 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 .
fuente
Esta biblioteca pudo resolver mi problema con nls
singular gradient
: http://www.r-bloggers.com/a-better-nls/ Un ejemplo:fuente
nls.lm
ahora.Entonces ... creo que leí mal esto como una función exponencial. Todo lo que necesitaba era
poly()
O, usando
lattice
:fuente