AIC在biglm和lm之间有所不同

时间:2014-02-12 21:56:49

标签: r lm model-comparison

我一直在尝试使用biglm在大型数据集上运行线性回归(大约60,000,000行)。我想使用AIC进行模型选择。但是我发现在较小的数据集上使用biglm时,biglm返回的AIC变量与lm返回的变量不同。这甚至适用于biglm帮助中的示例。

data(trees)
ff<-log(Volume)~log(Girth)+log(Height)

chunk1<-trees[1:10,]
chunk2<-trees[11:20,]
chunk3<-trees[21:31,]

library(biglm)
a <- biglm(ff,chunk1)
a <- update(a,chunk2)
a <- update(a,chunk3)

AIC(a)#48.18546

a_lm <- lm(ff, trees)
AIC(a_lm)#-62.71125

有人可以解释一下这里发生了什么吗?使用biglm生成的AIC是否可以安全地用于比较同一数据集上的biglm模型?

2 个答案:

答案 0 :(得分:5)

tl; dr 它让我觉得在biglm的AIC方法中有一个非常明显的错误 - 类对象(更具体地说,在更新方法中),在当前(0.9-1)版本,但biglm包的作者是一个聪明,经验丰富的人,biglm被广泛使用,所以也许我错过了一些东西。谷歌搜索"biglm AIC df.resid",似乎已经discussed way back in 2009? 更新:软件包作者/维护者通过电子邮件报告这确实是一个错误。

有趣的东西似乎在这里发生。模型之间AIC中的差异在建模框架中应该是相同的,无论使用哪些常数,然而计算参数(因为这些常量和参数计数应该是 in 建模框架......)

原始示例:

data(trees)
ff <- log(Volume)~log(Girth)+log(Height)
chunk1<-trees[1:10,]
chunk2<-trees[11:20,]
chunk3<-trees[21:31,]
library(biglm)
a <- biglm(ff,chunk1)
a <- update(a,chunk2)
a <- update(a,chunk3)
a_lm <- lm(ff, trees)

现在适合简化模型:

ff2 <- log(Volume)~log(Girth)    
a2 <- biglm(ff2, chunk1)
a2 <- update(a2, chunk2)
a2 <- update(a2 ,chunk3)
a2_lm <- lm(ff2,trees)

现在比较AIC值:

AIC(a)-AIC(a2)
## [1] 1.80222

AIC(a_lm)-AIC(a2_lm)
## [1] -20.50022

检查我们是不是搞砸了什么:

all.equal(coef(a),coef(a_lm))  ## TRUE
all.equal(coef(a2),coef(a2_lm))  ## TRUE

看看引擎盖:

biglm:::AIC.biglm
## function (object, ..., k = 2) 
##    deviance(object) + k * (object$n - object$df.resid)

原则上这是正确的公式(观察数量减去残差df应该是拟合的参数数量),但是挖掘,看起来对象的$df.resid组件没有正确更新:

a$n  ## 31, correct
a$df.resid  ## 7, only valid before updating!

查看biglm:::update.biglm,我会添加

object$df.resid <- object$df.resid + NROW(mm)

在读取

的行之前或之后
object$n <- object$n + NROW(mm)

...

这对我来说似乎是一个相当明显的错误,所以也许我错过了一些明显的东西,或者它已经被修复了。

一个简单的解决方法是将您自己的AIC功能定义为

AIC.biglm <- function (object, ..., k = 2) {
    deviance(object) + k * length(coef(object))
}

AIC(a)-AIC(a2)  ## matches results from lm()

(虽然请注意AIC(a_lm)仍然不等于AIC(a),因为stats:::AIC.default()使用2 *对数似然而不是偏差(这两个度量的加法系数不同)。 。)

答案 1 :(得分:1)

我已经玩了一下这个。我不确定,但我认为包AIC使用biglm的公式为:

2 * (n.parameters  + obs.added - 1) + deviance(a)

