Por que existe um valor R ^ 2 (e o que está determinando) quando lm não tem variação no valor previsto?

10

Considere o seguinte código 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)

Ver http://svn.r-project.org/R/trunk/src/appl/dqrls.f ) não me ajudou a entender o que está acontecendo, porque não conheço o Fortran. Em outra pergunta , foi respondido que os erros de tolerância da máquina de ponto flutuante são os responsáveis ​​pelos coeficientes de X que estão próximos, mas não exatamente de 0.

R2 é maior quando o valor de coef(example(n))["X"]for mais próximo de 0. Mas ...

  1. Por que existe um valor ? R2
  2. O que (especificamente) está determinando isso?
  3. Por que a progressão aparentemente ordenada dos NaNresultados?
  4. Por que as violações dessa progressão?
  5. O que é esse comportamento "esperado"?
russellpierce
fonte
Nota: R's de 7 deve ser 0,4542 para ver algo mais construtivo, veja minha resposta. :-)
11
Bem, para ser justo, o usuário deve realmente saber algo sobre métodos estatísticos antes de usar as ferramentas (ao contrário, digamos, dos usuários do Excel (ok, desculpe-me pelo preço baixo)). Como é óbvio que R ^ 2 se aproxima de 1 quando o erro se aproxima de zero, sabemos que não devemos confundir um valor de NaN com o limite de uma função. Agora, se houve um problema com R ^ 2 divergindo quanto ynoise -> 0 (digamos, substituir declaração Y acima com Y <- rep(1,n)+runif(n)*ynoise), que seria interessante :-)
Carl Witthoft
@eznme: Eu acho que os resultados são específicos da máquina, ou pelo menos 32 ou 64 bits; Eu tenho uma máquina de 32 bits que fornece 0,1963 para 7, mas minha máquina de 64 bits fornece NaN. Curiosamente, na máquina de 64 bits, os R ^ 2s que não são NaN estão todos muito próximos de 0,5. Faz sentido quando penso nisso, mas me surpreendeu a princípio.
Aaron deixou Stack Overflow em
11
Você está estudando um erro de arredondamento com precisão dupla. Dê uma olhada nos coeficientes; por exemplo apply(as.matrix(2:17), 1, function(n){example(n)$coefficients[-1]}),. (Meus resultados, em um Win 7 x64 Xeon, variam de -8e-17 a + 3e-16; cerca da metade são zeros verdadeiros.) Aliás, a fonte Fortran não ajuda em nada: é apenas um invólucro para o dqrdc; esse é o código que você deseja analisar.
whuber
11
R2

Respostas:

6

Como Ben Bolker diz, a resposta para esta pergunta pode ser encontrada no código para summary.lm().

Aqui está o cabeçalho:

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

Então, vamos x <- 1:1000; y <- rep(1,1000); z <- lm(y ~ x)dar uma olhada neste extrato ligeiramente modificado:

    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)
    }

0.4998923

Para responder a uma pergunta com uma pergunta: o que extraímos disso? :)

mssrssR2mssrss0/0NaN2^(1:k)


Atualização 1: Aqui está um bom tópico da R-help, abordando alguns dos motivos pelos quais avisos de fluxo insuficiente não são abordados em R.

Além disso, essas perguntas e respostas da SO têm várias postagens interessantes e links úteis sobre subfluxo, aritmética de alta precisão, etc.

Iterador
fonte
8

Estou curioso sobre sua motivação para fazer a pergunta. Não consigo pensar em uma razão prática para esse comportamento ter importância; a curiosidade intelectual é uma razão alternativa (e IMO muito mais sensível). Acho que você não precisa entender o FORTRAN para responder a essa pergunta, mas acho que precisa saber sobre a decomposição do QR e seu uso na regressão linear. Se você tratar dqrlscomo uma caixa preta que calcula uma decomposição QR e retorna várias informações sobre ela, poderá rastrear as etapas ... ou simplesmente ir direto summary.lme rastrear para ver como o R ^ 2 é calculado. Em particular:

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)

Então você deve voltar lm.fite verificar que os valores ajustados são calculados como r1 <- y - z$residuals(ou seja, como a resposta menos os resíduos). Agora você pode descobrir o que determina o valor dos resíduos e se o valor menos sua média é exatamente zero ou não, e daí descobrir os resultados computacionais ...

Ben Bolker
fonte
A curiosidade intelectual é a maior parte do motivo da minha pergunta. Um colega relatou o comportamento e eu queria bisbilhotar e ver se conseguia descobrir. Depois de rastrear a questão além do meu conjunto de habilidades, decidi fazer a pergunta. Como uma questão prática, algumas vezes as análises são feitas por lote ou outros erros ocorrem, e esse comportamento me parece decididamente "estranho".
22812 russellpierce
11
mms e rss são resultados de z, que é o nome do objeto lm dentro de summary.lm. Portanto, uma resposta provavelmente requer uma explicação da decomposição do QR, seu uso na regressão linear e, especificamente, alguns detalhes da decomposição do QR instanciados no código subjacente a R, a fim de explicar por que a decomposição do QR termina com aproximações de 0 em vez de 0 .
22812 russellpierce
mssrssR2R2
R2
0

R2R2=1SSerrSStot

Bernd Elkemann
fonte
11
Você pode dar uma situação prática em que esse comportamento seria importante?
Ben Bolker
3
@Brandon - O Iterator colocou o smiley lá dentro e você ainda gritou!
Carl Witthoft
2
@eznme Embora um erro seja bom, é bastante difícil encontrar todos os tipos de locais onde surgem problemas de ponto flutuante, principalmente no mundo da aritmética IEEE-754. A lição aqui é que mesmo os cálculos de pão com manteiga com R devem ser tratados com delicadeza.
Iterator
2
Essas considerações são especialmente importantes porque, em seus escritos, John Chambers (um dos criadores de S e, portanto, um "avô" de R) enfatiza fortemente o uso de R para computação confiável. Por exemplo, veja Chambers, Software para Análise de Dados: Programação com R (Springer Verlag 2008): "os cálculos e o software para análise de dados devem ser confiáveis: eles devem fazer o que afirmam e devem fazê-lo". [Na p. 3.]
whuber
2
O problema é que, para o bem ou para o mal, o R-core é resistente a (como eles o vêem) enfeitar o código com muitas, muitas verificações que interceptam todos os casos de canto e possíveis erros estranhos do usuário - eles têm medo (eu acho) de que (a) levará muito tempo, (b) tornará a base de código muito maior e mais difícil de ler (porque existem literalmente milhares desses casos especiais); e (c) diminuirá a execução forçando essas verificações o tempo todo mesmo em situações em que os cálculos estão sendo repetidos muitas e muitas vezes.
Ben Bolker