Search code examples
rmodel

Why would AICc be less than AIC?


My general understanding of AICc is AIC is modified for small samples so that we are less "certain" about a model with few samples, and that as the sample size gets very large, the modification approaches 0 and we become more "certain" (excuse me if I use incorrect terminology). However, I've encountered an issue when using the AICc function in the 'AICcmodavg' package to calculate AICc for a null model (y = mx + c; m = 0) I'm comparing to others. Here you can see that AICc is supposedly smaller than the AIC:

library(minpack.lm)
library(AICcmodavg)

y = c(80,251,304,482,401,141,242,221,304,243,544,669,638)

mNull <- nlsLM(y ~ c, start=c(c=mean(y)))

And when I run the AIC functions:

> AIC(mNull)
[1] 175.6431
> AICc(mNull)
[1] 169.6431

The help file says the AICc should be calculated as: −2∗log−likelihood+2∗K∗(n/(n−K−1)), but when I try to calculate it by hand:

> k=AICc(mNull, return.K = T)
> n=length(y)
> -2*as.numeric(logLik(mNull))+2*k*(n/(n-k-1))
[1] 176.8431

Meanwhile, calculating AIC by hand seems to work correctly:

> AIC(mNull)==-2*as.numeric(logLik(mNull))+2*k
[1] TRUE

So conceptually, why would AICc be less than AIC? Both n and k in this instance wouldn't lead to a negative modifier. Am I missing something?


Solution

  • The problem is the way that AICc.nls() calculates the number of observations. It uses the length of the fitted values if nobs is not supplied. In your case, this is 1 (not the length of y). So, if you supply nobs to AICc(), you'll get the right answer.

    library(minpack.lm)
    library(AICcmodavg)
    y = c(80,251,304,482,401,141,242,221,304,243,544,669,638)
    
    mNull <- nlsLM(y ~ c, start=c(c=mean(y)))
    #> Warning in .swts * attr(rhs, "gradient"): Recycling array of length 1 in vector-array arithmetic is deprecated.
    #>   Use c() or as.vector() instead.
    
    fitted(mNull)
    #> [1] 347.6923
    #> attr(,"label")
    #> [1] "Fitted values"
    
    AICc(mNull, nobs=length(y))
    #> [1] 176.8431
    
    k=AICc(mNull, return.K = T)
    n=length(y)
    -2*as.numeric(logLik(mNull))+2*k*(n/(n-k-1))
    #> [1] 176.8431
    

    Created on 2023-01-24 by the reprex package (v2.0.1)

    The relevant piece of code from AICcmodavg:::AICc.nls() (where nobs=NULL is the default) is:

        if (identical(nobs, NULL)) {
            n <- length(fitted(mod))
        }
        else {
            n <- nobs
        }