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