Perché nls () mi dà errori di "matrice gradiente singolare alle stime iniziali dei parametri"?


21

Ho alcuni dati di base sulla riduzione delle emissioni e sul costo per auto:

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 = "")

So che questa è una funzione esponenziale, quindi mi aspetto di riuscire a trovare un modello adatto a:

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

ma sto ricevendo un errore:

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

Ho letto un sacco di domande sull'errore che sto vedendo e sto raccogliendo che il problema è probabilmente che ho bisogno di startvalori migliori / diversi (il che initial parameter estimatesha un po 'più senso) ma non sono sicuro, dato il dati che ho, come farei per stimare parametri migliori.


Suggerirei di iniziare la decifratura cercando nel nostro sito il messaggio di errore .
whuber

3
In realtà, l'ho fatto e la mia ricerca dell'errore completo ha prodotto una domanda a metà con tre punti dati e nessuna risposta. Ma la tua ricerca più specifica ottiene alcuni risultati. Forse perché hai più esperienza qui e sai quali termini si distinguono come rilevanti.
Amanda,

Una cosa che ho scoperto sugli errori del software è che la ricerca del messaggio di errore specifico (di solito tra virgolette) è il modo più sicuro per scoprire se è stato discusso in precedenza. (Questo vale a livello di Internet, non solo sui siti SE.) Come dice il nostro messaggio "in attesa", se la tua ricerca aggiuntiva non risolve il tuo problema, ti preghiamo di tornare indietro e di rispedirci un po ': questa domanda è a l'intersezione tra statistica e informatica e potrebbe esporre alcune questioni di grande interesse qui.
whuber

1
La misura dei valori iniziali è molto lontana dai dati; confrontare exp(50)e exp(95)con i valori y in x = 50 e x = 95. Se imposti c=0e prendi il log di y (creando una relazione lineare), puoi utilizzare la regressione per ottenere stime iniziali per il log ( ) eb che saranno sufficienti per i tuoi dati (o se inserisci una linea attraverso l'origine, puoi lasciare a a 1 e usa solo la stima per b ; questo è sufficiente anche per i tuoi dati). Se b è molto al di fuori di un intervallo abbastanza stretto attorno a questi due valori, si verificheranno alcuni problemi. [In alternativa, prova un algoritmo diverso]un'Bun'BB
Glen_b -Reinstate Monica

1
Grazie @Glen_b. Speravo di poter usare R al posto di una calcolatrice grafica per lavorare attraverso un libro di testo di introduzione alle statistiche (e scavalcare il corso stesso), quindi sto iniziando con solo la più chiara intuizione statistica, ma molta esperienza facendo altri tagli e cubetti in R .
Amanda

Risposte:


38

Trovare automaticamente buoni valori iniziali per un modello non lineare è un'arte. (È relativamente facile per i set di dati una tantum quando è possibile tracciare semplicemente i dati e fare alcune ipotesi visivamente.) Un approccio è quello di linearizzare il modello e utilizzare le stime dei minimi quadrati.

In questo caso, il modello ha la forma

E(Y)=un'exp(BX)+c

per parametri sconosciuti . La presenza dell'esponenziale ci incoraggia a usare i logaritmi - ma l'aggiunta di c rende difficile farlo. Si noti, tuttavia, che se un è positivo allora c sarà inferiore al minimo valore atteso di Y --e quindi potrebbe essere un po 'inferiore al minimo osservata valore di Y . (Se a potrebbe essere negativo, dovrai anche considerare un valore di c che è un po 'più grande del più grande valore osservato di Y. )un',B,ccun'cYYun'cY

Prendiamoci quindi cura di usando come stima iniziale c 0 qualcosa come metà del minimo delle osservazioni y i . Il modello può ora essere riscritto senza quel termine additivo spinoso comecc0yio

E(Y)-c0un'exp(BX).

Che possiamo prendere il registro di:

log(E(Y)-c0)log(un')+BX.

log(un')B

Ecco il codice rivisto:

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)

Il suo output (per i dati di esempio) è

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 convergenza sembra buona. Tracciamolo:

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

figura

Ha funzionato bene!

yun'<0


Un altro metodo per stimare i valori iniziali si basa sulla comprensione del loro significato, che può essere basato sull'esperienza, sulla teoria fisica, ecc. Un esempio esteso di adattamento non lineare (moderatamente difficile) i cui valori iniziali possono essere determinati in questo modo è descritto nella mia risposta all'indirizzo /stats//a/15769 .

L'analisi visiva di un diagramma a dispersione (per determinare le stime dei parametri iniziali) è descritta e illustrata su /stats//a/32832 .

In alcune circostanze, viene eseguita una sequenza di accoppiamenti non lineari in cui è possibile aspettarsi che le soluzioni cambino lentamente. In tal caso è spesso conveniente (e veloce) utilizzare le soluzioni precedenti come stime iniziali per quelle successive . Ricordo di aver usato questa tecnica (senza commento) su /stats//a/63169 .



-1

Quindi ... penso di aver letto male questa come una funzione esponenziale. Tutto ciò di cui avevo bisogno 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)))

Oppure, 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")

2
Questo non risponde alla domanda che hai posto - lo cambia in qualcosa di diverso (e piuttosto meno interessante, IMHO).
whuber

6
Sebbene possa risolvere il problema di adattare una funzione per rappresentare i dati, le risposte accettate non sono le aspettative per la tua domanda. Mr. @whuber ti ha fornito un'ottima spiegazione e merita la risposta accettata.
Lourenco,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.