Perché esiste un valore R ^ 2 (e cosa lo sta determinando) quando lm non ha variazioni nel valore previsto?


10

Considera il seguente codice R:

example <- function(n) {
    X <- 1:n
    Y <- rep(1,n)
    return(lm(Y~X))
}
#(2.13.0, i386-pc-mingw32)
summary(example(7))    #R^2 = .1963
summary(example(62))   #R^2 = .4529
summary(example(4540)) #R^2 = .7832
summary(example(104))) #R^2 = 0
#I did a search for n 6:10000, the result for R^2 is NaN for
#n = 2, 4, 16, 64, 256, 1024, 2085 (not a typo), 4096, 6175 (not a typo), and 8340 (not a typo)

Guardare http://svn.r-project.org/R/trunk/src/appl/dqrls.f ) non mi ha aiutato a capire cosa sta succedendo, perché non conosco Fortran. In un'altra domanda è stato risposto che gli errori di tolleranza della macchina in virgola mobile sono la causa dei coefficienti per X che sono vicini, ma non del tutto 0.

R2 è maggiore quando il valore per coef(example(n))["X"]è più vicino a 0. Ma ...

  1. Perché esiste un valore ? R2
  2. Cosa (specificamente) lo sta determinando?
  3. Perché la progressione apparentemente ordinata dei NaNrisultati?
  4. Perché le violazioni di tale progressione?
  5. Che cosa è questo comportamento "previsto"?

Nota: R ^ 2 di 7 dovrebbe essere 0.4542 per vedere qualcosa di più costruttivo vedere la mia risposta. :-)