其中obs_addedchunk2中的观察次数加上chunk3中的观察次数:

obs.added <- dim(chunk2)[1] + dim(chunk3)[1]

n.parameterssummary(a) + 1返回的估算系数的数量(+1用于错误字词的位置),而deviance(a)是您模型的偏差{ {1}}。

a

由于我不是100%肯定我的回答是正确的,你可以使用下面的代码,看看你是否能找到AIC的拟议公式不起作用的场景。如果我发现任何此类情况,我将尝试根据需要修改下面的代码和上面的公式。

####################################################

data(trees)

ff  <- log(Volume)~log(Girth)+log(Height)

n.parm  <- 4

chunk1<-trees[1:10,]
chunk2<-trees[11:20,]
chunk3<-trees[21:31,]

obs.added <- dim(chunk2)[1] + dim(chunk3)[1]

library(biglm)

a <- biglm(ff,chunk1)
a <- update(a,chunk2)
a <- update(a,chunk3)
AIC(a)
summary(a)
deviance(a)

2 * (n.parm  + obs.added - 1) + deviance(a)

round(AIC(a), 5) == round(2 * (n.parm  + obs.added - 1) + deviance(a), 5)

# [1] TRUE

####################################################

修改

我建议######################################################### # Generate some data n <- 118 # number of observations B0 <- 2 # intercept B1 <- -1.5 # slope 1 B2 <- 0.4 # slope 2 B3 <- 2.0 # slope 3 B4 <- -0.8 # slope 4 sigma2 <- 5 # residual variance x1 <- round(runif(n, -5 , 5), digits = 3) # covariate 1 x2 <- round(runif(n, 10 , 20), digits = 3) # covariate 2 x3 <- round(runif(n, 2 , 8), digits = 3) # covariate 3 x4 <- round(runif(n, 12 , 15), digits = 3) # covariate 4 eps <- rnorm(n, mean = 0, sd = sqrt(sigma2)) # error y <- B0 + B1 * x1 + B2 * x2 + B3 * x3 + B4 * x4 + eps # dependent variable my.data <- data.frame(y, x1, x2, x3, x4) # analyze data with linear regression model.1 <- lm(my.data$y ~ my.data$x1 + my.data$x2 + my.data$x3 + my.data$x4) summary(model.1) AIC(model.1) n.parms <- length(model.1$coefficients) + 1 my.AIC <- 2 * n.parms - 2 * as.numeric(logLik(model.1)) my.AIC ######################################################### ff0 <- y ~ 1 ff1 <- y ~ x1 ff2 <- y ~ x1 + x2 ff3 <- y ~ x1 + x2 + x3 ff4 <- y ~ x1 + x2 + x3 + x4 n.parm0 <- 2 n.parm1 <- 3 n.parm2 <- 4 n.parm3 <- 5 n.parm4 <- 6 n.chunks <- 5 chunk1<-my.data[ 1:round(((nrow(my.data)/n.chunks)*1)+0),] chunk2<-my.data[round(((nrow(my.data)/n.chunks)*1)+1):round(((nrow(my.data)/n.chunks)*2)+0),] chunk3<-my.data[round(((nrow(my.data)/n.chunks)*2)+1):round(((nrow(my.data)/n.chunks)*3)+0),] chunk4<-my.data[round(((nrow(my.data)/n.chunks)*3)+1):round(((nrow(my.data)/n.chunks)*4)+0),] chunk5<-my.data[round(((nrow(my.data)/n.chunks)*4)+1):nrow(my.data),] obs.added <- dim(chunk2)[1] + dim(chunk3)[1] + dim(chunk4)[1] + dim(chunk5)[1] # check division of data foo <- list() foo[[1]] <- chunk1 foo[[2]] <- chunk2 foo[[3]] <- chunk3 foo[[4]] <- chunk4 foo[[5]] <- chunk5 all.data.foo <- do.call(rbind, foo) all.equal(my.data, all.data.foo) #################################################### library(biglm) #################################################### a0 <- biglm(ff0, chunk1) a0 <- update(a0, chunk2) a0 <- update(a0, chunk3) a0 <- update(a0, chunk4) a0 <- update(a0, chunk5) AIC(a0) summary(a0) deviance(a0) print(a0) 2 * (n.parm0 + obs.added - 1) + deviance(a0) round(AIC(a0), 5) == round(2 * (n.parm0 + obs.added - 1) + deviance(a0), 5) #################################################### a1 <- biglm(ff1, chunk1) a1 <- update(a1, chunk2) a1 <- update(a1, chunk3) a1 <- update(a1, chunk4) a1 <- update(a1, chunk5) AIC(a1) summary(a1) deviance(a1) print(a1) 2 * (n.parm1 + obs.added - 1) + deviance(a1) round(AIC(a1), 5) == round(2 * (n.parm1 + obs.added - 1) + deviance(a1), 5) #################################################### a2 <- biglm(ff2, chunk1) a2 <- update(a2, chunk2) a2 <- update(a2, chunk3) a2 <- update(a2, chunk4) a2 <- update(a2, chunk5) AIC(a2) summary(a2) deviance(a2) print(a2) 2 * (n.parm2 + obs.added - 1) + deviance(a2) round(AIC(a2), 5) == round(2 * (n.parm2 + obs.added - 1) + deviance(a2), 5) #################################################### a3 <- biglm(ff3, chunk1) a3 <- update(a3, chunk2) a3 <- update(a3, chunk3) a3 <- update(a3, chunk4) a3 <- update(a3, chunk5) AIC(a3) summary(a3) deviance(a3) print(a3) 2 * (n.parm3 + obs.added - 1) + deviance(a3) round(AIC(a3), 5) == round(2 * (n.parm3 + obs.added - 1) + deviance(a3), 5) #################################################### a4 <- biglm(ff4, chunk1) a4 <- update(a4, chunk2) a4 <- update(a4, chunk3) a4 <- update(a4, chunk4) a4 <- update(a4, chunk5) AIC(a4) summary(a4) deviance(a4) print(a4) 2 * (n.parm4 + obs.added - 1) + deviance(a4) round(AIC(a4), 5) == round(2 * (n.parm4 + obs.added - 1) + deviance(a4), 5) #################################################### 使用biglm的以下等式:

