为什么statmodels和R在AIC计算上不一致

wkftcu5l  于 2023-04-09  发布在  其他
关注(0)|答案(1)|浏览(195)

我在Google上搜索了这个问题,找不到解决办法。
似乎R在AIC/BIC计算方面有问题。它产生了不正确的结果。下面是一个简单的例子:

link = 'https://gist.githubusercontent.com/seankross/a412dfbd88b3db70b74b/raw/5f23f993cd87c283ce766e7ac6b329ee7cc2e1d1/mtcars.csv'
df = read.csv(link, row.names = 'model')
form = 'mpg ~ disp + hp + wt + qsec + gear'
my_model = lm(form, data = df)
summary(my_model)
cat('AIC:',AIC(my_model),'\tBIC:',AIC(my_model, k = log(nrow(df))))

AIC: 157.4512   BIC: 167.7113

在Python中做同样的事情,我得到:

import pandas as pd
from statsmodels.formula.api import ols as lm

link = 'https://gist.githubusercontent.com/seankross/a412dfbd88b3db70b74b/raw/5f23f993cd87c283ce766e7ac6b329ee7cc2e1d1/mtcars.csv'
df = pd.read_csv(link, index_col='model')
form = 'mpg ~ disp + hp + wt + qsec + gear'
my_model = lm(form, df).fit()
my_model.summary()
print(f'AIC: {my_model.aic:.4f}\tBIC: {my_model.bic:.4f}')

AIC: 155.4512   BIC: 164.2456

你可以检查一下R中的summary(my_model)和python中的my_model.summary(),你会注意到这两个模型除了AIC和BIC之外,在所有方面都完全相同。
我决定在R中手动计算:

p = length(coef(my_model)) # number of predictors INCLUDING the Intercept ie 6
s = sqrt(sum(resid(my_model)^2)/nrow(df)) #sqrt(sigma(my_model)^2 * (nrow(df) - p)/nrow(df))
logl = -2* sum(dnorm(df$mpg, fitted(my_model),s, log = TRUE))

c(aic = logl + 2*p, bic = logl + log(nrow(df))*p)
 aic      bic 
155.4512 164.2456

它与python生成的结果相匹配。
深入挖掘,我注意到AIC确实使用了logLik函数。这就是问题所在:logLik(my_model)给出的结果与上面的logl在乘以-2之前所示的结果完全相同,但df被给出为7而不是6。
如果我蛮力排名,以使其6,我得到正确的结果,即:

my_model$rank = my_model$rank - 1
cat('AIC:',AIC(my_model),'\tBIC:',AIC(my_model, k = log(nrow(df))))

AIC: 155.4512   BIC: 164.2456

为什么R要在预测器的数量上加1?你可以通过在Rstudio上输入stats:::logLik.lm并按回车键来访问base R中使用的logLik函数。下面的两行似乎有问题:

function (object, REML = FALSE, ...) 
{
    ...
    p <- object$rank
    ...
    attr(val, "df") <- p + 1 # This line here. Why does R ADD 1?
    ...
}
wswtfjt7

wswtfjt71#

这显然是一个深思熟虑的选择:R对估计参数集中的尺度参数进行计数。从?logLik.lm
对于“lm”拟合,假设已经估计了尺度(通过最大似然或REML)
(see也是here,由@MrFlick在评论中指出)。这种模糊性(以及,归一化常数是否包括在对数似然中:在R中,它们是)在跨平台比较结果之前总是必须检查,有时甚至在同一平台内的过程或函数之间。
正如评论中所讨论的,在跨平台比较时,AIC中的一个单位差异令人困惑,但对平台内的任何结论都没有影响,因为所有结论(所选模型、模型权重)基于AIC值的 * 差异 *,而非绝对值实际上,通过减去一组模型中的最小AIC将AIC转换为ΔAIC来开始通常是有用的。
值得一提的是,似乎也有很多关于statsmodels方面的讨论,例如this (closed) issue关于为什么AIC/BIC在R和statmodels之间不一致。
This commit in March 2002显示Martin Maechler将“df”(自由度/模型参数数)属性更改回object$rank+1,并添加了以下注解:
帮助页面?logLik.lm获得:
请注意,误差方差\eqn{\sigma^2}在\code{lm()}中估计,因此也被计算在内。
(this消息显然是在稍后的某个时间点编辑到上面看到的版本)。
NEWS文件获得(在“BUG FIXES”下):

o    logLik.lm() now uses  "df = p + 1" again (`+ sigma'!).

我很难再往前做考古了(也就是说,根据这里的消息,p+1推算 * 最初 * 使用,然后有人将其改为p,MM在2002年将其更改),因为函数四处移动(这个文件是在2001年创建的,所以更早的版本会更难找到)。我在2002年2月或3月的r-devel mailing list archive中没有找到任何关于这个的讨论...

相关问题