1
Bene, per essere onesti, l'utente dovrebbe effettivamente sapere qualcosa sui metodi statistici prima di utilizzare gli strumenti (a differenza, diciamo, degli utenti di Excel (ok, scusate per lo sparo economico)). Poiché è piuttosto ovvio che R ^ 2 si avvicina a 1 quando l'errore si avvicina a zero, sappiamo meglio che confondere un valore NaN con il limite di una funzione. Ora, se ci fosse un problema con R ^ 2 divergente come ynoise -> 0 (diciamo, sostituisci l'istruzione Y sopra con Y <- rep(1,n)+runif(n)*ynoise), sarebbe interessante :-)
Carl Witthoft,

@eznme: penso che i risultati siano specifici della macchina, o almeno a 32 o 64 bit; Ho una macchina a 32 bit che fornisce 0,1963 per 7, ma la mia macchina a 64 bit fornisce NaN. È interessante notare che sulla macchina a 64 bit, gli R ^ 2 che non sono NaN sono tutti molto vicini a 0,5. Ha senso quando ci penso, ma all'inizio mi ha sorpreso.
Aaron ha lasciato Stack Overflow il

1
Stai studiando un errore di arrotondamento a doppia precisione. Dai un'occhiata ai coefficienti; ad es apply(as.matrix(2:17), 1, function(n){example(n)$coefficients[-1]}). (I miei risultati, su Win 7 x64 Xeon, vanno da -8e-17 a + 3e-16; circa la metà sono veri zeri.) A proposito, la fonte Fortran non è di alcun aiuto: è solo un wrapper per dqrdc; questo è il codice che vuoi guardare.
whuber

1
(Continua) Ma, come utente, la scelta del CV è un sito migliore, per la semplice ragione che l'analisi statistica diligente è responsabilità dell'utente, non dello sviluppatore. Se l'utente vede un errato rispetto all'entità dell'RSS, allora dovrebbe fare la propria post-elaborazione prima di riferire ulteriormente. Per quanto riguarda la programmazione, vorrei sapere come evitare il più possibile questi problemi numerici, ma penso che non possano essere sfuggiti, ed è qui che è importante avere un utente diligente ed educare gli altri. R2
Iteratore

Risposte:


6

Come dice Ben Bolker, la risposta a questa domanda può essere trovata nel codice per summary.lm().

Ecco l'intestazione:

function (object, correlation = FALSE, symbolic.cor = FALSE, 
    ...) 
{

Quindi, diamo x <- 1:1000; y <- rep(1,1000); z <- lm(y ~ x)un'occhiata a questo estratto leggermente modificato:

    p <- z$rank
    rdf <- z$df.residual
    Qr <- stats:::qr.lm(z)
    n <- NROW(Qr$qr)
    r <- z$residuals
    f <- z$fitted.values
    w <- z$weights
    if (is.null(w)) {
        mss <- sum((f - mean(f))^2)
        rss <- sum(r^2)
    }
    ans <- z[c("call", "terms")]
    if (p != attr(z$terms, "intercept")) {
        df.int <- 1L
        ans$r.squared <- mss/(mss + rss)
        ans$adj.r.squared <- 1 - (1 - ans$r.squared) * ((n - 
            df.int)/rdf)
    }

Si noti che ans $ r.squared è ...0.4998923

Per rispondere a una domanda con una domanda: cosa traggiamo da questo? :)

Credo che la risposta stia nel modo in cui R gestisce i numeri in virgola mobile. Penso che msssia rssla somma di errori di arrotondamento molto piccoli (al quadrato), quindi la ragione è circa 0,5. Per quanto riguarda la progressione, sospetto che ciò abbia a che fare con il numero di valori necessari affinché le approssimazioni +/- si annullino su 0 (per entrambi e , come è probabile la fonte di questi valori). Non so perché i valori differiscano da una progressione, però.R2mssrss0/0NaN2^(1:k)


Aggiornamento 1: Ecco un bel thread di R-help che affronta alcuni dei motivi per cui gli avvisi di underflow non vengono risolti in R.

Inoltre, le domande e risposte SO contengono numerosi post interessanti e collegamenti utili relativi a underflow, aritmetica ad alta precisione, ecc.


8

Sono curioso della tua motivazione per porre la domanda. Non riesco a pensare a una ragione pratica che dovrebbe comportare questo comportamento; la curiosità intellettuale è una ragione alternativa (e l'IMO molto più ragionevole). Penso che non sia necessario comprendere FORTRAN per rispondere a questa domanda, ma penso che sia necessario conoscere la decomposizione QR e il suo utilizzo nella regressione lineare. Se trattate dqrlscome una scatola nera che calcola una decomposizione QR e restituisce varie informazioni su di essa, allora potreste essere in grado di tracciare i passaggi ... o semplicemente andare direttamente summary.lme rintracciare per vedere come viene calcolato R ^ 2. In particolare:

mss <- if (attr(z$terms, "intercept")) 
          sum((f - mean(f))^2)
       else sum(f^2)
rss <- sum(r^2)
## ... stuff ...
ans$r.squared <- mss/(mss + rss)

Quindi devi tornare indietro lm.fite vedere che i valori adattati vengono calcolati come r1 <- y - z$residuals(cioè come la risposta meno i residui). Ora puoi capire cosa determina il valore dei residui e se il valore meno la sua media è esattamente zero o no, e da lì capire i risultati computazionali ...


La curiosità intellettuale è la maggior parte del motivo della mia domanda. Un collega ha riferito il comportamento e volevo dare un'occhiata in giro e vedere se riuscivo a capirlo. Dopo aver tracciato il problema oltre il mio set di abilità, ho deciso di porre la domanda. Come problema pratico, a volte le analisi vengono eseguite in batch o si verificano altri errori e questo comportamento mi sembra decisamente "strano".
Russellpierce,

1
mms e rss sono entrambi risultati di z, che è il nome dell'oggetto lm all'interno di summary.lm. Quindi, una risposta probabilmente richiede una spiegazione della decomposizione QR, il suo uso nella regressione lineare, e in particolare alcuni dettagli Decomposizione QR come istanziata nel codice sottostante R per spiegare perché la decomposizione QR finisce con approssimazioni di 0 anziché 0 .
Russellpierce,

@drknexus Non sono d'accordo. QR decomp è uno dei molti algoritmi numerici; se il problema di fondo è la precisione numerica, questo comparirà in QR, moltiplicazione di matrici, solutori non lineari e così tanti altri posti. La sequenza essenziale è semplice: i coefficienti sono leggermente off (dovrebbe essere (0,1)); questo non è irragionevole, ma produce il msse rss"rumore". È il principio GIGO che assicura che è preciso, ma non corretto. Preferirei inserire un "rilevatore di immondizia" prima di calcolare piuttosto che modificare l'algo QR, perché dubito che la sua validità potrebbe essere migliorata. R2R2
Iteratore,

Mi sembra che il rilevatore di immondizia dovrebbe essere al QR o proprio prima di esso. Un semplice controllo di integrità sulla varianza di Y e avvertire che Y manca di varianza andrebbe bene (potrei scrivere un lm wrapper per i miei amici che fa proprio questo). Mi sembra che quando stai calcolando , uno è già troppo lontano nella tana del coniglio computazionale per sapere se si sta guardando la spazzatura o no. R2
Russellpierce,

0

R2 è definito come ( http://en.wikipedia.org/wiki/R_squared ), quindi se la somma dei quadrati è 0, allora non è definita. Secondo me R dovrebbe mostrare un messaggio di errore.R2=1-SSerrSStot


1
Puoi dare una situazione pratica in cui questo comportamento avrebbe importanza?
Ben Bolker,

3
@Brandon - Iterator ha messo la faccina lì dentro e sei ancora sbronzo!
Carl Witthoft,

2
@eznme Anche se un errore è buono, è abbastanza difficile individuare tutti i tipi di luoghi in cui sorgono problemi in virgola mobile, in particolare nel mondo dell'aritmetica IEEE-754. La lezione qui è che anche i calcoli di pane e burro con R dovrebbero essere gestiti delicatamente.
Iteratore,

2
Queste considerazioni sono particolarmente importanti perché nei suoi scritti John Chambers (uno dei creatori di S e quindi un "nonno" di R) sottolinea fortemente l'uso di R per un calcolo affidabile. Ad esempio, vedi Chambers, Software per l'analisi dei dati: Programmazione con R (Springer Verlag 2008): "i calcoli e il software per l'analisi dei dati dovrebbero essere affidabili: dovrebbero fare ciò che sostengono e farsi vedere." [A pag. 3.]
whuber

2
Il problema è che, nel bene o nel male, R-core è resistente (come lo vedono) a festoni il codice con molti, molti controlli che intercettano tutti i casi angolari e possibili strani errori dell'utente - hanno paura (penso) che (a) impiegherà enormi quantità di tempo, (b) renderà la base di codice molto più grande e più difficile da leggere (perché ci sono letteralmente migliaia di questi casi speciali), e (c) rallenterà l'esecuzione forzando tali controlli continuamente anche in situazioni in cui i calcoli vengono ripetuti molte, molte volte.
Ben Bolker,
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.