AIC

Ben Bolker指出2 * (n.parameters + obs.added - 1) + deviance(a) 用于biglm的等式是:

AIC

Ben还确定deviance(object) + k * (object$n - object$df.resid) 没有更新残差df的第一个值。

鉴于这些新信息,我现在看到这两个方程是等价的 首先,将这两个方程限制在下面,这是它们唯一不同的地方:

biglm

重新安排我考虑我将参数数量加1,然后减去一个:

(n.parameters  + obs.added - 1) # mine

(object$n    - object$df.resid) # Ben's

现在将我的方程变为Ben的:

我的((n.parameters-1) + obs.added) = ((4-1) + obs.added) = (3 + 21) = 24 与:

相同
3

,并提供:

(number of observations in chunk1 - object$df.resid) = (10 - 7) = 3

或:

((number of obs in chunk1 - object$df.resid) + obs.added) = ((10-7) + 21)

重新安排:

(3 + 21) = 24

或:

((number of obs in chunk1 + obs.added) - object$df.resid) = ((10 + 21) - 7)

(31 - 7) = 24

与:

相同
((number of observations in chunk1 + obs.added) - object$df.resid)

与以下内容相同:

(total number of observations - object$df.resid)

我提出的等式似乎是(object$n - object$df.resid) = (31 - 7) = 24 用于biglm的等式,只是以不同的形式表达。

当然,我只能意识到这一点,因为Ben提供了关键代码和错误的关键解释。